The correct way to use super (transfer argument)

So, I followed the Python Super was considered harmful and went to check their examples.

However, Example 1-3 , which should show the correct way to call super when processing __init__ methods that expect different arguments, alignment does not work.

This is what I get:

 ~ $ python example1-3.py MRO: ['E', 'C', 'A', 'D', 'B', 'object'] E arg= 10 C arg= 10 A D arg= 10 B Traceback (most recent call last): File "Download/example1-3.py", line 27, in <module> E(arg=10) File "Download/example1-3.py", line 24, in __init__ super(E, self).__init__(arg, *args, **kwargs) File "Download/example1-3.py", line 14, in __init__ super(C, self).__init__(arg, *args, **kwargs) File "Download/example1-3.py", line 4, in __init__ super(A, self).__init__(*args, **kwargs) File "Download/example1-3.py", line 19, in __init__ super(D, self).__init__(arg, *args, **kwargs) File "Download/example1-3.py", line 9, in __init__ super(B, self).__init__(*args, **kwargs) TypeError: object.__init__() takes no parameters 

It seems that object itself violates one of the best practices mentioned in the document, that is, methods that use super should accept *args and **kwargs .

Now, obviously, Mr. Knight was expecting his examples to work, so is that what has been changed in recent versions of Python? I checked 2.6 and 2.7 and it does not work on both.

So what is the correct way to solve this problem?

+50
python
Jan 23 2018-12-12T00:
source share
3 answers

Sometimes two classes can have common parameter names. In this case, you cannot push key-value pairs from **kwargs or remove them from *args . Instead, you can define a Base class, which, unlike object , absorbs / ignores arguments:

 class Base(object): def __init__(self, *args, **kwargs): pass class A(Base): def __init__(self, *args, **kwargs): print "A" super(A, self).__init__(*args, **kwargs) class B(Base): def __init__(self, *args, **kwargs): print "B" super(B, self).__init__(*args, **kwargs) class C(A): def __init__(self, arg, *args, **kwargs): print "C","arg=",arg super(C, self).__init__(arg, *args, **kwargs) class D(B): def __init__(self, arg, *args, **kwargs): print "D", "arg=",arg super(D, self).__init__(arg, *args, **kwargs) class E(C,D): def __init__(self, arg, *args, **kwargs): print "E", "arg=",arg super(E, self).__init__(arg, *args, **kwargs) print "MRO:", [x.__name__ for x in E.__mro__] E(10) 

gives

 MRO: ['E', 'C', 'A', 'D', 'B', 'Base', 'object'] E arg= 10 C arg= 10 A D arg= 10 B 

Note that for this, Base must be the penultimate class in the MRO.

+52
Jan 23 2018-12-12T00:
source share

If you have a lot of inheritance (in this case here), I suggest you pass all the parameters using **kwargs , and then pop them immediately after using them (unless you need them in the upper classes).

 class First(object): def __init__(self, *args, **kwargs): self.first_arg = kwargs.pop('first_arg') super(First, self).__init__(*args, **kwargs) class Second(First): def __init__(self, *args, **kwargs): self.second_arg = kwargs.pop('second_arg') super(Second, self).__init__(*args, **kwargs) class Third(Second): def __init__(self, *args, **kwargs): self.third_arg = kwargs.pop('third_arg') super(Third, self).__init__(*args, **kwargs) 

This is the easiest way to solve such problems.

 third = Third(first_arg=1, second_arg=2, third_arg=3) 
+13
Jan 23 2018-12-12T00:
source share

As explained in Python, super () is considered super , one way is for the class to feed on the arguments it needs and pass the rest. That way, when the call chain reaches object , all arguments have been eaten, and object.__init__ will be called without arguments (as expected). Therefore, your code should look like this:

 class A(object): def __init__(self, *args, **kwargs): print "A" super(A, self).__init__(*args, **kwargs) class B(object): def __init__(self, *args, **kwargs): print "B" super(B, self).__init__(*args, **kwargs) class C(A): def __init__(self, arg, *args, **kwargs): print "C","arg=",arg super(C, self).__init__(*args, **kwargs) class D(B): def __init__(self, arg, *args, **kwargs): print "D", "arg=",arg super(D, self).__init__(*args, **kwargs) class E(C,D): def __init__(self, arg, *args, **kwargs): print "E", "arg=",arg super(E, self).__init__(*args, **kwargs) print "MRO:", [x.__name__ for x in E.__mro__] E(10, 20, 30) 
+5
Jan 23 2018-12-12T00:
source share



All Articles