Using super()

P

Pupeno

Hello,
I have a class called MyConfig, it is based on Python's
ConfigParser.ConfigParser.
It implements add_section(self, section), which is also implemented on
ConfigParser.ConfigParser, which I want to call.
So, reducing the problem to the bare minimum, the class (with a useless
add_section that shows the problem):
.... def add_section(self, section):
.... super(MyConfig, self).add_section(section)
....

Create an object

and call the problematic method:
Traceback (most recent call last):
File "<stdin>", line 1, in ?

Why is super() requiring a type ? doesn't it work with classes ? Is there a
way to achieve what I am trying to do (other than calling the specific
class that happens to be the parent today) ?

Thanks.
 
L

Laszlo Nagy

Pupeno írta:
Hello,
I have a class called MyConfig, it is based on Python's
ConfigParser.ConfigParser.
It implements add_section(self, section), which is also implemented on
ConfigParser.ConfigParser, which I want to call.
So, reducing the problem to the bare minimum, the class (with a useless
add_section that shows the problem):
The problem is that ConfigParser.ConfigParser is an old style class. It
is in the standard library, so I have no clue why. For old style
classes, you should directly call the ancestor class method.
For new style classes it works just fine:


class ConfigParser(object):
def add_section(self, section):
print section, "in ",self.__class__.__name__

class MyConfig(ConfigParser):
def add_section(self, section):
super(MyConfig, self).add_section(section)

m = MyConfig()
m.add_section("blah")


The output:

blah in MyConfig
 
P

Pupeno

Laszlo said:
Pupeno írta:
The problem is that ConfigParser.ConfigParser is an old style class. It
is in the standard library, so I have no clue why. For old style
classes, you should directly call the ancestor class method.
For new style classes it works just fine:


class ConfigParser(object):
def add_section(self, section):
print section, "in ",self.__class__.__name__

class MyConfig(ConfigParser):
def add_section(self, section):
super(MyConfig, self).add_section(section)

m = MyConfig()
m.add_section("blah")

I see, thank you.

class MyConfig(ConfigParser, object):
def add_section(self, section)
super(MyConfig, self).add_section(section)

seems to work and as expected. Is there anything wrong with it ?
 
L

Laszlo Nagy

I see, thank you.

class MyConfig(ConfigParser, object):
def add_section(self, section)
super(MyConfig, self).add_section(section)

seems to work and as expected. Is there anything wrong with it ?
I have never seen this before. :) I don't know the answer, but I'm
interested too.

Laszlo
 
C

Carl Banks

Pupeno said:
I see, thank you.

class MyConfig(ConfigParser, object):
def add_section(self, section)
super(MyConfig, self).add_section(section)

seems to work and as expected. Is there anything wrong with it ?

Wow.

I highly recommend not doing this, unless the new type system was
designed to allow this sort of mixing, which I highly doubt. There are
some significant under-the-cover differences between old- and new-style
classes that could mess everything up when trying to mix them.


Carl Banks
 
J

Jan Niklas Fingerle

Pupeno said:
class MyConfig(ConfigParser, object):
def add_section(self, section)
super(MyConfig, self).add_section(section)

seems to work and as expected. Is there anything wrong with it ?

yes.

(1) There's a colon missing in the def-line. ;-)

(2) The folling doesn't work as you might expect:

----------------------------------------------8<---------------
from ConfigParser import ConfigParser
class MyConfig(ConfigParser, object):
def add_section(self, section):
print "in MyConfig"
super(MyConfig, self).add_section(section)

class AnotherConfig(object):
def add_section(self, section):
print "in AnotherConfig"
super(AnotherConfig, self).add_section(section)

class TheConfigIReallyUse(MyConfig, AnotherConfig):
def add_section(self, section):
print "in TheConfigConfigIReallyUse"
super(TheConfigIReallyUse, self).add_section(section)

a = TheConfigIReallyUse()

a.add_section(None)
---------------------------------------------->8---------------

If you call this little script, you get ...

----------------------------------------------8<---------------
in TheConfigConfigIReallyUse
in MyConfig
---------------------------------------------->8---------------

...., i. e. add_section in AnotherConfig won't be called.

The reason for this is, that the usage of "super" (or it's non-usage
in this case) is part of the interface of a class. ConfigParser doesn't
support super (as most if not all classes in the standard lib),
therefore it doesn't ensure AnotherConfig's add_section will be called
at an appropriate time. This call just gets lost.

In my world you should never user super with the only exception being
that you really know what you are doing. ;-) In fact, super is a cool
thing for non-trivial diamond shape inheritance (i.e. not counting
object to introduce the diamond shape, otherwise this would make every
multiple inheritance of new style classes a diamond shape). Even then
you have to be careful, that all methods must have the same signature
(*args and **kwargs may help you with this), because in the end you
never know which class calls which other class next. (Well, yes, you
may find out, but the next inheritance may break this again.)

In the end it comes down to:
(1) If you use diamond shape inheritance (or might in the
future), then use super.
(2) If your base classes support super, use super.
(3) If (1) goes without (2) be extra careful.
(4) Whatever you do, read the documentation of super and try to
understand what you are doing.
(5) If you want to know about the flamewar sourrounding this issue,
google for "python", "super" and "harmful"...

Cheers,
--Jan Niklas
 
M

Michele Simionato

Carl Banks ha scritto:
Wow.

I highly recommend not doing this, unless the new type system was
designed to allow this sort of mixing, which I highly doubt. There are
some significant under-the-cover differences between old- and new-style
classes that could mess everything up when trying to mix them.

I believe the new style system was designed to allows this sort of
mixing and
that there are no issues at all. A child of new style + old style is
simply a new
style class. If you do

class NewStyle(OldStyle, object):
pass

you will see that

type(NewStyle) == type

There should be something more on
http://www.python.org/download/releases/2.2.3/descrintro

(I have seen somewhere how type.__new__ works, and how the metaclass
is chosen, so I am pretty sure sure there are no issue, at least for
pure Python
classes).

Michele Simionato
 
M

Michele Simionato

Michele Simionato ha scritto:
I believe the new style system was designed to allows this sort of
mixing and
that there are no issues at all.

Thinking a bit more, there are no issues at all if you know what a new
style class is and if you do not expect it to work as an old-style one
;) For the benefit of the OP, it may be useful to notice that there are
a few differences, most notably on how special methods works. Here is
an example:

class Old:
pass

old = Old()

old.__str__ = lambda : 'hello!'

print old # special methods defined on the instance are recognized

class New(Old, object):
pass

new = New()

new.__str__ = lambda : 'hello!' # special methods defined on the
instance are not recognized

print new


HTH,

Michele Simionato
 

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,981
Messages
2,570,188
Members
46,732
Latest member
ArronPalin

Latest Threads

Top