@CLASSMETHOD 隐藏的传递给第一个参数,是对象实体的类,而不是SELF。 @STATICMETHOD 不管传递给第一个参数的是SELF(对象实体)还是CLS(对象实体的类),他们的效果(表现)都一样。

如果有个具体的例子,可能会更好的理解,这里也应用 foo bar原则,就不多做解释。

class Foo(object):
    def bar(self,x):
        print("executing bar({},{})".format(self,x))
    @classmethod
    def class_bar(cls,x):
        print("executing class_bar({},{})".format(cls,x))
    @staticmethod
    def static_bar(x):
        print("executing static_bar({})".format(x))
a=Foo()

下面是一个对象实体调用方法的常用方式。对相关实体a被隐藏的传递给了第一个参数。

a.bar(100)
executing bar(<__main__.Foo object at 0x7f67aca7bf28>,100)

如果用classmethod装饰器来调用呢?隐藏传递到第一个参数的是对象实体类(class Foo),而不是self。
如下:

a.class_bar(100)
executing class_bar(<class '__main__.Foo'>,100)

其实吧,你把一些方法定义成@classmethod装饰器,就是想直接通过类来调用这个方法,而不需要先实例化类,再调用静态方法。这个在日常开发中比较常用,例如我在写flask modules 定义 一些查询方法时会用到类装饰器,刚开始我也不知道为什么这样搞,刚开始就是对着文档抄。
你如果不实例化类来调用bar()方法的话会报错

Foo.bar(100)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: bar() missing 1 required positional argument: 'x'

而调用类方法就不会有问题:

Foo.class_bar(100)
executing class_bar(<class '__main__.Foo'>,100)

至于静态方法装饰器呢?
不管你传递给第一个参数的是self, 还是cls, 他们的结果都一样:

a.static_bar(100)
executing static_bar(100)
Foo.static_bar(100)
executing static_bar(100)

静态方法被用来组织类之间有逻辑关系的函数。为什么这么说呢?
bar()只是函数,但你要调用a.bar的时候你得到的不仅是一个函数,你得到的是一个第一个参数绑定到a的”pro版”函数。 bar()需要两个参数。而a.foo()只需要一个参数。

a绑定了foo。下面可以证实什么是绑定了:

print(a.bar)
<bound method Foo.bar of <__main__.Foo object at 0x7f67aca7bf28>>

如果使用 a.class_bar,是Foo绑定到了class_bar,而不是a。

print(a.class_bar)
<bound method Foo.class_bar of <class '__main__.Foo'>>

最后呢?静态方法其实就是一个方法。 a.static_bar 只返回一个不带参数绑定的方法。static_bar 和 a.static_bar只需要一个参数。

print(a.static_bar)
<function Foo.static_bar at 0x7f67ac8e0598>

总结就不用了吧,文章开头已经说了总结,这里就说一下文章逻辑,本文参考100道面实题,做面试题还能明白以前不明白为什么那样写。如果不明白为什么文档里这样写,那就先抄下来,让程序跑起来,过一段时间其义自见。


参考文献

相关文章