Python has three types of methods. Here is an example illustrating their use in Python.
class MyClass(object): def some_instance_method(self, *args, **kwds): pass @classmethod def some_class_method(cls, *args, **kwds): pass @staticmethod def some_static_method(*args, **kwds): passPython is unique in that its instance methods take an explicit instance argument. You can call it any name, but the convention is to call it
self
. Many languages like C++ and Java have an implicit this
instead. Syntax wise, the class method would take a class (which is also an object in Python) as its first argument, and a static method takes no explicit class nor object references.Many people understand that static methods do not use per-instance object states, but they implement functionality grouped as part of the class. That's why you can forego the explicit references. But nobody seems to explain well what class methods are good for. Class states? That's a synonym to the dirty word "global variables" which everyone knows you should avoid. But class methods have legitimate uses.
The first legitimate use is to use a class method like a static method, but better.
Imagine you have a static method that wants to use another static method in the same class, or a static method that wants to use constants defined in the class. You could refer to the class by its full name like this:
class Smoothie(object): YOGURT = 1 STRAWBERRY = 2 BANANA = 4 MANGO = 8 @staticmethod def blend(*mixes): return sum(mixes) / len(mixes) @staticmethod def eternal_sunshine(): return Smoothie.blend( Smoothie.YOGURT, Smoothie.STRAWBERRY, Smoothie.BANANA) @staticmethod def mango_lassi(): return Smoothie.blend( Smoothie.YOGURT, Smoothie.MANGO)But with class method, you could write instead:
class Smoothie(object): YOGURT = 1 STRAWBERRY = 2 BANANA = 4 MANGO = 8 @staticmethod def blend(*mixes): return sum(mixes) / len(mixes) @classmethod def eternal_sunshine(cls): return cls.blend(cls.YOGURT, cls.STRAWBERRY, cls.BANANA) @classmethod def mango_lassi(cls): return cls.blend(cls.YOGURT, cls.MANGO)This results in a much more succinct code. Imagine the headache you would have saved renaming the class if you later decide that
SimpleSmoothie
is a better name for just Smoothie
. Indeed, making code refactoring easier is one of the first use case I discovered with Python class methods.This is what you get if you want to see what the class methods return:
>>> Smoothie.eternal_sunshine() 2 >>> Smoothie.mango_lassi() 4There is a subtle performance benefit. If you refer to the full class name in a static method, the Python interpreter has to first look up the local variables, not finding it there, and then look up the global variables. With a class method,
cls
would be found in the local variables, so there is no need to look up the globals.With this in mind, the second legitimate use is to allow a subclass to override static and class methods.
class BetterSmoothie(Smoothie): YOGURT = 'yogurt' STRAWBERRY = 'strawberry' BANANA = 'banana' MANGO = 'mango' @staticmethod def blend(*mixes): return ', '.join(mixes)Now, without touching the class methods
eternal_sunshine()
and mango_lassi()
, they will use the new blend()
as well as the new constants, and produce a different kind of smoothie mix.
>>> BetterSmoothie.eternal_sunshine() 'yogurt, strawberry, banana' >>> BetterSmoothie.mango_lassi() 'yogurt, mango'If you use a class method for your class factory, then it will be able to construct derived classes too. It may or may not make sense depending on your class design.
class Xyzzy(object): def __init__(self, which_factory): self.which_factory = which_factory @classmethod def factory_foo(cls): return cls('factory_foo') @classmethod def factory_bar(cls): return cls('factory_bar') class Yappy(Xyzzy): def __init__(self, which_factory): super(Yappy, self).__init__(which_factory) print which_factoryNotice that only the
Yappy
class prints out the factory type, but not Xyzzy
. And this is what you get:
>>> Xyzzy.factory_foo() <__main__.Xyzzy object at 0x1027d1050> >>> Xyzzy.factory_bar() <__main__.Xyzzy object at 0x1027c7e10> >>> Yappy.factory_foo() factory_foo <__main__.Yappy object at 0x1027d10d0> >>> Yappy.factory_bar() factory_bar <__main__.Yappy object at 0x1027c7e10>With class method factories, even though the factories are defined in the base class, they are able to construct the derived classes as well.
Class method in Python is really a unique feature. Some use cases shown above demonstrate how to use class methods to refer to other static or class methods in the same class and how to allow a subclass to change behavior of the base class. The closest analog in C++ would be the curiously recurring template pattern.