5

Someone had this exact same problem on this site, but the answer didn't relate to the part I have trouble with.
Inheritance - Method Calls

Consider the following class definitions.

class C1(object):
    def f(self):
        return 2*self.g()

    def g(self):
        return 2

class C2(C1):
    def f(self):
        return 3*self.g()


class C3(C1):
    def g(self):
        return 5

class C4(C3):
    def f(self):
        return 7*self.g()

obj1 = C1()
obj2 = C2()
obj3 = C3()
obj4 = C4()

For this problem you are to consider which methods are called when the f method is called. So for example, when obj1.f() is called, the f method of C1 is called which calls the g method of C1. This could be represented as a 'calling list' of the form

['C1.f', 'C1.g'] 

Write three assignment statements that, respectively, assigns the 'calling list' for obj2.f() to the variable obj2_calls, assigns the 'calling list' for obj3.f() to the variable obj3_calls and assigns the 'calling list' for obj4.f() to the variable obj4_calls.

I have no problem understanding the first assignment, it is obj2_calls = ['C2.f', 'C1.g']
but I am wracking my brain trying to figure out the next one. I thought since there is no C3.f that the list would be ['C1.f'] but unfortunately it's not.

Just to clear up, this IS homework

timss
  • 9,982
  • 4
  • 34
  • 56
Mark D
  • 75
  • 1
  • 7
  • 3
    Add some `print` statements to each function to figure out what's really going on. – Mark Ransom Apr 22 '13 at 01:19
  • if you type in C3.f you'll see c3.f which means its a part of the class C3 – Greg Apr 22 '13 at 01:25
  • Hi guys very helpful, using print I have the correct answer. But I used more common sense to get that than understanding of the code. I'd still like to understand why the answer was obj3_calls = ['C1.f', 'C3.g'] . I don't get why 'c3.g' is called after 'c1.f' – Mark D Apr 22 '13 at 01:31
  • Just to be certain I'm understanding the assignment correctly the proper answer is `['C1.f', 'C3.g']`, correct? – mgilson Apr 22 '13 at 01:33
  • Yep, that's what I got – Mark D Apr 22 '13 at 01:33

2 Answers2

3

This has to do with the method resolution order (MRO) of your class. (see here for some useful info)

As you stated correctly, there is no C3.f function, so python looks up the f method on the first base-class in the MRO that has f defined. In this case, that is (C1). Now, that method (C1.f) calls self.g(). In this case self is an instance of C3, so of course, self.g calls C3.g since that is the highest g function in the MRO. If you wanted to guarantee that you get C1.g, you'd need to do it explicitly:

class C1(object):
    def f(self):
        return 2*C1.g(self)
    def g(self):
        return 5

which also makes a nice lead-in to talking about double-underscore name mangling. Since that is a separate topic though, maybe it's best to only leave a link to some useful documentation.

Community
  • 1
  • 1
mgilson
  • 300,191
  • 65
  • 633
  • 696
1

obj3_calls is ['C1.f', 'C3.g']. As you point out, there is no C3.f in that class, but this method is inherited from C1. This one in turn calls self.g, and since C3.g is defined, it overrides the method that is inherited from C1.

A. Rodas
  • 20,171
  • 8
  • 62
  • 72