'Create alias in derived class for method in base class with the same name in Python
I'm new to Python. Let's say that I have a Parent base class and a derived Child class that inherits from Parent:
class Parent():
def foo(self):
print('foo in Parent')
def bar(self):
print('bar in Parent')
class Child(Parent):
pass
print(Child.__dict__)
print(Parent.__dict__)
The output is something like this:
# Child.__dict__
{'__module__': '__main__', '__doc__': None}
# Parent.__dict__
{'__module__': '__main__', 'foo': <function Parent.foo at 0x104f76680>, 'bar': <function Parent.bar at 0x104f76710>, '__dict__': <attribute '__dict__' of 'Parent' objects>, '__weakref__': <attribute '__weakref__' of 'Parent' objects>, '__doc__': None}
My understanding is that foo and bar in Parent class are instance methods so they don't appear in Child.__dict__. This is how it works in order for Child class to be able to override those methods, please correct me if I'm wrong.
If i change Child class a little bit, by creating an alias named foo and assign it to method foo in Parent class:
class Child(Parent):
foo = Parent.foo
I expect this to not work because Child already inherits all the members that Parent so it doesn't make sense that I can create another foo when one already exists.
But it works, if I create an object of type Child and call foo from it, it will print foo in Parent. And contents of Child.__dict__ and Parent.__dict__ now are:
Child.__dict__
{'__module__': '__main__', 'foo': <function Parent.foo at 0x1010ee680>, '__doc__': None}
Parent.__dict__
{'__module__': '__main__', 'foo': <function Parent.foo at 0x1010ee680>, 'bar': <function Parent.bar at 0x1010ee710>, '__dict__': <attribute '__dict__' of 'Parent' objects>, '__weakref__': <attribute '__weakref__' of 'Parent' objects>, '__doc__': None}
With foo method now in Child.__dict__ at the same address of 0x1010ee680.
Can someone walk me through what's going on here and is this something that one should do/avoid? Thank you!
Solution 1:[1]
Let's walk through this:
class Parent():
def foo(self):
print('foo in Parent')
def bar(self):
print('bar in Parent')
class Child(Parent):
pass
x = Parent()
x.foo()
y = Child()
y.foo()
When you say x.foo, Python first searches for a foo attribute in x's own instance dict. It won't find any. Then, Python will search for a foo attribute in x's class' dict, and as you already discovered, there is in indeed a foo in Parent.__dict__. Python will then construct a bound method whose __func__ is Parent.foo. (Try method = x.foo and then print(method.__func__) or maybe method(). You will find that you also want to try method.__func__(x).)
Now when you say y.foo, again the interpreter will find no foo attribute in y, and then it will go on to search for an attribute in y's class. This time, there will be no attribute foo in Child, and then Python will look for the next class in Child's method resolution order (or MRO; try print(Child.__mro__)). The next class is just Child's parent class, which is Parent, and as we know, Python will find a foo attribute in Parent. Now you can try y.foo.__func__ to see that it says function Parent.foo; this is Parent's implementation of foo.
If you had that foo = Parent.foo line inside Child's body, not much would change: the interpreter wouldn't have to walk down Child's MRO chain to find foo (i.e. foo would be found right inside Child's dict), but anyway the actual function object found would be the same: that's just Parent.foo again. (Try Child.foo is Parent.foo. This will be true with or without the foo = Parent.foo line.)
This is how it works in order for Child class to be able to override those methods, please correct me if I'm wrong.
Yes, that's right. If instead of foo = Parent.foo, you had actually defined another function named foo in Child's body, then the attribute named foo inside Child's dict would be a different object from Parent.foo. This way, y.foo would again have no need to walk down the MRO all the way to Parent, because it would find a foo attribute right in Child, but this time this attribute would be Child's own implementation of the foo method.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
