When do you need to pass arguments to python super()?

走远了吗. 提交于 2021-01-28 02:03:09

问题


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 staticmethods (since the first argument isn't actually the class), though staticmethods 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 like dict 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!