Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #30484 > unrolled thread
| Started by | Ramchandra Apte <maniandram01@gmail.com> |
|---|---|
| First post | 2012-09-29 06:27 -0700 |
| Last post | 2012-09-30 00:10 -0600 |
| Articles | 18 — 7 participants |
Back to article view | Back to comp.lang.python
Should one always add super().__init__() to the __init__? Ramchandra Apte <maniandram01@gmail.com> - 2012-09-29 06:27 -0700
Re: Should one always add super().__init__() to the __init__? Ramchandra Apte <maniandram01@gmail.com> - 2012-09-29 06:28 -0700
Re: Should one always add super().__init__() to the __init__? Ian Kelly <ian.g.kelly@gmail.com> - 2012-09-29 10:59 -0600
Re: Should one always add super().__init__() to the __init__? Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2012-09-29 17:17 +0000
Re: Should one always add super().__init__() to the __init__? Devin Jeanpierre <jeanpierreda@gmail.com> - 2012-09-29 14:18 -0400
Re: Should one always add super().__init__() to the __init__? Chris Angelico <rosuav@gmail.com> - 2012-09-30 04:31 +1000
Re: Should one always add super().__init__() to the __init__? Piet van Oostrum <piet@vanoostrum.org> - 2012-09-29 17:51 -0400
Re: Should one always add super().__init__() to the __init__? Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2012-09-30 04:40 +0000
Re: Should one always add super().__init__() to the __init__? Ian Kelly <ian.g.kelly@gmail.com> - 2012-09-30 00:08 -0600
Re: Should one always add super().__init__() to the __init__? Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2012-09-30 09:34 +0000
Re: Should one always add super().__init__() to the __init__? Manuel Pégourié-Gonnard <mpg@elzevir.fr> - 2012-09-30 14:04 +0200
Re: Should one always add super().__init__() to the __init__? Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2012-09-30 04:37 +0000
Re: Should one always add super().__init__() to the __init__? Chris Angelico <rosuav@gmail.com> - 2012-09-30 14:53 +1000
Re: Should one always add super().__init__() to the __init__? Ian Kelly <ian.g.kelly@gmail.com> - 2012-09-30 01:13 -0600
Re: Should one always add super().__init__() to the __init__? Ramchandra Apte <maniandram01@gmail.com> - 2012-09-29 20:14 -0700
Re: Should one always add super().__init__() to the __init__? Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2012-09-30 04:23 +0000
Re: Should one always add super().__init__() to the __init__? Ramchandra Apte <maniandram01@gmail.com> - 2012-09-29 21:55 -0700
Re: Should one always add super().__init__() to the __init__? Ian Kelly <ian.g.kelly@gmail.com> - 2012-09-30 00:10 -0600
| From | Ramchandra Apte <maniandram01@gmail.com> |
|---|---|
| Date | 2012-09-29 06:27 -0700 |
| Subject | Should one always add super().__init__() to the __init__? |
| Message-ID | <d8fc9d99-8dc0-4290-88a0-33cd38d09f7d@googlegroups.com> |
Should one always add super().__init__() to the __init__? The reason for this is the possibility of changing base classes (and forgetting to update the __init__).
[toc] | [next] | [standalone]
| From | Ramchandra Apte <maniandram01@gmail.com> |
|---|---|
| Date | 2012-09-29 06:28 -0700 |
| Message-ID | <403a13e6-a118-4620-bf3d-827644987d81@googlegroups.com> |
| In reply to | #30484 |
On Saturday, 29 September 2012 18:57:48 UTC+5:30, Ramchandra Apte wrote: > Should one always add super().__init__() to the __init__? The reason for this is the possibility of changing base classes (and forgetting to update the __init__). This is my first post so I may be breaching nettique.
[toc] | [prev] | [next] | [standalone]
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2012-09-29 10:59 -0600 |
| Message-ID | <mailman.1640.1348937989.27098.python-list@python.org> |
| In reply to | #30484 |
On Sat, Sep 29, 2012 at 7:27 AM, Ramchandra Apte <maniandram01@gmail.com> wrote: > Should one always add super().__init__() to the __init__? The reason for this is the possibility of changing base classes (and forgetting to update the __init__). As long as the class and its subclasses only use single inheritance, it makes little difference, so if you think it will reduce the maintenance burden, I would say go for it.
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2012-09-29 17:17 +0000 |
| Message-ID | <50672d20$0$29981$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #30484 |
On Sat, 29 Sep 2012 06:27:47 -0700, Ramchandra Apte wrote: > Should one always add super().__init__() to the __init__? The reason for > this is the possibility of changing base classes (and forgetting to > update the __init__). No. Only add code that works and that you need. Arbitrarily adding calls to the superclasses "just in case" may not work: py> class Spam(object): ... def __init__(self, x): ... self.x = x ... super(Spam, self).__init__(x) ... py> x = Spam(1) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 4, in __init__ TypeError: object.__init__() takes no parameters -- Steven
[toc] | [prev] | [next] | [standalone]
| From | Devin Jeanpierre <jeanpierreda@gmail.com> |
|---|---|
| Date | 2012-09-29 14:18 -0400 |
| Message-ID | <mailman.1649.1348942728.27098.python-list@python.org> |
| In reply to | #30514 |
On Sat, Sep 29, 2012 at 1:17 PM, Steven D'Aprano <steve+comp.lang.python@pearwood.info> wrote: > No. Only add code that works and that you need. Arbitrarily adding calls > to the superclasses "just in case" may not work: > > > > py> class Spam(object): > ... def __init__(self, x): > ... self.x = x > ... super(Spam, self).__init__(x) > ... > py> x = Spam(1) > Traceback (most recent call last): > File "<stdin>", line 1, in <module> > File "<stdin>", line 4, in __init__ > TypeError: object.__init__() takes no parameters That's a good thing. We've gone from code that doesn't call the initializer and leaves the object in a potentially invalid state (silently!), to code that calls the initializer and then fails (loudly). -- Devin
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2012-09-30 04:31 +1000 |
| Message-ID | <mailman.1650.1348943511.27098.python-list@python.org> |
| In reply to | #30514 |
On Sun, Sep 30, 2012 at 3:17 AM, Steven D'Aprano <steve+comp.lang.python@pearwood.info> wrote: > No. Only add code that works and that you need. Arbitrarily adding calls > to the superclasses "just in case" may not work: > > py> class Spam(object): > ... def __init__(self, x): > ... self.x = x > ... super(Spam, self).__init__(x) > ... > py> x = Spam(1) > Traceback (most recent call last): > File "<stdin>", line 1, in <module> > File "<stdin>", line 4, in __init__ > TypeError: object.__init__() takes no parameters That's because you're subclassing something that doesn't take parameters and giving it parameters. Of course that won't work. The normal and logical thing to do is to pass on only the parameters that you know the parent class expects... but that implies knowing the parent, so it's kinda moot. ChrisA
[toc] | [prev] | [next] | [standalone]
| From | Piet van Oostrum <piet@vanoostrum.org> |
|---|---|
| Date | 2012-09-29 17:51 -0400 |
| Message-ID | <m23920jy5a.fsf@cochabamba.vanoostrum.org> |
| In reply to | #30521 |
Chris Angelico <rosuav@gmail.com> writes: > On Sun, Sep 30, 2012 at 3:17 AM, Steven D'Aprano > <steve+comp.lang.python@pearwood.info> wrote: >> No. Only add code that works and that you need. Arbitrarily adding calls >> to the superclasses "just in case" may not work: >> >> py> class Spam(object): >> ... def __init__(self, x): >> ... self.x = x >> ... super(Spam, self).__init__(x) >> ... >> py> x = Spam(1) >> Traceback (most recent call last): >> File "<stdin>", line 1, in <module> >> File "<stdin>", line 4, in __init__ >> TypeError: object.__init__() takes no parameters > > That's because you're subclassing something that doesn't take > parameters and giving it parameters. Of course that won't work. The > normal and logical thing to do is to pass on only the parameters that > you know the parent class expects... but that implies knowing the > parent, so it's kinda moot. It is not necesarily calling the parent class. It calls the initializer of the next class in the MRO order and what class that is depends on the actual multiple inheritance structure it is used in, which can depend on subclasses that you don't know yet. This makes it even worse. -- Piet van Oostrum <piet@vanoostrum.org> WWW: http://pietvanoostrum.com/ PGP key: [8DAE142BE17999C4]
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2012-09-30 04:40 +0000 |
| Message-ID | <5067cd36$0$29981$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #30530 |
On Sat, 29 Sep 2012 17:51:29 -0400, Piet van Oostrum wrote: > It is not necesarily calling the parent class. It calls the initializer > of the next class in the MRO order and what class that is depends on the > actual multiple inheritance structure it is used in, which can depend on > subclasses that you don't know yet. This makes it even worse. I don't quite follow you here. It sounds like you are saying that if you have these classes: # pre-existing classes class A(object): pass class B(object): pass # your class class C(A, B): pass and somebody subclasses A or B, the MRO of C will change. That is not actually the case as far as I can see. -- Steven
[toc] | [prev] | [next] | [standalone]
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2012-09-30 00:08 -0600 |
| Message-ID | <mailman.1663.1348985321.27098.python-list@python.org> |
| In reply to | #30539 |
On Sat, Sep 29, 2012 at 10:40 PM, Steven D'Aprano <steve+comp.lang.python@pearwood.info> wrote: > On Sat, 29 Sep 2012 17:51:29 -0400, Piet van Oostrum wrote: > >> It is not necesarily calling the parent class. It calls the initializer >> of the next class in the MRO order and what class that is depends on the >> actual multiple inheritance structure it is used in, which can depend on >> subclasses that you don't know yet. This makes it even worse. > > I don't quite follow you here. It sounds like you are saying that if you > have these classes: > > # pre-existing classes > class A(object): pass > class B(object): pass > > # your class > class C(A, B): pass > > and somebody subclasses A or B, the MRO of C will change. That is not > actually the case as far as I can see. The MRO of C will not change, but the class that follows C may be different in the MRO of a subclass.
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2012-09-30 09:34 +0000 |
| Message-ID | <50681219$0$29981$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #30543 |
On Sun, 30 Sep 2012 00:08:03 -0600, Ian Kelly wrote: > On Sat, Sep 29, 2012 at 10:40 PM, Steven D'Aprano > <steve+comp.lang.python@pearwood.info> wrote: >> On Sat, 29 Sep 2012 17:51:29 -0400, Piet van Oostrum wrote: >> >>> It is not necesarily calling the parent class. It calls the >>> initializer of the next class in the MRO order and what class that is >>> depends on the actual multiple inheritance structure it is used in, >>> which can depend on subclasses that you don't know yet. This makes it >>> even worse. >> >> I don't quite follow you here. It sounds like you are saying that if >> you have these classes: >> >> # pre-existing classes >> class A(object): pass >> class B(object): pass >> >> # your class >> class C(A, B): pass >> >> and somebody subclasses A or B, the MRO of C will change. That is not >> actually the case as far as I can see. > > The MRO of C will not change, but the class that follows C may be > different in the MRO of a subclass. To quote a famous line from the movie Cool Hand Luke, "what we have here, is a failure to communicate." What do you mean by one class following another? Which class is it that follows C? What subclass are you talking about, and what is it subclassing? I have absolutely no idea what you are trying to get across here, why you think it is important, or whether it matches what Piet is trying to say. -- Steven
[toc] | [prev] | [next] | [standalone]
| From | Manuel Pégourié-Gonnard <mpg@elzevir.fr> |
|---|---|
| Date | 2012-09-30 14:04 +0200 |
| Message-ID | <k49cfk$hqo$1@thue.elzevir.fr> |
| In reply to | #30547 |
Steven D'Aprano scripsit :
> On Sun, 30 Sep 2012 00:08:03 -0600, Ian Kelly wrote:
>
>> On Sat, Sep 29, 2012 at 10:40 PM, Steven D'Aprano
>> <steve+comp.lang.python@pearwood.info> wrote:
>>> On Sat, 29 Sep 2012 17:51:29 -0400, Piet van Oostrum wrote:
>>>
>>>> It is not necesarily calling the parent class. It calls the
>>>> initializer of the next class in the MRO order and what class that is
>>>> depends on the actual multiple inheritance structure it is used in,
>>>> which can depend on subclasses that you don't know yet. This makes it
>>>> even worse.
>>>
>>> I don't quite follow you here. It sounds like you are saying that if
>>> you have these classes:
>>>
>>> # pre-existing classes
>>> class A(object): pass
>>> class B(object): pass
>>>
>>> # your class
>>> class C(A, B): pass
>>>
>>> and somebody subclasses A or B, the MRO of C will change. That is not
>>> actually the case as far as I can see.
>>
>> The MRO of C will not change, but the class that follows C may be
>> different in the MRO of a subclass.
>
> To quote a famous line from the movie Cool Hand Luke, "what we have here,
> is a failure to communicate."
>
> What do you mean by one class following another? Which class is it
> that follows C? What subclass are you talking about, and what is it
> subclassing?
>
I think Piet's (and Ian's) point is, you can't assume that
super().__init__, written in a method of C, is always going to refer to
__init__ of the parent class of C, when a subclass of C is instanciated.
For example:
class C:
def __init__(self):
print("C init, calling C's parent init?")
super().__init__() # sic
class NotParentOfC:
def __init__(self):
print("NotParentOfC init")
class Sub(C, NotParentOfC):
pass
spam = Sub()
When Sub is instantiated, the line marked "sic" calls
NotParentOfC.__init, not object.__init__ (as if would if C was
instantiated).
--
Manuel Pégourié-Gonnard - http://people.math.jussieu.fr/~mpg/
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2012-09-30 04:37 +0000 |
| Message-ID | <5067cc81$0$29981$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #30521 |
On Sun, 30 Sep 2012 04:31:48 +1000, Chris Angelico wrote: > On Sun, Sep 30, 2012 at 3:17 AM, Steven D'Aprano > <steve+comp.lang.python@pearwood.info> wrote: >> No. Only add code that works and that you need. Arbitrarily adding >> calls to the superclasses "just in case" may not work: >> >> py> class Spam(object): >> ... def __init__(self, x): >> ... self.x = x >> ... super(Spam, self).__init__(x) ... >> py> x = Spam(1) >> Traceback (most recent call last): >> File "<stdin>", line 1, in <module> >> File "<stdin>", line 4, in __init__ >> TypeError: object.__init__() takes no parameters > > That's because you're subclassing something that doesn't take parameters > and giving it parameters. Of course that won't work. The normal and > logical thing to do is to pass on only the parameters that you know the > parent class expects... but that implies knowing the parent, so it's > kinda moot. Which is exactly my point -- you can't call the superclass "just in case" it changes, because you don't know what arguments the new superclass or classes expect. You have to tailor the arguments to what the parent expects, and even whether or not you have to call super at all.[1] super() is not some magic command "don't bother me with the details, just make method overriding work". You have to actually think about what you are overriding. You can't expect to take a class that inherits from dict and change it to inherit from collections.defaultdict and have super magically sort out the differences in __init__. The usual advise given for using super is: * the method being called by super() needs to exist * the caller and callee need to have a matching[2] argument signature * and every occurrence of the method needs to use super() If all three conditions apply, then yes, you should use super. Otherwise, perhaps not. For further discussion and practical examples, see: http://rhettinger.wordpress.com/2011/05/26/super-considered-super/ For a contrary argument, or at least a look at how NOT to use super, see: https://fuhm.net/super-harmful/ which makes the mistake of blaming super() for mistakes made by people who don't use it correctly. Note that the author has back-peddled from his original argument that super was actively harmful to a less provocative argument that "you can't use super" (except you actually can: if you read past the first paragraph, the author tells you exactly what you need to do to use super correctly). [1] You *should* call super, unless you have an excellent reason not to, so that your class doesn't break multiple-inheritance. But you need to do so with care making sure that the argument signatures are designed for cooperative use of super. [2] Matching in this case does not necessarily mean identical. -- Steven
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2012-09-30 14:53 +1000 |
| Message-ID | <mailman.1661.1348980792.27098.python-list@python.org> |
| In reply to | #30538 |
On Sun, Sep 30, 2012 at 2:37 PM, Steven D'Aprano <steve+comp.lang.python@pearwood.info> wrote: > Which is exactly my point -- you can't call the superclass "just in case" > it changes, because you don't know what arguments the new superclass or > classes expect. You have to tailor the arguments to what the parent > expects, and even whether or not you have to call super at all.[1] > > super() is not some magic command "don't bother me with the details, just > make method overriding work". You have to actually think about what you > are overriding. Yeah. Far as I'm concerned, subclassing should *always* involve knowing the parent class. You needn't concern yourself with its implementation (I can subclass dict without caring about the details of hash randomization), but you have to be aware of its interface. And if you change the base class without changing your method chaining, you'd better be changing to a new base class that's equivalent to the old one. The advantage of super() is that you can substitute a subclass of X as a new base class without changing anything. But you need to be sure that the replacement base class obeys the Liskov Substitution Principle. ChrisA
[toc] | [prev] | [next] | [standalone]
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2012-09-30 01:13 -0600 |
| Message-ID | <mailman.1665.1348989229.27098.python-list@python.org> |
| In reply to | #30538 |
On Sat, Sep 29, 2012 at 10:37 PM, Steven D'Aprano
<steve+comp.lang.python@pearwood.info> wrote:
> [1] You *should* call super, unless you have an excellent reason not to,
> so that your class doesn't break multiple-inheritance. But you need to do
> so with care making sure that the argument signatures are designed for
> cooperative use of super.
I disagree. Most classes will not ever be used for multiple
inheritance, and the changes involved in "making sure that the
argument signatures are designed for cooperative use of super" are not
trivial. For one, it means not being able to use positional arguments
in __init__ methods. For two, the
receive-and-strip-off-keyword-arguments approach falls apart if you
have unrelated classes that take the same arguments. For
illustration, suppose you have the following two classes, both of
which use a required Frobnik object to perform their functions.
class A:
def __init__(self, frobnik, **kwargs):
super().__init__(**kwargs)
self._frobnik = frobnik
...
class B:
def __init__(self, frobnik, **kwargs):
super().__init__(**kwargs)
self._frobnik = frobnik
...
Even though these classes have been designed to be cooperative, they
cannot be inherited together. Whichever class is first in the MRO
will receive the frobnik argument and strip it off, and then the other
class's __init__ method will complain of a missing required argument.
There are solutions to this. For instance, you could make frobnik
optional in each class, each one relying on the other to receive the
frobnik argument if it is missing, but this complicates the
implementations and makes it difficult to detect in a timely manner if
the frobnik argument has actually not been supplied. Or you could
change the name of the argument in one of the classes, but then your
library users will complain of inconsistent naming.
What it boils down to is that classes that are expected to be used for
multiple inheritance should be designed to use super cooperatively,
but the majority of classes that you write should not have to deal
with these sorts of restrictions. Classes that will only ever be
singly inherited should be written normally and using whatever
superclass call style feels most appropriate.
[toc] | [prev] | [next] | [standalone]
| From | Ramchandra Apte <maniandram01@gmail.com> |
|---|---|
| Date | 2012-09-29 20:14 -0700 |
| Message-ID | <46096186-8383-4990-99c9-61c87f1c5a2f@googlegroups.com> |
| In reply to | #30514 |
On Saturday, 29 September 2012 22:47:20 UTC+5:30, Steven D'Aprano wrote: > On Sat, 29 Sep 2012 06:27:47 -0700, Ramchandra Apte wrote: > > > > > Should one always add super().__init__() to the __init__? The reason for > > > this is the possibility of changing base classes (and forgetting to > > > update the __init__). > > > > No. Only add code that works and that you need. Arbitrarily adding calls > > to the superclasses "just in case" may not work: > > > > > > > > py> class Spam(object): > > ... def __init__(self, x): > > ... self.x = x > > ... super(Spam, self).__init__(x) > > ... > > py> x = Spam(1) > > Traceback (most recent call last): > > File "<stdin>", line 1, in <module> > > File "<stdin>", line 4, in __init__ > > TypeError: object.__init__() takes no parameters > > > > > > > > -- > > Steven I forgot something: I meant super().__init__() or similar
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2012-09-30 04:23 +0000 |
| Message-ID | <5067c951$0$29981$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #30534 |
On Sat, 29 Sep 2012 20:14:10 -0700, Ramchandra Apte wrote: > I forgot something: > I meant super().__init__() or similar What about it? Please try to remember that we can't read your mind and don't know what you are thinking, we can only work from what you put in writing. There is no difference between super(Class, self).__init__ and super().__init__ except that the second version only works in Python 3. -- Steven
[toc] | [prev] | [next] | [standalone]
| From | Ramchandra Apte <maniandram01@gmail.com> |
|---|---|
| Date | 2012-09-29 21:55 -0700 |
| Message-ID | <66f99af0-39c2-4ef1-8f1e-dac17924432f@googlegroups.com> |
| In reply to | #30537 |
On Sunday, 30 September 2012 09:53:45 UTC+5:30, Steven D'Aprano wrote: > On Sat, 29 Sep 2012 20:14:10 -0700, Ramchandra Apte wrote: > > > > > I forgot something: > > > I meant super().__init__() or similar > > > > What about it? Please try to remember that we can't read your mind and > > don't know what you are thinking, we can only work from what you put in > > writing. > > > > There is no difference between super(Class, self).__init__ and > > super().__init__ except that the second version only works in Python 3. > > > > > > > > -- > > Steven When I said "super().__init__()" it could have been "super().__init__(size+67)" or whatever arguments are needed for __init__
[toc] | [prev] | [next] | [standalone]
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2012-09-30 00:10 -0600 |
| Message-ID | <mailman.1664.1348985440.27098.python-list@python.org> |
| In reply to | #30541 |
On Sat, Sep 29, 2012 at 10:55 PM, Ramchandra Apte <maniandram01@gmail.com> wrote: > When I said "super().__init__()" it could have been "super().__init__(size+67)" or whatever arguments are needed for __init__ But if you change the base class, couldn't those arguments change? Then you would have to change the call whether super is used or not. I believe this is what Steven is getting at.
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.python
csiph-web