class super method

G

gigs

is there any tutorial for super method (when/how to use it)?

or maybe someone could explain me how it works?

thx
 
E

Ed Leafe

is there any tutorial for super method (when/how to use it)?

or maybe someone could explain me how it works?

thx

Super is one of the dark corners of the language [1,2]... a good rule
of thumb is to stay away from it, or at least stick to its basic
usage.


I disagree - super is quite elegant and dependable.

Because Python support multiple inheritance, it is difficult to
manually ensure that when augmenting a method that the correct
superclass calls are made. super() handles that without having to
guess as to what the correct inheritance hierarchy is.

In my own project (Dabo), we use mixin classes liberally to provide
consistent behavior across our UI classes. The use of super makes
customizing __init__() behavior, for example, quite straightforward.
The general form looks like:

class DaboUIClass(dabo.ui.dControlMixin, someWxPythonClass):
def __init__(self, *args, **kwargs):
doOurCustomStuffBeforeTheSuperCall()
super(DaboUIClass, self).__init__(*args, **kwargs)
doOurCustomStuffAfterTheSuperCall()

This has worked reliably for us in every place where we have used it.
There's nothing dark and mysterious about it at all.

-- Ed Leafe
 
E

Ed Leafe

On Apr 1, 2008, at 7:23 AM,
I've also found myself wondering:

1. What are the two arguments to super used for?

To determine the type (1st arg) for which the superclass hierarchy is
to be determined, and the instance (2nd arg) if the super object is to
be bound. In typical usage, they are the class of the current
instance, and the 'self' reference to the instance.
2. What happens when the method supplied *after* the super is
different from the containing method?

In the above example what happens if:

class DaboUIClass(dabo.ui.dControlMixin, someWxPythonClass):
def __init__(self, *args, **kwargs):
doOurCustomStuffBeforeTheSuperCall()
super(DaboUIClass, self).callRandomMethod(foobar)
doOurCustomStuffAfterTheSuperCall()


super() returns an object that doesn't "know" in what method it was
derived, so as long as the superclass has the 'callRandomMethod'
method, and 'foobar' is defined, there is no problem at all. IOW, the
only context is the class of the instance, not any particular method
of the instance.

You could also do something like this:

class DaboUIClass(dabo.ui.dControlMixin, someWxPythonClass):
def __init__(self, *args, **kwargs):
doOurCustomStuffBeforeTheSuperCall()
self.super = super(DaboUIClass, self)
self.super.__init__(*args, **kwargs)
doOurCustomStuffAfterTheSuperCall()

def someMethod(self, foo, bar):
self.super.someMethod(foo, bar)

def someOtherMethod(self):
self.super.someOtherMethod()

-- Ed Leafe
 
G

George Sakkis

Super is one of the dark corners of the language [1,2]... a good rule
of thumb is to stay away from it, or at least stick to its basic
usage.

I disagree - super is quite elegant and dependable.

Did you follow the links I gave by any chance? With all the gotchas
and rules of how to use it properly, it's far from what I would call
elegant.
In my own project (Dabo), we use mixin classes liberally to provide
consistent behavior across our UI classes. The use of super makes
customizing __init__() behavior, for example, quite straightforward.
The general form looks like:

class DaboUIClass(dabo.ui.dControlMixin, someWxPythonClass):
def __init__(self, *args, **kwargs):
doOurCustomStuffBeforeTheSuperCall()
super(DaboUIClass, self).__init__(*args, **kwargs)
doOurCustomStuffAfterTheSuperCall()

This has worked reliably for us in every place where we have used it.
There's nothing dark and mysterious about it at all.

Pehaps, at least as long as you make sure that all superclasses have a
compatible signature - which in practice typically means accept
arbitrary *args and **kwargs in every class in the hierarchy like your
example. Good luck figuring out what's wrong if it's not used
consistently.

Also doOurCustomStuffBeforeTheSuperCall() works as long as all
ancestor methods to be called need the same CustomStuff massaging.

In a sentence, it's better than nothing but worse than anything.

George
 
E

Ed Leafe

Did you follow the links I gave by any chance? With all the gotchas
and rules of how to use it properly, it's far from what I would call
elegant.

Please. Anything powerful can be dangerous if used indiscriminately.
But in a language that supports multiple inheritance, it is amazingly
elegant to use a simple function to create a superclass object for a
class with multiple mixins at various levels of the inheritance
hierarchy that "just works". Yes, having to specify the current class
is a bit of a wart that is being addressed in 3.0, but the approach is
still the same.
Pehaps, at least as long as you make sure that all superclasses have a
compatible signature - which in practice typically means accept
arbitrary *args and **kwargs in every class in the hierarchy like your
example. Good luck figuring out what's wrong if it's not used
consistently.

