Is __init__ a class method?

若如初见. 提交于 2019-12-05 02:56:44

super() in the face of multiple inheritance, especially on methods that are present on object can get a bit tricky. The general rule is that if you use super, then every class in the hierarchy should use super. A good way to handle this for __init__ is to make every method take **kwargs, and always use keyword arguments everywhere. By the time the call to object.__init__ occurs, all arguments should have been popped out!

class Base1(object):
    def __init__(self, a, **kwargs):
        print "In Base 1", a
        super(Base1, self).__init__()

class Base2(object):
    def __init__(self, **kwargs):
        print "In Base 2"
        super(Base2, self).__init__()

class Child(Base1, Base2):
    def __init__(self, **kwargs):
        super(Child, self).__init__(a="Something for Base1")

See the linked article for way more explanation of how this works and how to make it work for you!

Edit: At the risk of answering two questions, "Why use super at all?"

We have super() for many of the same reasons we have classes and inheritance, as a tool for modularizing and abstracting our code. When operating on an instance of a class, you don't need to know all of the gritty details of how that class was implemented, you only need to know about its methods and attributes, and how you're meant to use that public interface for the class. In particular, you can be confident that changes in the implementation of a class can't cause you problems as a user of its instances.

The same argument holds when deriving new types from base classes. You don't want or need to worry about how those base classes were implemented. Here's a concrete example of how not using super might go wrong. suppose you've got:

class Foo(object):
     def frob(self):
         print "frobbign as a foo"
class Bar(object):
     def frob(self):
         print "frobbign as a bar"

and you make a subclass:

class FooBar(Foo, Bar):
    def frob(self):
        Foo.frob(self)
        Bar.frob(self)

Everything's fine, but then you realize that when you get down to it, Foo really is a kind of Bar, so you change it

 class Foo(Bar):
     def frob(self):
         print "frobbign as a foo"
         Bar.frob(self)

Which is all fine, except that in your derived class, FooBar.frob() calls Bar.frob() twice.

This is the exact problem super() solves, it protects you from calling superclass implementations more than once (when used as directed...)

As for your first question, __init__ is neither a staticmethod nor a classmethod; it is an ordinary instance method. (That is, it receives the instance as its first argument.)

As for your second question, if you want to explicitly call multiple base class implementations, then doing it explicitly as you did is indeed the only way. However, you seem to be misunderstanding how super works. When you call super, it does not "know" if you have already called it. Both of your calls to super(Child, self).__init__ call the Base1 implementation, because that is the "nearest parent" (the most immediate superclass of Child).

You would use super if you want to call just this immediate superclass implementation. You would do this if that superclass was also set up to call its superclass, and so on. The way to use super is to have each class call only the next implementation "up" in the class hierarchy, so that the sequence of super calls overall calls everything that needs to be called, in the right order. This type of setup is often called "cooperative inheritance", and you can find various articles about it online, including here and here.

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