15.3. Class Methods¶
Class methods are associated with a class rather than with individual objects, like regular methods are. You can recognize a class method in code when you see two markers: the @classmethod decorator before the method’s def statement and the use of cls as the first parameter, as shown in the follow- ing example.
>>> class ExampleClass:
>>> def exampleRegularMethod(self):
>>> print('This is a regular method.')
>>> @classmethod
>>> def exampleClassMethod(cls):
>>> print('This is a class method.')
>>> # Call the class method without instantiating an object:
>>> ExampleClass.exampleClassMethod()
>>> obj = ExampleClass()
>>> # Given the above line, these two lines are equivalent:
>>> obj.exampleClassMethod()
>>> obj.__class__.exampleClassMethod()
This is a class method.
This is a class method.
This is a class method.
The cls parameter acts like self except self refers to an object, but the cls parameter refers to an object’s class. This means that the code in a class method cannot access an individual object’s attributes or call an object’s regular methods. Class methods can only call other class methods or access class attributes. We use the name cls because class is a Python keyword, and just like other keywords, such as if , while , or import , we can’t use it for parameter names. We often call class attributes through the class object, as in ExampleClass.exampleClassMethod() . But we can also call them through any object of the class, as in obj.exampleClassMethod() .
Class methods aren’t commonly used. The most frequent use case is to provide alternative constructor methods besides __init__() . For exam- ple, what if a constructor function could accept either a string of data the new object needs or a string of a filename that contains the data the new object needs? We don’t want the list of the __init__() method’s parameters to be lengthy and confusing. Instead let’s use class methods to return a new object.
For example, let’s create an AsciiArt class. As you saw in Chapter 14, ASCII art uses text characters to form an image.
>>> class AsciiArt:
>>> def __init__(self, characters):
>>> self._characters = characters
>>> @classmethod
>>> def fromFile(cls, filename):
>>> with open(filename) as fileObj:
>>> characters = fileObj.read()
>>> return cls(characters)
>>> def display(self):
>>> print(self._characters)
>>> # Other AsciiArt methods would go here...
>>> face1 = AsciiArt(' _______\n' +
>>> '| . . |\n' +
>>> '| \\___/ |\n' +
>>> '|_______|')
>>> face1.display()
>>> face2 = AsciiArt.fromFile('face.txt')
>>> face2.display()
_______ | . . | | ___/ | |_______|
The AsciiArt class has an __init__() method that can be passed the text characters of the image as a string. It also has a fromFile() class method that can be passed the filename string of a text file containing the ASCII art. Both methods create AsciiArt objects.
When you run this program and there is a face.txt file that contains the ASCII art face, the output will look something like this:
The fromFile() class method makes your code a bit easier to read, com- pared to having __init__() do everything.
Another benefit of class methods is that a subclass of AsciiArt can inherit its fromFile() method (and override it if necessary). This is why we call cls(characters) in the AsciiArt class’s fromFile() method instead of AsciiArt(characters) . The cls() call will also work in subclasses of AsciiArt without modification because the AsciiArt class isn’t hardcoded into the method. But an AsciiArt() call would always call AsciiArt class’s __init__() instead of the subclass’s __init__() . You can think of cls as meaning “an object representing this class.”
Keep in mind that just as regular methods should always use their self parameter somewhere in their code, a class method should always use its cls parameter. If your class method’s code never uses the cls parameter, it’s a sign that your class method should probably just be a function.