python的staticmethod与classmethod实现实例代码
本文源于一时好奇,想要弄清出python的staticmethod()这一builtin方法的实现,查了一些资料(主要是python官方手册了)汇集于此
python在类中,有三种调用method的方法:普通method,staticmethod和classmethod
前两个应该都好理解,classmethod就是在调用这个函数的时候,会把调用对象的classobject对象隐式地传进去。咦?这个classobject不是一个类型?No,在python里面,classobject不像静态语言一样是个类型,它在虚拟机中,就是一个对象。普通method调用需要把自己self作为参数传递,初学的时候怎么着也不能理解,不过看多了就自然熟悉了。比较奇怪的是staticmethod和classmethod不像静态语言一样,通过保留关键字定义,而是使用@staticmethod或者staticmethod()这种builtin函数进行定义。这个@staticmethod到底是个什么东东?
@staticmethod deffoo(x): print(x)
之前用过java,所以第一反应这是个annotation……唔,确实感觉像个AOP的东西,python里把它称作decorator。如果我们要自己实现一个staticmethod,该怎么写呢?
研究了下官方的代码,我再改了改,感觉应该这样写:
deffoo(x): print(x) classStaticMethod(object): def__init__(self,function): print("__init__()called") self.f=function def__get__(self,instance,owner): print("\t__get__()called") print("\tINFO:self=%s,instance=%s,owner=%s"%(self,instance,owner)) returnself.f classClass1(object): method=StaticMethod(foo) if__name__=='__main__': ins=Class1() print("ins=%s,Class1=%s"%(ins,Class1)) print("ins.method=%s,Class1.method=%s"%(ins.method,Class1.method)) ins.method('abc') Class1.method('xyz')
输出结果是:
__init__()called
ins=<__main__.Class1objectat0xece2d0>,Class1=
__get__()called
INFO:self=<__main__.StaticMethodobjectat0xece5d0>,instance=<__main__.Class1objectat0xece2d0>,owner=
__get__()called
INFO:self=<__main__.StaticMethodobjectat0xece5d0>,instance=None,owner=
ins.method=,Class1.method=
__get__()called
INFO:self=<__main__.StaticMethodobjectat0xece5d0>,instance=<__main__.Class1objectat0xece2d0>,owner=
abc
__get__()called
INFO:self=<__main__.StaticMethodobjectat0xece5d0>,instance=None,owner=
xyz
嗯,看上去一切都挺顺利,Class1包含了一个变量method,不过这个method其实也是一个特殊处理过的StaticMethod类。这个类中有一个__get__函数,当类被“get”的时候,被访问的时候,会默认把访问者的instance和class信息都传进来。所以我们看到不管是否调用method()这个函数,只要碰着了method,这个函数就会触发,就会打印出当前instance和class信息。虽然ins和Class1的instance各有不同,但__get__函数中只是返回foo函数,所以这里调用method之时就没有区别,调用的都是同一个function对象。
好的,那么classmethod又如何实现呢?
deffoo2(cls,x): print("foo2'sclass=",cls) print(x) classClassMethod(object): def__init__(self,function): print("ClassMethod:__init__()called") self.f=function def__get__(self,instance,owner=None): print("\t__get__()called") print("\tINFO:self=%s,instance=%s,owner=%s"%(self,instance,owner)) deftmpfunc(x): print("I'mtmpfunc") returnself.f(owner,x) returntmpfunc classClass2(object): method=ClassMethod(foo2) classClass21(Class2): pass if__name__=='__main__': ins=Class2() print("ins.method=%s,Class2.method=%s,Class21.method=%s"%(ins.method,Class2.method,Class21.method)) ins.method('abc') Class2.method('xyz') Class21.method('asdf')
输出结果是:
ClassMethod:__init__()called
__get__()called
INFO:self=<__main__.ClassMethodobjectat0xdeb250>,instance=<__main__.Class2objectat0xdeb350>,owner=
__get__()called
INFO:self=<__main__.ClassMethodobjectat0xdeb250>,instance=None,owner=
__get__()called
INFO:self=<__main__.ClassMethodobjectat0xdeb250>,instance=None,owner=
ins.method=,Class2.method= ,Class21.method=
__get__()called
INFO:self=<__main__.ClassMethodobjectat0xdeb250>,instance=<__main__.Class2objectat0xdeb350>,owner=
I'mtmpfunc
foo2'sclass=
abc
__get__()called
INFO:self=<__main__.ClassMethodobjectat0xdeb250>,instance=None,owner=
I'mtmpfunc
foo2'sclass=
xyz
__get__()called
INFO:self=<__main__.ClassMethodobjectat0xdeb250>,instance=None,owner=
I'mtmpfunc
foo2'sclass=
asdf
可以看出,classmethod和staticmethod的实现方法是大同小异。staticmethod比较简单,直接返回self.f变量就好了,而classmethod不行,需要把调用时候的class类型信息传给foo2函数,这个函数根据接收的class信息来作不同的工作。(不过我现在也没有想到可以用来做些什么)
有个地方值得注意,可能同志们刚才也已经想到了,我一定必须要定义一个tempfunc,再返回它才能完成工作吗?可不可以不要
deftmpfunc(x): print("I'mtmpfunc") returnself.f(owner,x) returntmpfunc
而直接返回一个
returnself.f(owner,*args)
我刚试了一把,直接传args默认参数是不行的,因为__get__被调用的时候,还没有把参数传进来。只有returntmpfunc之后,Class2.method('xyz')的参数才挂在tmpfunc之上。
当然,如果有朋友成功做到了,请一定留言告诉我XD
小结:看来staticmethod和classmethod实现不是很困难,多亏了__get__函数帮忙。前文也提到__get__被调用时会把instance和class信息都填进来,真是帮了很大忙。但是,这个__get__函数到底又是怎么一回事?为什么这么神奇?大家可以参考Python中__get__和__getattr__和__getattribute__的区别
总结
以上就是本文关于python的staticmethod与classmethod实现实例代码的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!