Reputation: 830
I need help in writing code that does what I think it should do.
Here's the code:
class Food:
kind = 'fruit'
def __init__(self, name):
self.name = name
a = Food('tomato')
b = Food('cabbage')
print 'a ->', a.kind
print 'b ->', b.kind
print 'change a\'s kind'
a.kind = 'veg'
print 'a ->', a.kind
print 'b ->',b.kind
print 'change kind in the class'
Food.kind = 'meat'
print 'a ->', a.kind
print 'b ->', b.kind
The output I got was this:
a -> fruit
b -> fruit
change a's kind
a -> veg
b -> fruit
change kind in the class
a -> veg
b -> meat
It's the last result that puzzles me. If I've declared 'kind' correctly as a class attribute then surely when I change it in the class with 'Food.kind = ' it should change it for both instance. Actually I expected it to change when I gave it the new value via one of the instances also, but it only changed it in one. What am I missing here?
Upvotes: 0
Views: 77
Reputation: 250881
Attribute lookup starts from instance's dictionary, so changing kind
in class won't affect* a
's kind
attribute. But other instances of the class that still don't have that attribute will still look for it in class dictionary or further up in in the class tree if not found in Food
.
>>> a.kind = 'veg'
>>> a.__dict__
{'kind': 'veg', 'name': 'tomato'}
>>> b.__dict__
{'name': 'cabbage'}
Since, there are no base classes here attribute lookup will stop immediately after Food
for non-existent attributes resulting in AttributeError
.
>>> a.foo
Traceback (most recent call last):
File "<pyshell#6>", line 1, in <module>
a.foo
AttributeError: Food instance has no attribute 'foo'
Note that in new-style classes special methods are always looked up in class not instances. But since you're using an old-style class(removed in Python 3) that won't be the case. But it is recommended to always use new-style classes(i.e inherit from object
in Python 2).
You should read: New-style and classic classes.
* Mutable class attributes(lists, dict etc) are one exception here, doing in-place operations on them from either instance or class will be reflected everywhere in class and other instances(unless an instance defined a new attribute by the same name):
class Food:
kind = []
def __init__(self, name):
self.name = name
a = Food('tomato')
b = Food('cabbage')
b.kind = []
a.kind.append(10)
Food.kind.append(20)
print a.kind #[10, 20]
print b.kind #[] b.kind points to a different object due to the assignment above
print Food.kind #[10, 20]
Upvotes: 1
Reputation: 40683
You may be aware that in C++/Java referencing a static member via an instance is frowned upon. Instead you are encouraged to refer to static members via a class reference In Java, for instance:
theThing.value = 1; // bad
Thing.value = 1; // good
In Python, when reading a field on an instance, Python will first look at the instance's fields. If no instance field is found then the instance's class's fields will be inspected.
When writing to a field, the field written is always the object that was referenced -- be that an instance or a class. For instance:
theThing.value = 1 # creates an instance field if one does not exist
Thing.value = 1 # creates a class field if one does not exist
Thus, when reading the value of kind
: a.kind
will always read the instance field (unless the field is deleted); and b.kind
will always read the class field (unless an instance field is created).
Upvotes: 0