This works as expected:
>>> class Foo(object):
... @classmethod
... def hello(cls):
... print 'hello, foo'
...
>>> class Bar(Foo):
... @classmethod
... def hello(cls):
... print 'hello, bar'
... super(Bar, cls).hello()
...
>>> b = Bar()
>>> b.hello()
hello, bar
hello, foo
I can also call the base class explicitly:
>>> class Bar(Foo):
... @classmethod
... def hello(cls):
... print 'hello, bar'
... Foo.hello()
...
>>> b = Bar()
>>> b.hello()
hello, bar
hello, foo
I was wondering why I can't omit the first argument to super
, like this:
>>> class Bar(Foo):
... @classmethod
... def hello(cls):
... print 'hello, bar'
... super(Bar).hello()
...
>>> b = Bar()
>>> b.hello()
hello, bar
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in hello
AttributeError: 'super' object has no attribute 'hello'
when the result of the super
call without a second argument seems to be a class type inside a super type:
>>> class Bar(Foo):
... @classmethod
... def hello(cls):
... print Foo, type(Foo)
... print super(Bar), type(super(Bar))
... print cls, type(cls)
...
>>> b = Bar()
>>> b.hello()
<class '__main__.Foo'> <type 'type'>
<super: <class 'Bar'>, NULL> <type 'super'>
<class '__main__.Bar'> <type 'type'>
I guess I'm just wondering about the design here. Why would I need to pass the class object into the super call to get a reference to the base class type Foo
? For a normal method, it makes sense to pass self
to the function, since it needs to bind the base class type to an actual instance of the class. But a classmethod doesn't need a specific instance of the class.
EDIT:
I get the same error in Python 3.2 as I do above in 2.7 for super(Bar).hello()
. However, I can simply do super().hello()
and that works fine.
But somehow, even if you call super () without the props argument, you’ll still be able to access this.props in the render and other methods. (If you don’t believe me, try it yourself!) How does that work? It turns out that React also assigns props on the instance right after calling your constructor:
In JavaScript, super refers to the parent class constructor. (In our example, it points to the React.Component implementation.) Importantly, you can’t use this in a constructor until after you’ve called the parent constructor.
But this.props would still be undefined between the super call and the end of your constructor: It can be even more challenging to debug if this happens in some method that’s called from the constructor. And that’s why I recommend always passing down super (props), even though it isn’t strictly necessary:
So React was intentionally unopinionated about whether calling super () is required — even though ES6 classes are. So does this mean you can just write super () instead of super (props)? Probably not because it’s still confusing. Sure, React would later assign this.props after your constructor has run.
super()
returns a descriptor, and needs two items:
For the two argument (and implicit zero-argument *) case the second argument is used to bind to, but if you do not pass in a second argument, super()
cannot invoke the descriptor protocol to bind the returned functions, classmethods, properties or other descriptors. classmethods
are still descriptors and are bound; the bind to a class and not an instance, but super()
does not know how the descriptor will use the context to which you bind.
super()
should not and cannot know that you are looking up a class method instead of a regular method; class methods only differ from regular methods because their .__get__()
method acts differently.
Why are class methods bound? Because when you subclass Foo
but do not override .hello()
, calling Bar.hello()
invokes the Foo.__dict__['hello']
function, binds it to Bar
and your first argument to hello(cls)
will be that subclass, not Foo
.
Without a second argument, super()
returns an unbound object that can manually be bound later on. You can do the binding yourself using the .__get__()
method provided by the super()
instance:
class Bar(Foo):
@classmethod
def hello(cls):
print 'hello, bar'
super(Bar).__get__(cls, None).hello()
super().__get__()
on an instance without a context effectively returns a new super()
instance with the context set. On an instance with a context .__get__()
just returns self
; it is already bound.
* In Python 3, calling super()
without arguments from inside a bound method will use the calling frame to discover, implicitly, what the type and bound object are, so you no longer have to explicitly pass in the type and object arguments in that case. Python 3 actually adds a implicit __class__
closure variable to methods for this purpose. See PEP 3135 and Why is Python 3.x's super() magic?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With