7

I read somewhere that "if python can't find instance variable it will try to return value of the class variable having the same name"

eg

class Sample:
    pi = 10

Now

x1 = Sample()
x2 = Sample()

x1.pi         # returns 10
x2.pi         # returns 10

x1.pi = 20    # change the value of class variable
x1.pi         # return 20 (OK)
x2.pi         # still returns 10 :(
Sample.pi     # returns 10 :(

What is happening??

Emmanuel Mtali
  • 4,383
  • 3
  • 27
  • 53

1 Answers1

4

As soon as you assign to a name on an instance, it gains an instance attribute that shadows the class attribute.

The only way you can assign to the class attribute is to assign to an attribute of the class, not an attribute of the instance, e.g. if you have an instance, you need to do:

x1.__class__.pi = 20
# If you're on Py3, or on Py2 and x1 is an instance of a new-style class,
# using type(x1) is slightly "nicer" than manually accessing dunder special
# variables, but unfortunately, it doesn't work on old-style class instances
# For new-style class instances though, the following is equivalent:
type(x1).pi = 20

if you want all instances of the same type as x1 to show the change. This gets the class itself from __class__ (or via type function), then assigns to it.

If you accidentally created an instance attribute and want to expose the class attribute again, you can do:

del x1.pi

which will succeed if an instance attribute named pi exists, and raise AttributeError if it does not (it will not delete the class attribute if it exists, you'd need to do del x1.__class__.pi/del type(x1).pi to do that).

ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
  • Note: This answer assumes the class attribute is really named `pi`; your example names it `x`, then accesses `pi`. – ShadowRanger Dec 02 '16 at 20:09
  • If you can change the value of a class variable for a specific instance, what's the point of defining it as a class variable instead of an instance variable? – Abhimanyu Pallavi Sudhir Jan 24 '23 at 10:31
  • @AbhimanyuPallaviSudhir: If the intent is that every instance gets its own value, then yeah, don't use a class attribute. The reason to use class attributeis for 1) Shared "constants", and 2) Shared state between instances (usually state that constructs an instance, e.g. to assign unique IDs to each instance or the like). Name-shadowing a class attribute is also a lazy person's "default attribute" (until reassigned, the instance sees the class attribute), but it's not recommended (CPython has optimizations that only work if all instance attributes are created at once, in the order). – ShadowRanger Jan 24 '23 at 14:28