9

I'm trying something very basic with Python inheritance:

class Parent:
    def __init__(self):
        self.text = 'parent'

    def getText(self):
        print self.text

class Child1(Parent):
    def __init__(self):
        self.x = 'x'

class Child2(Parent):
    def __init__(self):
        self.x = 'x'

if __name__ == "__main__": 
    parent = Parent()
    child1 = Child1()
    child2 = Child2()

    parent.getText()
    child1.getText()
    child2.getText()

but I keep getting

Child1 instance has no attribute 'text'

how are variables passed to children?

Holt
  • 36,600
  • 7
  • 92
  • 139
Abdul Ahmad
  • 9,673
  • 16
  • 64
  • 127
  • You need to call the constructor of the parent classes manually - Here, `self.text` is initialize in `Parent` constructor which is never called. – Holt Mar 03 '16 at 15:50
  • @Holt what would that be? `super().__init__()` ? – Abdul Ahmad Mar 03 '16 at 15:51
  • @deceze no they're not. I put `self.x = 'x'` to stop the compiler from complaining about indenting block expected – Abdul Ahmad Mar 03 '16 at 15:52
  • 2
    @Abdul I misread. For that purpose you should just use `pass`, that's what it's for (a dummy body). – deceze Mar 03 '16 at 15:53
  • 1
    If you don't want python complaining about empty block, use `pass`, e.g. `if a: pass` (only for demonstration purpose). – Holt Mar 03 '16 at 15:54
  • 2
    In addition to `pass`, if the block is also a function, then adding a docstring also works to prevent python from complaining about the indentation being wrong. – mgilson Mar 03 '16 at 16:03

4 Answers4

11

You need to call the constructor of the parent classes manually - Here, self.text is initialize in Parent constructor which is never called:

class Child1(Parent):
    def __init__ (self):
        super(Child1, self).__init__ ()
        # or Parent.__init__ (self)
        self.x = 'x'
Holt
  • 36,600
  • 7
  • 92
  • 139
  • any reason why I would use `super` vs `Parent` init? – Abdul Ahmad Mar 03 '16 at 15:54
  • 1
    @AbdulAhmad There are multiple posts on SO about this: http://stackoverflow.com/questions/222877/how-to-use-super-in-python, http://stackoverflow.com/questions/576169/understanding-python-super-with-init-methods. I personally use `super` most of the time. – Holt Mar 03 '16 at 15:55
  • one more question, what's the correct way of altering the `self.text` from parent in a child? just `self.text = 'new text'`? or is there another way more suited for inheritance? (I will accept the answer once the timer is down, have 2 minutes left) – Abdul Ahmad Mar 03 '16 at 16:02
  • 2
    @AbdulAhmad You're just setting an attribute on the `self` object, it's no different than altering it in another method of the object. Just assign a new value to it. – deceze Mar 03 '16 at 16:05
1

your init function needs to call the parent init

class Child1(Parent):
def __init__(self):
    self.x = 'x'
    Parent.__init__(self)
lafferc
  • 2,741
  • 3
  • 24
  • 37
1

In python when you override a function which was supposed to be inherited you override all of it, __init__ is no exception. You should call the functions super method to use the base initializer, or implement the attribute in the constructor you have rewrote.

class Parent:
    def __init__(self):
        self.text = 'parent'

    def getText(self):
        print self.text

class Child1(Parent):
    def __init__(self):
        super(Child1, self).__init__()
        self.x = 'x'

child1.getText()

Should work now.

GLaDOS
  • 620
  • 6
  • 17
1

Since python 3.6, we can now use the __init_subclass__ function, which is called automatically before __init__ of the Child.

class Parent:
    def __init__(self):
        self.text = 'parent'
    
    def __init_subclass__(self):
        Parent.__init__(self)

    def getText(self):
        print(self.text)

class Child1(Parent): pass
class Child2(Parent): pass

classes = [Parent(), Child1(), Child2()]

for item in classes:
    item.getText()

output

parent
parent
parent

If you use your Parent class more as a "interface", here is another example.

class Animal():
    def __init_subclass__(self, sound):
        self.sound = sound

    def make_sound(self):
        print(self.sound)

class Cat(Animal, sound='meow'): pass
class Dog(Animal, sound='woof'): pass

animals = [Cat(), Dog()]

for animal in animals:
    animal.make_sound()

output

meow
woof
kruserr
  • 463
  • 4
  • 8