user4180854
user4180854

Reputation:

can you explain why changing a class' function attribute has the following effect?

consider the code below:

class A:
    def __init__(self, data):
        self.data = data    

    def f(self):
        print('from A', self.data)

a = A(20)

def fnew(self):
    print('new from A', self.data)

A.f = fnew
print(a.f.__func__ is A.f)

the output is True, but i expected it to be false. here is why: from what i understand, each time an object O is created from class C it inherits all of the function attributes of C in the form of objects with type 'method'. each such method object has as attributes O and the corresponding function. in this case a.f has attributes the object a and the function with name 'f'. but when A.f = fnew is executed i am only changing the attributes of the class object A, not the attributes of the method object a.f, so how come a.f.func is changed at the end?

Upvotes: 1

Views: 33

Answers (1)

poke
poke

Reputation: 388153

When you do a.f, Python will look up the member f from the instance a. When it cannot find a member with that name, it will look up the type hierarchy to find it. So in this case, it will look at the instance’s type, which is A. That’s why accessing a.f will use the function that is stored in A.f.

If you were to overwrite f in the instance, this would not happen:

>>> A.f = fnew
>>> a.f
<bound method fnew of <__main__.A object at 0x00000083E819B1D0>>
>>> a.f = 'foo'
>>> a.f
'foo

Note that when creating an instance, members from the type will not be copied down to the instance. If that were to happen, that would make creating instances of objects very expensive. Instead, the type system will just look up members from the type when the instance does not have the member on its own.


As noted by timgeb in the comments, in Python 2, your final check a.f.__func__ is A.f will return False. This is because there, A.f will return an unbound function which is not the same as the original function. But that’s just a minor detail that will not change anything about what I wrote above: The method will still be looked up from the type.

Upvotes: 2

Related Questions