File: classmethods.py
#----------------------------------------------------------------------- # LP5E supplemental example: classmethod versus staticmethod # # Classmethods can work much like customizable module functions: # they're callable with no instances, are localized to the containing # class, and may be customized via normal class inheritance. However, # they are functionally equivalent to staticmethods (and to simple # class-level functions called only through classes in 3.X), unless # they use per-class data. Here is the case for classmethods: #----------------------------------------------------------------------- from __future__ import print_function # 2.X compatibility class C: x = 1 @classmethod def m1(c): # replaced print(c.__name__, c.x) @classmethod def m2(c): # inherited print(c.__name__, c.x) # c is most-specific (lowest) class class D(C): x = 2 @classmethod def m1(c): # m1 replaced, m2 from C, m3 unique print(c.__name__, c.x) @classmethod def m3(c): # inherited print(c.__name__, c.x) class E(D): x = 3 @classmethod def m1(c): # m1 replaced, m2 from C, m3 from D print(c.__name__, c.x) print('CLASSMETHOD') print('class calls...') C.m1(); C.m2() # local, local D.m1(); D.m2(); D.m3() # local, inherited, local E.m1(); E.m2(); E.m3() # local, inherited, inherited print('instance calls...') c = C(); d = D(); e = E() c.m1(); c.m2() # ditto, but from instances d.m1(); d.m2(); d.m3() e.m1(); e.m2(); e.m3() #----------------------------------------------------------------------- # And here's the equivalent with staticmethods. As function calls, # the routing is the same, but there is no notion of per-class data # here: staticmethods have access to data in their own class (or # other classes named specifically) only, while classmethods have # access to data in the class that's the implied subject of a call. # That's why LP5E states that classmethod is best for per-class data, # and staticmethod is for local class data. The two are equivalent # only if the classes are used to package just functions with no data. #----------------------------------------------------------------------- class C: x = 1 @staticmethod def m1(): # replaced print(C.__name__, C.x) @staticmethod def m2(): # inherited print(C.__name__, C.x) # there is no lowest class here class D(C): x = 2 @staticmethod def m1(): # m1 replaced, m2 from C, m3 unique print(D.__name__, D.x) @staticmethod def m3(): # inherited print(D.__name__, D.x) class E(D): x = 3 @staticmethod def m1(): # m1 replaced, m2 from C, m3 from D print(E.__name__, E.x) print('\nSTATICMETHOD') print('class calls...') C.m1(); C.m2() # local, local D.m1(); D.m2(); D.m3() # local, inherited, local E.m1(); E.m2(); E.m3() # local, inherited, inherited print('instance calls...') c = C(); d = D(); e = E() c.m1(); c.m2() # ditto, but from instances d.m1(); d.m2(); d.m3() e.m1(); e.m2(); e.m3() #----------------------------------------------------------------------- # Output #----------------------------------------------------------------------- """ c:\...\code> py -3 classmethods.py CLASSMETHOD class calls... C 1 C 1 D 2 D 2 D 2 E 3 E 3 E 3 instance calls... C 1 C 1 D 2 D 2 D 2 E 3 E 3 E 3 STATICMETHOD class calls... C 1 C 1 D 2 C 1 D 2 E 3 C 1 D 2 instance calls... C 1 C 1 D 2 C 1 D 2 E 3 C 1 D 2 """