See my comment above. If you do not know what you're doing, you
shouldn't be doing it. This is not the fault of super(); it's the
fault of a poor programmer. And I used generic *args and **kwargs in
the method sig since I was using made-up class names and methods.
Would you have reacted more favorably if I had used (self, foo, bar)
instead?
Also doOurCustomStuffBeforeTheSuperCall() works as long as all
ancestor methods to be called need the same CustomStuff massaging.

Oh, c'mon. Of course that's the case; if you are overriding method
behavior, it is your job as the programmer to ensure that. Again, this
is nothing to do with the super() function, and everything to do with
the abilities of the developer.
In a sentence, it's better than nothing but worse than anything.


I guess I must be the world's most amazing Python developer, as I've
used super() extensively for years without ever suffering any of the
pitfalls you and others describe.

-- Ed Leafe
 
G

George Sakkis

See my comment above. If you do not know what you're doing, you
shouldn't be doing it. This is not the fault of super(); it's the
fault of a poor programmer. And I used generic *args and **kwargs in
the method sig since I was using made-up class names and methods.
Would you have reacted more favorably if I had used (self, foo, bar)
instead?

No, that was exactly my point; with a non-generic signature like
(self, foo, bar), it's a matter of time until some subclass breaks it.
Non-trivial hierarchies with all __init__ having compatible signatures
is not typical in my experience, but they have to be compatible to be
used correctly with super. Here is the conclusion from the second
article I linked:

'''
If you do use super, here are some best practices:

* Use it consistently, and document that you use it, as it is part
of the external interface for your class, like it or not.
* Never call super with anything but the exact arguments you
received, unless you really know what you're doing.
* When you use it on methods whose acceptable arguments can be
altered on a subclass via addition of more optional arguments, always
accept *args, **kw, and call super like "super(MyClass,
self).currentmethod(alltheargsideclared, *args, **kwargs)". If you
don't do this, forbid addition of optional arguments in subclasses.
* Never use positional arguments in __init__ or __new__. Always
use keyword args, and always call them as keywords, and always pass
all keywords on to super.
'''
I guess I must be the world's most amazing Python developer, as I've
used super() extensively for years without ever suffering any of the
pitfalls you and others describe.

Some people use the same argument for explicit memory management in C/C
++. Sure, it can be done, but that doesn't make it elegant or trivial.
When experts like Michele Simionato find super() tricky enough to
write an article about it, that says something.

George
 
G

Gabriel Genellina

See my comment above. If you do not know what you're doing, you
shouldn't be doing it. This is not the fault of super(); it's the
fault of a poor programmer. And I used generic *args and **kwargs in
the method sig since I was using made-up class names and methods.
Would you have reacted more favorably if I had used (self, foo, bar)
instead?

Then *all* classes must use exactly the same signature for that method.
You don't know which one will be the next class in the MRO order used by
super() so you can't adjust the arguments in any way.
In the case of __init__, the only practical way is to make all of them
take keyword arguments exclusively and use *args and **kwarsg.
See the earlier links for a simple failing example.
Oh, c'mon. Of course that's the case; if you are overriding method
behavior, it is your job as the programmer to ensure that. Again, this
is nothing to do with the super() function, and everything to do with
the abilities of the developer.

How do you know that? super may call a method on a different class that is
*not* an ancestor of the current class. Again, for examples, see the
earlier links.
I guess I must be the world's most amazing Python developer, as I've
used super() extensively for years without ever suffering any of the
pitfalls you and others describe.

Maybe you're a very lucky man!
 
M

Michele Simionato

I disagree - super is quite elegant and dependable.

Because Python support multiple inheritance, it is difficult to
manually ensure that when augmenting a method that the correct
superclass calls are made. super() handles that without having to
guess as to what the correct inheritance hierarchy is.

In my own project (Dabo), we use mixin classes liberally to provide
consistent behavior across our UI classes. The use of super makes
customizing __init__() behavior, for example, quite straightforward.
The general form looks like:

class DaboUIClass(dabo.ui.dControlMixin, someWxPythonClass):
def __init__(self, *args, **kwargs):
doOurCustomStuffBeforeTheSuperCall()
super(DaboUIClass, self).__init__(*args, **kwargs)
doOurCustomStuffAfterTheSuperCall()

This has worked reliably for us in every place where we have used it.
There's nothing dark and mysterious about it at all.

