Today i was trying to figure out how __mro__ and super works in python, I found something interesting as well as strange to me, because I got something which is not that i understood after reading __mro__. Here is the code snippets.
Code Snippets 1:
#!/usr/bin/pyhon
class A(object):
def test(self):
return 'A'
class B(A):
def test(self):
return 'B to %s' % super(B, self).test()
class C(A):
def test(self):
return 'C'
class D(B, C):
pass
print D().test()
Output :
B to C
Code snippet 2: When I update my super inside class B:
#!/usr/bin/pyhon
class A(object):
def test(self):
return 'A'
class B(A):
def test(self):
return 'B to %s' % super(C, self).test()
class C(A):
def test(self):
return 'C'
class D(B, C):
pass
print D().test()
Output:
B to A
Then now i got what I expected before. Could someone please explain how mro works with super ?
The MRO for D is [D, B, C, A, object].
super(C, self) ~ A
super(B, self) ~ C
super(MyClass, self) is not about the "base class of MyClass", but about the next class in the MRO list of MyClass.
As stated in the comments, super(…) actually does not return the next class in the MRO, but delegates calls to it.
Related
The Python documentation of super states:
This is useful for accessing inherited methods that have been overridden in a class.
Is there a point in calling super().method() in a subclass that does not override method?
To me there is not, since calling self.method() would be equivalent, that is to say inheritance would look method up in self's superclasses using the same type(self).__mro__ method resolution order (given by the C3 linearization of self's superclass hierarchy) than super.
So to me, super is useful in this situation:
class A:
def f(self):
print("A")
class B:
pass
class C(B, A):
def f(self):
super().f()
print("C")
C().f() # prints A C
but not in this one:
class A:
def f(self):
print("A")
class B:
pass
class C(B, A):
def g(self):
super().f() # should be just self.f()
print("C")
C().g() # prints A C
As noted by #chepner, calling super().method() in a subclass that does not override method is not equivalent to calling self.method(). The difference appears in subclasses of that subclass that override method.
Compare:
class A:
def f(self):
print("A")
class B:
pass
class C(B, A):
def g(self):
super().f() # == super(C, self).f(), so lookup starts after C in type(self).__mro__
print("C")
class D(C):
def f(self):
print("D")
D().g() # prints A C, since D.__mro__ == (D, C, B, A, object)
with:
class A:
def f(self):
print("A")
class B:
pass
class C(B, A):
def g(self):
self.f() # lookup starts at the beginning in type(self).__mro__
print("C")
class D(C):
def f(self):
print("D")
D().g() # prints D C, since D.__mro__ == (D, C, B, A, object)
Sorry, may be this is silly question, but its very confusing to me. Let's suppose we have the following classes:
class A():
def say(self):
print("A")
class B(A):
def say(self):
print("B")
class C(B):
def say(self,*args, **kwargs):
return super(C, self).say(*args, **kwargs)
I am accessing parent method in child, and it prints B, but I want to access method from class A as we are getting access from class B.
I know we can add super in class B, but I don't want to modify class B. so is there any option to get method from A directly in class C?
You can by calling A.say(self) like this:
class A():
def say(self):
print("A")
class B(A):
def say(self):
print("B")
class C(B):
def say(self):
A.say(self)
B.say(self)
print("C")
Then to test it out from a terminal:
>>> a = A()
>>> a.say()
A
>>> b = B()
>>> b.say()
B
>>> c = C()
>>> c.say()
A
B
C
Note: I dropped the args and kwargs because the A and B classes didn't use those arguments. If you wanted to make say take those all the way up though simply call A.say(self, *args, **kwargs) and if A.say returns something you can return it too
Given a parent class 'A'
class A(object):
def __init__(self,a,b):
self.a = a
self.b = b
def methodA():
# do something
What is the difference between making a subclass 'B' among the below options
Option 1
class B(A):
def methodB():
# do something
Option 2
class B(A):
def __init__(self,a,b):
A.__init__(self, a, b)
def methodB():
# do something
class A(object):
def __init__(self,a,b):
self.a = a
self.b = b
class B(A):
def __init__(self,a,b):
A.__init__(self, a, b)
def methodB():
pass
class C(A):
def methodB():
pass
b = B(1,2)
c = C(1,2)
print b.a == c.a # True
print b.b == c.b # True
In both class instantiation, init under class A will be ran only once.
so no, there is nothing significantly different.
class B is not clean IMO and poses no real purpose at all. It will be ran anyways.
If you wish to do something different in class B init, then yes, you can use this code.
class B(A):
def __init__(self,a,b):
A.__init__(self, a+1, b+1)
def methodB():
pass
Are there any side-effects of adding grandparent to the MRO? Purpose is I would like to get grandchildren classes by using grandparent.__subclasses__()
class A(object):
def work(self):
print 'A'
class B(A):
def work(self):
print 'B'
super(B, self).work()
class C(B):
def work(self):
print 'C'
super(C, self).work()
class D(B, A):
def work(self):
print 'D'
super(D, self).work()
>>> C().work()
C
B
A
>>> D().work()
D
B
A
>>> A.__subclasses__()
[<class 'test.B'>, <class 'test.D'>]
We have come up a recursive function to work out the subclasses
def get_all_subclasses(cls):
all_subclasses = []
for subclass in cls.__subclasses__():
all_subclasses.append(subclass)
all_subclasses.extend(get_all_subclasses(subclass))
return all_subclasses
I was wandering if you have any suggestions on how I should perform the following task in python:
Suppose I have the following classes:
class A(object):
self._classes = []
def magic(self):
c.foo() for c in self._classes
class B(object):
def foo():'''some cool stuff here'''
class C(B):
def foo():'''very cool stuff'''
class D(B):
def foo():'''very cool stuff'''
What I want to do is when class A is instantiated all classes of type B - (C and D) will be insantiated in self._classes, meaning _classes is [C(),D()].
The general motivation for this, is that I want the user to easily add classes without the need to know about class that uses them. Any help will be appricated.
Voila (thanks to this answer for all_subclasses()):
# recursively get all subclasses of a given class
def all_subclasses(cls):
return cls.__subclasses__() + [g for s in cls.__subclasses__()
for g in all_subclasses(s)]
class B(object):
def foo(self): print '''some cool stuff here in B'''
class C(B):
def foo(self): print '''very cool stuff in C'''
class D(B):
def foo(self): print '''very cool stuff in D'''
class E(D):
def foo(self): print '''very cool stuff in E'''
class A(object):
def __init__(self):
self._classes = [cls() for cls in all_subclasses(B)]
def magic(self):
for c in self._classes: c.foo()
# usage:
A().magic()
Output:
very cool stuff in C
very cool stuff in D
very cool stuff in E
If you know the module in question for example modulex, you can use dir(modulex) to list all the names in the module and then for each name x you can use modulex.__dict__.get(x) to get the actual object.
Then just check if it is of type of B.
In python you can store objects like other methods in list , so first note that you need to define other class then store them in a list , also you need to using self as your foo functions argument! if you haven't subclasses you can use this :
class B(object):
def foo(self):
print 'B'
class C(B):
def foo(self):
print 'C'
class D(B):
def foo(self):
print 'D'
class A(object):
def __init__(self):
self._classes = [B(),C(),D()]
def magic(self):
for c in self._classes:
c.foo()
A().magic()
resoult:
B
C
D