donatello donatello - 7 months ago 8
Python Question

How does attribute resolution work in Python?

Consider the following code:

class A(object):
def do(self):
print self.z

class B(A):
def __init__(self, y):
self.z = y

b = B(3)
b.do()


Why does this work? When executing
b = B(3)
, attribute z is set. When
b.do()
is called, Python's MRO finds the
do
function in class A. But why is it able to access an attribute defined in a subclass?

Is there a use case for this functionality? I would love an example.

Answer

It works in a pretty simple way: when a statement is executed that sets an attribute, it is set. When a statement is executed that reads an attribute, it is read. When you write code that reads an attribute, Python does not try to guess whether the attribute will exist when that code is executed; it just waits until the code actually is executed, and if at that time the attribute doesn't exist, then you'll get an exception.

By default, you can always set any attribute on an instance of a user-defined class; classes don't normally define lists of "allowed" attributes that could be set (although you can make that happen too), they just actually set attributes. Of course, you can only read attributes that exist, but again, what matters is whether they exist when you actually try to read them. So it doesn't matter if an attribute exists when you define a function that tries to read it; it only matters when (or if) you actually call that function.

In your example, it doesn't matter that there are two classes, because there is only one instance. Since you only create one instance and call methods on one instance, the self in both methods is the same object. First __init__ is run and it sets the attribute on self. Then do is run and it reads the attribute from the same self. That's all there is to it. It doesn't matter where the attribute is set; once it is set on the instance, it can be accessed from anywhere: code in a superclass, subclass, other class, or not in any class.