I want to be able to recycle a method from a parent class that uses a second method in that parent class. However the second method is overridden in the child class. I want the recycled parent method to use the new overridden second method when it is called from the child class. An example of how I want it to work will hopefully make this clearer:
class Parent:
def method1(self, num):
return num**2
def method2(self, list_size):
return [self.method1(i) for i in range(list_size)] #List of squares
class Child(Parent):
def method1(self, num): #Overrides corresponding parent method
return num**3
def method2(self, list_size):
return super().method2(list_size) #Returns a list of cubes using child's method 1.
Is this possible in python3? Or will calling the parent's method 2 also use the parent's method 1? I'm hoping to reuse large parts of a parent class as the child class differs in only a few ways. The methods nesting like that in the parent class make it a lot more general.
Thanks!
EDIT: I forgot to test it with simple code! It does work like I wanted if anyone was wondering!
Short answer: yes. Just tried a slightly modified version of your code with prints.
class Parent:
def method1(self):
print("Parent method1")
def method2(self):
print("Parent method2")
self.method1()
class Child(Parent):
def method1(self):
print("Child method1")
def method2(self):
print("Child method2")
super().method2()
c = Child()
c.method2()
This is the output:
Child method2
Parent method2
Child method1
As you can see, the method1 used is the child one.
Yes, this works the way you want it to.
You can easily test this yourself. Unless you pass in nothing but 0s and 1s, it should be pretty obvious whether they're getting squared or cubed.
And, in cases where it's less obvious, just add a debugger breakpoint to Child.method1
and Parent.method1
and see which one gets hit. Or add print(f'Child1.method({self}, {num})')
to the method and see if it gets printed out.
If you're coming from another language with C++ OO semantics instead of Smalltalk OO semantics, it may help to think of it this way: Every method is always virtual.
__init__
calls virtual? Yes. __init__
? Yes. super
call? Yes. @classmethod
? Yes. The only exceptions are when you go out of your way to explicitly tell Python not to make a virtual function call:
super()
use the implementation from the next class in the MRO chain, because that's the whole point of super
. Parent.method1(self, num)
, you obviously get Parent.method1
, because that's the whole point of bound methods. If you're not trying to understand Python in terms of Java, and just want a deeper understanding of Python on its own terms, what you need to understand is what happens when you call self.method1(i)
.
First, self.method1
doesn't know or care that you're going to call it. It's an attribute lookup, just like, say, self.name
would be.
The way Python resolves this is described in the Descriptor HOWTO , but an oversimplified version looks like this:
self.__dict__
have anything named method1
? No. type(self).__dict__
have anything named method1
? Yes.
type(self).__dict__['method1'].__get__(self)
. If that second lookup failed, Python would loop over type(self).mro()
and do the same test for each one. But here, that doesn't come up. type(self)
is always going to be Child
for an instance of Child
, and Child.__dict__['method1']
exists, so it binds Child.method
to self
, and the result is what self.method1
means.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.