This chapter is taken from the book A Primer on Scientific Programming with Python by H. P. Langtangen, 5th edition, Springer, 2016.
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
1
>>> for i in range(400):
... p = SpacePoint(i*0.5, i, i+1)
...
>>> SpacePoint.counter
401
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!')
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.