25

I would like to give a daughter class some extra attributes without having to explicitly call a new method. So is there a way of giving the inherited class an __init__ type method which does not override the __init__ method of the parent class?

I have written the code below purely to illustrate my question (hence the poor naming of attributes etc).

class initialclass():
    def __init__(self):
        self.attr1 = 'one'
        self.attr2 = 'two'    

class inheritedclass(initialclass):
    def __new__(self):
        self.attr3 = 'three'

    def somemethod(self):
        print 'the method'


a = inheritedclass()

for each in a.__dict__:
    print each

#I would like the output to be:
attr1
attr2
attr3

Thank you

dreftymac
  • 31,404
  • 26
  • 119
  • 182
Anake
  • 7,201
  • 12
  • 45
  • 59
  • Call `initialclass.__init__` in the derived class constructor. However, the order of `attrX` is not guaranteed. – khachik Apr 12 '11 at 14:02
  • 1
    *Do not* override `__new__` unless you know exactly what it does and why you need to fiddle with it. You propably don't know. It's not another name for `__init__`. It's three levels more magic than one us usually concerned with, especially beginners. –  Apr 12 '11 at 14:05
  • Note that the argument to `__new__` is the _class_ of `self`, not `self`, as it's an implicit class method. So in your example you're actually setting the class attribute `inheritedclass.attr3`, not `self.attr3` as you thought. – Lauritz V. Thaulow Apr 12 '11 at 14:06

6 Answers6

39

As far as I know that's not possible, however you can call the init method of the superclass, like this:

class inheritedclass(initialclass):
    def __init__(self):
        initialclass.__init__(self)
        self.attr3 = 'three'
Yexo
  • 1,865
  • 15
  • 21
17

Just call the parent's __init__ using super:

class inheritedclass(initialclass):
    def __new__(self):
        self.attr3 = 'three'
        super(initialclass, self).__init__()

I strongly advise to follow Python's naming conventions and start a class with a Capital letter, e.g. InheritedClass and InitialClass. This helps quickly distinguish classes from methods and variables.

Adam Matan
  • 128,757
  • 147
  • 397
  • 562
  • 2
    Specifically, use `super(DerivingClass, self).__init__()`. Or just `super().__init__()` in Python 3. Edit: -1 because 1. `super` needs the inheriting(!) class and 2. you override `__new__` needlessly, and the code as of now is in fact incorrect (it creates a **class** attribute `attr3`). –  Apr 12 '11 at 14:04
  • this works with the __new__ method but as lazyr told me (correctly) that I shouldn't use __new__, I think the correct answer for me yexo's. Thanks though! – Anake Apr 12 '11 at 14:18
  • @Anake Credit where credit is due, it was @delnan who told you not to use `__new__`, I just explained what your code actually did. By the way, `__new__` **must** return an instance of its class if you implement it. In the above answer, and in your code too, `inheritedclass() is None`! In other words, it doesn't work at all. (I mistakenly gave this answer an upvote, didn't read the code properly, and now I can't change it :(.) – Lauritz V. Thaulow Apr 12 '11 at 15:08
6

First of all you're mixing __init__ and __new__, they are different things. __new__ doesn't take instance (self) as argument, it takes class (cls). As for the main part of your question, what you have to do is use super to invoke superclass' __init__.

Your code should look like this:

class initialclass(object):
    def __init__(self):
        self.attr1 = 'one'
        self.attr2 = 'two'    

class inheritedclass(initialclass):
    def __init__(self):
        self.attr3 = 'three'
        super(inheritedclass, self).__init__()
Community
  • 1
  • 1
vartec
  • 131,205
  • 36
  • 218
  • 244
  • thanks,my mistake about the new method. I am trying to use super and I keep getting this error: TypeError: super() argument 1 must be type, not classobj. (I copied and pasted you code exactly as well) – Anake Apr 12 '11 at 14:35
  • 1
    @Anake: `initialclass` needs to inherit `object` (`class initialclass(object)`), otherwise it's an old-style class, which is little more than a headache-inducing relic from the past and should be avoided. –  Apr 12 '11 at 14:39
4

It's incredibly simple. Define a new __init__ method and call the parent's __init__ at the beginning.

# assuming a class Base, its __init__ takes one parameter x

class Derived(Base):
    def __init__(self, x, y):
        # whatever initialization is needed so we can say Derived is-a Base
        super(Derived, self).__init__(x)
        # now, add whatever makes Derived special - do your own initialization
        self.y = y

In Python 3, you don't have to (and therefore propably shouldn't, for simplicity) explicitly inherit from object or pass the class and self to super.

0

Just call a designated method from the parent's init, if it exists:

class initialclass():
    def __init__(self):
        self.attr1 = 'one'
        self.attr2 = 'two'  
        if hasattr(self, 'init_subclass'):
            self.init_subclass()

class inheritedclass(initialclass):
    def init_subclass(self):
        self.attr3 = 'three'
Lauritz V. Thaulow
  • 49,139
  • 12
  • 73
  • 92
  • 1
    Virtual -1. No need to do any extra work, let alone `hasattr` and extra methods, in the parent class. You can simply define a new `__init__` that calls the parent's `__init__` using `super`. –  Apr 12 '11 at 14:12
  • @delnan I know this, but the question was "is there a way of giving the inherited class an init type method _which does not override the init method of the parent class_". I've provided such a way. This has the added benefit of giving an entrypoint to calling _only_ the subclass init from some other subclass method. – Lauritz V. Thaulow Apr 12 '11 at 14:22
  • 1
    That's why it's virtual. I know it's what OP asked for, but OP asked "How do I use a hammer to do this?" and the answer is "You use a screwdriver". –  Apr 12 '11 at 14:28
  • @delnan What I _thought_ OP asked was, to borrow your anology, "How do I use a hammer to do this when I don't want to use a screwdriver?". I assumed overriding included extending, since to my mind an extended method is simply a type of overridden method -- one that calls the parent method somehow. I assumed, wrongly it seems, he knew how to extend a method. By the way, aren't all python methods virtual? I've never heard anyone talk about virtual methods in python. – Lauritz V. Thaulow Apr 12 '11 at 14:40
  • You're correct about Python methods being virtual, the -1 is virtual ;) –  Apr 12 '11 at 14:43
0
class initialclass:
        def __init__(self):
                self.attr1 = 'one'
                self.attr2 = 'two'
class inheritedclass(initialclass):
        def __init__(self):
                super().__init__()
                self.attr3 = 'three'
        def somemethod(self):
                print (self.attr1, self.attr2, self.attr3)
a=inheritedclass()
a.somemethod()

 1. List item
Pingolin
  • 3,161
  • 6
  • 25
  • 40
Sacchit Jaiswal
  • 261
  • 3
  • 3