问题
A use case of the super()
builtin in python is to call an overridden method. Here is a simple example of using super()
to call Parent
class's echo
function:
class Parent():
def echo(self):
print("in Parent")
class Child(Parent):
def echo(self):
super().echo()
print("in Child")
I've seen code that passes 2 parameters to super()
. In that case, the signature looks somehing like super(subClass, instance)
where subClass
is the sub class calling super()
from, and instance
is the instance the call being made from, ie self
. So in the above example, the super()
line would become:
super(Child, self).echo()
Looking at python3 docs, these 2 use cases are the same when calling from inside of a class.
Is calling super()
with 2 parameters completely deprecated as of python3? If this is only deprecated for calling overridden functions, can you show an example why they're needed for other cases?
I'm also interested to know why python needed those 2 arguments? Are they injected/evaluated when making super()
calls in python3, or they're just not needed in that case?
回答1:
If you don't pass the arguments, Python 3 makes an effort to provide them for you. It's a little kludgy, but it usually works. Essentially, it just assumes the first parameter to your method is self
(the second argument to super
), and when the class definition completes, it provides a virtual closure scope for any function that refers to super
or __class__
that defines __class__
as the class you just defined, so no-arg super()
can check the stack frame to find __class__
as the first argument.
This usually works, but there are cases where it doesn't:
In
staticmethod
s (since the first argument isn't actually the class), thoughstaticmethod
s aren't really supposed to participate in the inheritance hierarchy the same way, so that's not exactly unexpected.In functions that take
*args
as the first argument (which was the only safe way to implement any method that accepted arbitrary keyword arguments likedict
subclasses prior to 3.8, when they introduced positional-only arguments).If the
super
call is in a nested scope, which can be implicit, e.g. a generator expression, or comprehension of any kind (list
,set
,dict
), since the nested scope isn't directly attached to the class, so it doesn't get the__class__
defining magic that methods attached to the class itself get.
There are also rare cases where you might want to explicitly bypass a particular class for resolving the parent method, in which case you'd need to explicitly pass a different class from later in the MRO than the one it would pull by default. This is deep and terrible magic, so I don't recommend it, but I think I've had cause to do it once.
All of those are relatively rare cases, so most of the time, for code purely targeting Python 3, you're fine using no-arg super
, and only falling back to explicitly passing arguments when you can't use it for whatever reason. No-arg super
is cleaner, faster, and during live development can be more correct (if you replace MyClass
, instances of the old version of the class will have the old version cached and no-arg super
will continue to work, where looking it up manually in your globals would find the new version of the class and explode), so use it whenever you can.
回答2:
In Python 3, super()
with zero arguments is already the shortcut for super(__class__, self)
. See PEP3135 for complete explanation.
This is not the case for Python 2, so I guess that most code examples you found were actually written for Python 2 (or Python2+3 compatible)
来源:https://stackoverflow.com/questions/59538746/when-do-you-need-to-pass-arguments-to-python-super