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
"""



[Home page] Books Code Blog Python Author Train Find ©M.Lutz