Python class variables offer a key tool for building libraries with DSL type syntax, as well as data shared between all instances of the class. This page explains how Python class variables work and gives some examples of usage.
- Class & Instance Variables
- Instances vs the class object
- Instance Variables
- Class Variables
- Using Class and Instance Variables
Class & Instance Variables
Instances vs the class object
In object oriented programming there is the concept of a class, and the definition of that class is the ‘blueprint’ for objects of that class. The class definition is used to create objects which are instances of the class. In Python, for each class, there is an additional object for the class itself. This object for the class itself, is an object of the class ‘type’. So if there is a class ‘Foo’ with two instanced objects ‘a’ and ‘b’, created by a = Foo()
and b = Foo()
, this creates objects a
and b
of class Foo
. In Python, the code declaring the class Foo does the equivalent of, for example, Foo = type().
This Foo
object can be manipulated at run time, the object can be inspected to discover things about the class, and the object can even be changed to alter the class itself at run time.
Instance Variables
Consider the following code as run in Idle (Python 3.6):
class Foo: def __init__(self): self.var = 1 >>> a = Foo() >>> type(a) 'class: __man__'.Foo >>type(Foo) 'class: type' >>'var' in a.__dict__ True >>>var in Foo.__dict__ False >>> a.var 1 >>> Foo.var Traceback (most recent call last): File "", line 1, in AttributeError: type object 'Foo' has no attribute 'var'
Note the results of type(a)
compared to type(Foo)
. 'var'
appears in the a.__dict__
, but not in the Foo.__dict__
within Foo. Further, a.var
gives a value of 1
while Foo.var
returns an error.
This is all quite straightforward, and is as would be expected.
Class Variables
Now consider this code as run in Idle that has a class variable in Idle (Python 3.6):
class Foo: var = 1 >>> a = Foo() >>'var' in a.__dict__ False >>>'var' in Foo.__dict__ True >>> Foo.var 1 >>> a.var 1 >>> a.var = 2 >>> a.var 2 >>> Foo.var 1 >>> a.__class__.var 1
All as would be expected, the __dict__
results are reversed, this time the class Foo initially has var
, and the instance a
does not.
But even though a
does not have a var
attribute, a.var
returns 1
, because when there is no instance variable var
, Python will return a class level variable if one is present with the same name.
However, assignment does not fall back to class level variables, so setting a.var = 2
actually creates an instance variable var
and reviewing the __dict__
data now reveals both that the class level object and instance each have var
. Once an instance variable is present, the class level variable is hidden from access using a.var
which will now access the instance variable. In this way, code can add an instance variable replacing the value of class variable which provides what can be effectively a default value until the instance value is set.
Simple Usage Example
Consider the following Python class:
class XYPoint: scale = 2.0 serial_no = 0 def __init__(self, x, y): self.serial_no = self.serial_no + 1 self.__class__.serial_no = self.serial_no self.x = x self.y = y def scaled_vector(self): vector = (self.x**2 + self.y**2)**.5 return vector * self.scale def set_scale(self, scale): self.__class__.scale = scale def __repr__(self): return f"XYPoint#{self.serial_no}(x={self.x},y={self.y})"
The class encloses an (x,y) coordinate, and has a method scaled_vector()
which calculates a vector (using Pythagoras theorem) from that coordinate, and then scales the vector from the class variable scale
.
If the class level variable scale
is changed, automatically all XYPoint objects will return vectors using the new scale.
Being a class variable, scale can be read as self.scale
but must be set as in the set_scale()
method by self.__class__.scale = scale
.
The other use case illustrated is the instance counter serial_no
, which provides each instance of XYPoint
a unique, incrementing serial_no
.
[…] first step is to scan the class __annotations__ data. This will contain an entry for each class level variable provided with an annotation. Since variable annotations only appeared in python 3.6, and class […]
LikeLike
[…] instance vs class variables in python […]
LikeLike