It is just that you did not run (yet) in a corner case of super. The
interesting question would be: did any of your users run into issues
using you library which is heavily relying on super? Especially when
composing it with their own classes?
I personally have changed my opinion about multiple inheritance over
the years.
At the beginning I thought it was a very cool idea, but now I think it
is a pretty bad idea. If I were to design a language, I would not
implement multiple inheritance. In Python I never use multiple
inheritance and actually I try very hard to avoid even single
inheritance, preferring composition whenever it is viable.

Michele Simionato
 
E

Ed Leafe

It is just that you did not run (yet) in a corner case of super. The
interesting question would be: did any of your users run into issues
using you library which is heavily relying on super? Especially when
composing it with their own classes?

None so far, and our users are pretty good about reporting bugs!
I personally have changed my opinion about multiple inheritance over
the years.
At the beginning I thought it was a very cool idea, but now I think it
is a pretty bad idea. If I were to design a language, I would not
implement multiple inheritance. In Python I never use multiple
inheritance and actually I try very hard to avoid even single
inheritance, preferring composition whenever it is viable.

I think MI is great as long as you understand how to use it. I would
never encourage anyone to mix dissimilar classes; that's just poor
design. But a well-designed mixin class is a wonderful thing.

I also don't consider inheritance and composition to be either/or
choices. Both can (and usually should) be part of a well-designed
application. In my experience, using either incorrectly can get you in
trouble.

-- Ed Leafe
 
S

Steve Holden

George said:
is there any tutorial for super method (when/how to use it)?
or maybe someone could explain me how it works?
thx
Super is one of the dark corners of the language [1,2]... a good rule
of thumb is to stay away from it, or at least stick to its basic
usage.
I disagree - super is quite elegant and dependable.

Did you follow the links I gave by any chance? With all the gotchas
and rules of how to use it properly, it's far from what I would call
elegant.
In my own project (Dabo), we use mixin classes liberally to provide
consistent behavior across our UI classes. The use of super makes
customizing __init__() behavior, for example, quite straightforward.
The general form looks like:

class DaboUIClass(dabo.ui.dControlMixin, someWxPythonClass):
def __init__(self, *args, **kwargs):
doOurCustomStuffBeforeTheSuperCall()
super(DaboUIClass, self).__init__(*args, **kwargs)
doOurCustomStuffAfterTheSuperCall()

This has worked reliably for us in every place where we have used it.
There's nothing dark and mysterious about it at all.

Pehaps, at least as long as you make sure that all superclasses have a
compatible signature - which in practice typically means accept
arbitrary *args and **kwargs in every class in the hierarchy like your
example. Good luck figuring out what's wrong if it's not used
consistently.

Also doOurCustomStuffBeforeTheSuperCall() works as long as all
ancestor methods to be called need the same CustomStuff massaging.

In a sentence, it's better than nothing but worse than anything.
So you are prepared to write off the voice of experience because some
random web pages contradict what Ed is saying?

As Ed rightly points out, any sufficiently complex gun can end up
shooting you in the foot.

regards
Steve
 
S

Steve Holden

Steve said:
So you are prepared to write off the voice of experience because some
random web pages contradict what Ed is saying?

As Ed rightly points out, any sufficiently complex gun can end up
shooting you in the foot.
Lest my remarks should be thought disrespectful to Michele Simionato, I
should point out that I am familiar with those comments, and they do
correctly identify problems with super() which are in fact fundamental
to any multiple inheritance scheme. So it was a little rude of me to
refer to "some random web pages" there, and I apologize.

Ed is a good enough designer to avoid the corner cases. Strangely enough
the one place where I have ended up making significant use of super()
was in providing mixins for wxPython interface classes!

regards
Steve
 
E

Ed Leafe

Ed is a good enough designer to avoid the corner cases. Strangely
enough
the one place where I have ended up making significant use of super()
was in providing mixins for wxPython interface classes!

Thanks much for the compliment. Yes, wrapping the disparate and
confusing wxPython classes to have a consistent interface is where we
also make the most use of super(), but our database wrappers also
provide consistent functionality to all the dbapi cursors, no matter
what the backend database may be.

The only reason this works is that we are working with a single known
class interface; we control all our own mixin class designs. With the
wxPython stuff, each class has a well-defined set of methods and
method signatures, and with the database stuff, we only mixin with the
dbapi-standard methods, and avoid hooking into module-specific
enhancements.

My point in these postings is that working with multiple inheritance
is fraught with potential pitfalls; super() doesn't create these
pitfalls, although it can make it easier to fall into them. If you try
to create a PotBelliedElephant class by using MI with a PotBelliedPig
class and an Elephant class, well, you *should* crash and burn,
whether you use super() or not.

http://en.wikipedia.org/wiki/An_Elephant_Makes_Love_to_a_Pig

-- Ed Leafe
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top