python的staticmethod与classmethod实现实例代码
作者:pi9nc 发布时间:2022-10-02 23:56:45
本文源于一时好奇,想要弄清出python的staticmethod()这一builtin方法的实现,查了一些资料(主要是python官方手册了)汇集于此
python在类中,有三种调用method的方法:普通method,staticmethod和classmethod
前两个应该都好理解,classmethod就是在调用这个函数的时候,会把调用对象的class object对象隐式地传进去。咦?这个class object不是一个类型?No,在python里面,class object不像静态语言一样是个类型,它在虚拟机中,就是一个对象。普通method调用需要把自己self作为参数传递,初学的时候怎么着也不能理解,不过看多了就自然熟悉了。比较奇怪的是staticmethod和classmethod不像静态语言一样,通过保留关键字定义,而是使用@staticmethod
或者staticmethod()
这种builtin函数进行定义。这个@staticmethod
到底是个什么东东?
@staticmethod
def foo(x):
print(x)
之前用过java,所以第一反应这是个annotation……唔,确实感觉像个AOP的东西,python里把它称作decorator。如果我们要自己实现一个staticmethod,该怎么写呢?
研究了下官方的代码,我再改了改,感觉应该这样写:
def foo(x):
print(x)
class StaticMethod(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))
return self.f
class Class1(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__.Class1 object at 0xece2d0>, Class1 = <class '__main__.Class1'>
__get__() called
INFO: self = <__main__.StaticMethod object at 0xece5d0>, instance =<__main__.Class1 object at 0xece2d0>, owner = <class '__main__.Class1'>
__get__() called
INFO: self = <__main__.StaticMethod object at 0xece5d0>, instance =None, owner = <class '__main__.Class1'>
ins.method = <function foo at 0xeb6c00>, Class1.method = <function foo at 0xeb6c00>
__get__() called
INFO: self = <__main__.StaticMethod object at 0xece5d0>, instance =<__main__.Class1 object at 0xece2d0>, owner = <class '__main__.Class1'>
abc
__get__() called
INFO: self = <__main__.StaticMethod object at 0xece5d0>, instance =None, owner = <class '__main__.Class1'>
xyz
嗯,看上去一切都挺顺利,Class1包含了一个变量method,不过这个method其实也是一个特殊处理过的StaticMethod类。这个类中有一个__get__
函数,当类被“get”的时候,被访问的时候,会默认把访问者的instance和class信息都传进来。所以我们看到不管是否调用method()这个函数,只要碰着了method,这个函数就会触发,就会打印出当前instance和class信息。虽然ins和Class1的instance各有不同,但__get__
函数中只是返回foo函数,所以这里调用method之时就没有区别,调用的都是同一个function对象。
好的,那么classmethod又如何实现呢?
def foo2(cls, x):
print("foo2's class = ", cls)
print(x)
class ClassMethod(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))
def tmpfunc(x):
print("I'm tmpfunc")
return self.f(owner, x)
return tmpfunc
class Class2(object):
method = ClassMethod(foo2)
class Class21(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__.ClassMethod object at 0xdeb250>, instance =<__main__.Class2 object at 0xdeb350>, owner = <class '__main__.Class2'>
__get__() called
INFO: self = <__main__.ClassMethod object at 0xdeb250>, instance =None, owner = <class '__main__.Class2'>
__get__() called
INFO: self = <__main__.ClassMethod object at 0xdeb250>, instance =None, owner = <class '__main__.Class21'>
ins.method = <function tmpfunc at 0xdee050>, Class2.method = <function tmpfunc at 0xdee1e8>, Class21.method = <function tmpfunc at 0xdee270>
__get__() called
INFO: self = <__main__.ClassMethod object at 0xdeb250>, instance =<__main__.Class2 object at 0xdeb350>, owner = <class '__main__.Class2'>
I'm tmpfunc
foo2's class = <class '__main__.Class2'>
abc
__get__() called
INFO: self = <__main__.ClassMethod object at 0xdeb250>, instance =None, owner = <class '__main__.Class2'>
I'm tmpfunc
foo2's class = <class '__main__.Class2'>
xyz
__get__() called
INFO: self = <__main__.ClassMethod object at 0xdeb250>, instance =None, owner = <class '__main__.Class21'>
I'm tmpfunc
foo2's class = <class '__main__.Class21'>
asdf
可以看出,classmethod和staticmethod的实现方法是大同小异。staticmethod比较简单,直接返回self.f变量就好了,而classmethod不行,需要把调用时候的class类型信息传给foo2函数,这个函数根据接收的class信息来作不同的工作。(不过我现在也没有想到可以用来做些什么)
有个地方值得注意,可能同志们刚才也已经想到了,我一定必须要定义一个tempfunc,再返回它才能完成工作吗?可不可以不要
def tmpfunc(x):
print("I'm tmpfunc")
return self.f(owner, x)
return tmpfunc
而直接返回一个
return self.f(owner, *args)
我刚试了一把,直接传args默认参数是不行的,因为__get__
被调用的时候,还没有把参数传进来。只有return tmpfunc之后,Class2.method('xyz')
的参数才挂在tmpfunc之上。
当然,如果有朋友成功做到了,请一定留言告诉我XD
小结:看来staticmethod和classmethod实现不是很困难,多亏了__get__
函数帮忙。前文也提到__get__
被调用时会把instance和class信息都填进来,真是帮了很大忙。但是,这个__get__
函数到底又是怎么一回事?为什么这么神奇?大家可以参考Python中 __get__和__getattr__和__getattribute__的区别
来源:http://blog.csdn.net/pi9nc/article/details/39121367
猜你喜欢
- 网站上的Banner条,是网站用来作为盈利或者是发布一些重要的信息的工具。但是它又不能作为网页的主要内容,因为它的主要目的是吸引人的注意力,
- 本文实例为大家分享了Django实现上传图片的具体代码,供大家参考,具体内容如下1.设置存放上传的图片的文件夹settings.pyMEDI
- 一、前言最近做web网站的测试,遇到很多需要批量造数据的功能;比如某个页面展示数据条数需要达到10000条进行测试,此时手动构造数据肯定是不
- 加密解密字符串的asp函数,如用于ASP链接地址栏参数的加密,看代码就明白。比如:show.asp?id=DB26538FA54C70E1E
- 一、概述公司新购了一批PC,准备把几个性能较优的PC升级为数据库服务器,替换老旧的机器。公司有套POS终端软件,后台数据存储是 MySQL
- 1、RuntimeError: invalid argument 0: Sizes of tensors must match except
- 想要利用Python来操作word文档可以使用docx模块.安装: pip install python-docxfrom docx imp
- 本文实例讲述了Python开发微信公众平台的方法。分享给大家供大家参考,具体如下:这两天将之前基于微信公众平台的代码重构了下,基础功能以库的
- 前言现在最流行的本地存储莫过于 cookie 的应用,但浏览器对 cookie 有很多限制,最大的限制在于其对cookie 总大小
- 用户登录验证脚本,Chkpwd.asp<% '=======用户登录验证脚本======= '如果尚未定义Passed
- 用css属性选择器可以有选择性地对链接样式进行控制,如让所有的外部链接都加一个小图标来标识其是一外部链接。但用css有弊端: 1、只支持Fi
- 在JavaScript中,我们应该尽可能的用局部变量来代替全局变量,这句话所有人都知道,可是这句话是谁先说的?为什么要这么做?有什么根据么?
- CSS的出现使网页制作者在对网页元素的控制方便许多,当然,有利必有弊,CSS只能对颜色、大小、距离等静
- sql server中变量要先申明后赋值:局部变量用一个@标识,全局变量用两个@(常用的全局变量一般都是已经定义好的);申明局部变量语法:d
- 在python3爬虫中如何我们想要导入/导出Redis数据,就要安装使用RedisDump。RedisDump是一个用于Redis数据导入/
- 1.文档对象模型(DOM)DOM是HTML和XML文档的编程基础,它定义了处理执行文档的途径。编程者可以使用DOM增加文档、定位文档结构、填
- 1.彻底弄懂CSS盒子模式一(DIV布局快速入门) 2.彻底弄懂CSS盒子模式二(导航栏实例) 3.彻底弄懂CSS盒子模式三(浮动的表演和清
- 凡搞WEB开发的人都离不开HTTP(超文本传输协议),而要了解HTTP,除了HTML本身以外,还有一部分不可忽视的就是HTTP消息头。做过S
- 对大家推荐很好使用的MySql节点系统,像让大家对MySql节点系统有所了解,然后对MySql节点系统全面讲解介绍,希望对大家有用在向大家详
- 这是我上一篇关于安全的文章的其中一节。这是一个众所周知的事实,对你运行中的网站的MySQL数据库备份是极为重要的只需按照下面3步做,一切都在