$$ \newcommand{\tp}{\thinspace .} $$




This chapter is taken from the book A Primer on Scientific Programming with Python by H. P. Langtangen, 5th edition, Springer, 2016.

Static methods and attributes

Up to now, each instance has its own copy of data attributes. Sometimes it can be natural to have data attributes that are shared among all instances. For example, we may have an attribute that counts how many instances that have been made so far. We can exemplify how to do this in a little class for points \( (x,y,z) \) in space:

>>> class SpacePoint(object):
...     counter = 0
...     def __init__(self, x, y, z):
...         self.p = (x, y, z)
...         SpacePoint.counter += 1

The counter data attribute is initialized at the same indentation level as the methods in the class, and the attribute is not prefixed by self. Such attributes declared outside methods are shared among all instances and called static attributes. To access the counter attribute, we must prefix by the classname SpacePoint instead of self: SpacePoint.counter. In the constructor we increase this common counter by 1, i.e., every time a new instance is made the counter is updated to keep track of how many objects we have created so far:

>>> p1 = SpacePoint(0,0,0)
>>> SpacePoint.counter
>>> for i in range(400):
...     p = SpacePoint(i*0.5, i, i+1)
>>> SpacePoint.counter

The methods we have seen so far must be called through an instance, which is fed in as the self variable in the method. We can also make class methods that can be called without having an instance. The method is then similar to a plain Python function, except that it is contained inside a class and the method name must be prefixed by the classname. Such methods are known as static methods. Let us illustrate the syntax by making a very simple class with just one static method write:

>>> class A(object):
...     @staticmethod
...     def write(message):
...         print message
>>> A.write('Hello!')

As demonstrated, we can call write without having any instance of class A, we just prefix with the class name. Also note that write does not take a self argument. Since this argument is missing inside the method, we can never access non-static attributes since these always must be prefixed by an instance (i.e., self). However, we can access static attributes, prefixed by the classname.

If desired, we can make an instance and call write through that instance too:

>>> a = A()
>>> a.write('Hello again')
Hello again

Static methods are used when you want a global function, but find it natural to let the function belong to a class and be prefixed with the classname.