Chapter 7. Classes and Object-Oriented Programming

The class Statement

Class Instances

Scoping Rules

Inheritance

Polymorphism Dynamic Binding and Duck Typing

Static Methods and Class Methods

Static Methods *

Besides instance methods there are two other common kinds of methods that can be defined. [p123]

A static method is an ordinary function that lives in the namespace defined by a class. It does not operate on any kind of instance. To define a static method, use the @staticmethod decorator as shown here:

class Foo(object):
    @staticmethod
    def add(x,y):
        return x + y

To call a static method, you just prefix it by the class name. You do not pass it any additional information. For example:

x = Foo.add(3,4) # x = 7

A common use of static methods is in writing classes where you might have many different ways to create new instances. Because there can only be one __init__() function, alternative creation functions are often defined as shown here:

class Date(object):
    def __init__(self,year,month,day):
        self.year = year
        self.month = month
        self.day = day

    @staticmethod
    def now():
        t = time.localtime()
        return Date(t.tm_year, t.tm_mon, t.tm_day)

    @staticmethod
    def tomorrow():
        t = time.localtime(time.time() + 86400)
        return Date(t.tm_year, t.tm_mon, t.tm_day)

Class Methods *

Class methods are methods that operate on the class itself as an object. Defined using the @classmethod decorator, a class method is different than an instance method in that the class is passed as the first argument which is named cls by convention. For example:

class Times(object):
    factor = 1

    @classmethod
    def mul(cls, x):
        return cls.factor * x


class TwoTimes(Times):
    factor = 2


x = TwoTimes.mul(4) # Calls Times.mul(TwoTimes, 4) -> 8

Notice how the class TwoTimes is passed to mul() as an object. These are practical but subtle uses of class methods. [p124]

Suppose that you defined a class that inherited from the Date class shown previously and customized it slightly:

class EuroDate(Date):
    # Modify string conversion to use European dates
    def __str__(self):
        return "%02d/%02d/%4d" % (self.day, self.month, self.year)

Because the class inherits from Date, it has all of the same features. However, the now() and tomorrow() methods are slightly broken. For example, if someone calls EuroDate.now(), a Date object is returned instead of a EuroDate object. A class method can fix this:

class Date(object):
    ...
    @classmethod
    def now(cls):
        t = time.localtime()
        # Create an object of the appropriate type
        return cls(t.tm_year, t.tm_month, t.tm_day)

class EuroDate(Date):
    ...

a = Date.now() # Calls Date.now(Date) and returns a Date
b = EuroDate.now() # Calls Date.now(EuroDate) and returns a EuroDate

One caution about static and class methods is that Python does not manage these methods in a separate namespace than the instance methods. As a result, they can be invoked on an instance. For example:

d = Date(1967,4,9)
b = d.now() # Calls Date.now(Date)

This is potentially quite confusing because a call to d.now() doesn’t really have anything to do with the instance d. This behavior is one area where the Python object system differs from that found in other OO languages such as Ruby. In those languages, class methods are strictly separate from instance methods.