简体   繁体   中英

Python: Call child method inside parent method from child method

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.

  • Are __init__ calls virtual? Yes.
  • What if you call a method during __init__ ? Yes.
  • What if you call a method inside a super call? Yes.
  • What about a @classmethod ? Yes.
  • What if…? Yes.

The only exceptions are when you go out of your way to explicitly tell Python not to make a virtual function call:

  • Calls on super() use the implementation from the next class in the MRO chain, because that's the whole point of super .
  • If you grab a parent's bound method and call that, like Parent.method1(self, num) , you obviously get Parent.method1 , because that's the whole point of bound methods.
  • If you go digging into the class dicts and run the descriptor protocol manually, you obviously get whatever you do manually.

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:

  • Does self.__dict__ have anything named method1 ? No.
  • Does type(self).__dict__ have anything named method1 ? Yes.
    • Return 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM