super with only one argument

S

Steven Bethard

When would you call super with only one argument? The only examples I
can find of doing this are in the test suite for super. Playing around
with it:

py> class A(object):
.... x = 'a'
....
py> class B(A):
.... x = 'b'
....
py> s = super(B)
py> s.x
Traceback (most recent call last):
File "<interactive input>", line 1, in ?
AttributeError: 'super' object has no attribute 'x'

So I can't access class attributes with a single-argument super.

You can see that there are some interesting attributes on a super object:

py> for name in dir(s):
.... if not hasattr(object, name):
.... print name, getattr(s, name)
....
__get__ <method-wrapper object at 0x011FD050>
__self__ None
__self_class__ None
__thisclass__ <class '__main__.B'>

Looks like I can call the descriptor machinery directly to get an attribute:

py> s.__get__(B).x
'a'
py> s.__get__(B, B()).x
'a'

But this doesn't seem horribly useful. And __self__, __self_class__ and
__thisclass__ are readonly, so I can't bind a super object to an
instance once it's been created.

So what's the use case?

Thanks in advance,

STeVe

P.S. The context here is that I'm trying to submit a patch to clarify
the docs on super a bit. But I realized that I don't actually
understand its behavior with only a single argument...
 
M

Michele Simionato

I asked myself the same question and I am not convinced
that using 'super' with one argument really makes sense
(i.e. IMO it is more a liability than an asset). BTW, I have a set
of notes on the tricky aspects of 'super' you may be interested in.

Michele Simionato
 
J

John Roth

Michele Simionato said:
I asked myself the same question and I am not convinced
that using 'super' with one argument really makes sense
(i.e. IMO it is more a liability than an asset). BTW, I have a set
of notes on the tricky aspects of 'super' you may be interested in.

Michele Simionato

Wouldn't you use it to access the overridden version
of a static method?

John Roth
 
M

Michele Simionato

No, you should use the version with two arguments for that.
The second argument would be a class however, not an instance.
Example:

class C(object):
@staticmethod
def f():
print "C.f"

class D(C):
@staticmethod
def f():
print "D.f"
super(D, D).f()

D.f()

Just using super(D).f() would not work. ``super`` with only one
argument is
a recipe for headaches.

Michele Simionato
 
G

Greg Chapman

Steven said:
When would you call super with only one argument? The only examples
I can find of doing this are in the test suite for super.

I think it's to allow something like this:

class A(B, C):
__super = super(A)
def foo(self):
return self.__super.foo()

This allows you to rename A and only have to change one super call to
reflect the new name.
 
G

Greg Chapman

Greg said:
I think it's to allow something like this:

class A(B, C):
__super = super(A)
def foo(self):
return self.__super.foo()

This allows you to rename A and only have to change one super call to
reflect the new name.

Except that doesn't work unless you use something like the autosuper
metaclass trick from test_descr.py (since the class A does not yet
exist where I put that super call). And autosuper has a comment that
it "only works for dynamic classes" -- not sure that I understand what
"dynamic" means there.

In case you haven't guessed by now, I've only used two-arg super in my
own code.
 
M

Michele Simionato

``super`` with only one argument ("bound" super) is a mess.

AFAICT ``super(C)`` is intended to be used as an attribute in
other classes. Then the descriptor magic will automatically convert the

unbound syntax in the bound syntax. For instance:
1

This works since ``d.sup.a`` calls ``super(C).__get__(d,D).a`` which is
converted to ``super(C, d).a`` and retrieves ``B.a``.

There is a single use case for the single argument
syntax of ``super`` that I am aware of, but I think it gives more
troubles
than advantages. The use case is the implementation of "autosuper" made

by Guido on his essay about new-style classes (the one Grep Chapman is
citing).

The idea there is to use the unbound super objects as private
attributes. For instance, in our example, we could define the
private attribute ``__sup`` in the class ``C`` as the unbound
super object ``super(C)``:

With this definition inside the methods the syntax
``self.__sup.meth(arg)`` can be used
as an alternative to ``super(C, self).meth(arg)``, and the advantage is

that you avoid to repeat the name of the class in the calling
syntax, since that name is hidden in the mangling mechanism of
private names. The creation of the ``__sup`` attributes can be hidden
in a metaclass and made automatic. So, all this seems to work: but
actually this is *not* the case.

Things may wrong in various case, for instance for classmethods,
as in this example::

#<ex1.py>

class B(object):
def __repr__(self):
return '<instance of %s>' % self.__class__.__name__
@classmethod
def meth(cls):
print "B.meth(%s)" % cls

class C(B):
@classmethod
def meth(cls):
print "C.meth(%s)" % cls
cls.__super.meth()

C._C__super = super(C)

class D(C):
pass

D._D__super = super(D)


d=D()

d.meth()

#</ex1.py>

The last line raises an ``AttributeError: 'super' object has no
attribute
'meth'.``

So, using a ``__super`` unbound super object is not a robust solution
(notice that everything would work by substituting
``self.__super.meth()``
with ``super(C,self).meth()``. There are other ways to avoid repeating
the class name, see for instance my cookbook recipe, which will also be
in the printed version.

If it was me, I would just remove the single argument syntax of
``super``,
making it illegal. But this would probably break someone code, so
I don't think it will ever happen. Another solution would be just to
deprecate it. There is no need for this syntax, one can always
circumvent
it. Also, notice that the unbound form of ``super`` does
not play well with pydoc.
The problems is still there in Python 2.4 (see bug report SF729103)
.... s=super(B)
....Traceback (most recent call last):
...
... lots of stuff here
...
File "/usr/lib/python2.4/pydoc.py", line 1290, in docother
chop = maxlen - len(line)
TypeError: unsupported operand type(s) for -: 'type' and 'int'

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
474,001
Messages
2,570,255
Members
46,853
Latest member
GeorgiaSta

Latest Threads

Top