-2

As per documentation: "Generally speaking, instance variables are for data unique to each instance and class variables are for attributes and methods shared by all instances of the class"

>>> class Dog:
...   kind='canine'
...   
...   def __init__(self, name):
...     self.name = name
... 
>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> d.name
'Fido'
>>> e.name
'Buddy'
>>> d.kind
'canine'
>>> e.kind
'canine'
>>> d.kind='cat' # changed supposedly shared variable to cat
>>> d.kind # OK here
'cat'
>>> e.kind # Not expected output (should be cat as per documentation)
'canine'

Am I missing something?

Tarik
  • 10,810
  • 2
  • 26
  • 40

3 Answers3

4

Doing d.kind='cat' creates a new instance attribute named kind and sets it to 'cat'. Moreover, this overshadows the class attribute.

In order to change the class attribute, you need to set it on the class itself and not an instance:

Dog.kind='cat'
1

You are setting an instance attribute, masking the class attribute:

d.kind = 'cat'

If you set it on the class instead it'll be visible on all instances:

Dog.kind = 'cat'

You cannot set class attributes by assigning to the name on instances. If you could, you would never be able to set instance attributes.

Use the vars() function to see the difference:

>>> class Dog:
...     kind = 'canine'
...     def __init__(self, name):
...         self.name = name
... 
>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> vars(d)
{'name': 'Fido'}
>>> 'kind' in vars(d)
False
>>> vars(Dog)
mappingproxy({'__module__': '__main__', '__dict__': <attribute '__dict__' of 'Dog' objects>, 'kind': 'canine', '__weakref__': <attribute '__weakref__' of 'Dog' objects>, '__doc__': None, '__init__': <function Dog.__init__ at 0x10084bbf8>})
>>> 'kind' in vars(Dog)
True
>>> d.kind
'canine'
>>> d.kind = 'cat'
>>> d.kind
'cat'
>>> vars(d)
{'name': 'Fido', 'kind': 'cat'}
>>> Dog.kind
'canine'

The vars() function reveals the attributes available on both the class and one of the instances. By assigning to d.kind, the new attribute appears in the dictionary of names for that instance, and from there on out all lookups on that instance will return that attribute and not fall through to the class.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
1

If you do instance.attr = "blah", you always set an instance attribute, even if there is already a class attribute of the same name. By doing d.kind = "cat" you created an instance attributed called kind which shadows the class variable called kind.

BrenBarn
  • 242,874
  • 37
  • 412
  • 384