python的staticmethod与classmethod实现实例代码


Posted in Python onFebruary 11, 2018

本文源于一时好奇,想要弄清出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__的区别

总结

以上就是本文关于python的staticmethod与classmethod实现实例代码的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!

Python 相关文章推荐
python远程登录代码
Apr 29 Python
python3实现读取chrome浏览器cookie
Jun 19 Python
深入解析Python编程中super关键字的用法
Jun 24 Python
老生常谈python之鸭子类和多态
Jun 13 Python
神经网络理论基础及Python实现详解
Dec 15 Python
Python OpenCV实现图片上输出中文
Jan 22 Python
python对离散变量的one-hot编码方法
Jul 11 Python
Python比较配置文件的方法实例详解
Jun 06 Python
Python3 sys.argv[ ]用法详解
Oct 24 Python
python隐藏类中属性的3种实现方法
Dec 19 Python
Python脚本破解压缩文件口令实例教程(zipfile)
Jun 14 Python
keras CNN卷积核可视化,热度图教程
Jun 22 Python
Python语言的变量认识及操作方法
Feb 11 #Python
利用Opencv中Houghline方法实现直线检测
Feb 11 #Python
tensorflow输出权重值和偏差的方法
Feb 10 #Python
详解tensorflow实现迁移学习实例
Feb 10 #Python
Python学习之Django的管理界面代码示例
Feb 10 #Python
Tensorflow 自带可视化Tensorboard使用方法(附项目代码)
Feb 10 #Python
tensorflow训练中出现nan问题的解决
Feb 10 #Python
You might like
PHP中基于ts与nts版本- vc6和vc9编译版本的区别详解
2013/04/26 PHP
PHP高效获取远程图片尺寸和大小的实现方法
2017/10/20 PHP
PHP7 mongoDB扩展使用的方法分享
2019/05/02 PHP
详解PHP PDO简单教程
2019/05/28 PHP
Mootools 1.2教程 选项卡效果(Tabs)
2009/09/15 Javascript
google jQuery 引用文件,jQuery 引用地址集合(jquery 1.2.6至jquery1.5.2)
2011/04/24 Javascript
基于jQuery替换table中的内容并显示进度条的代码
2011/08/02 Javascript
JavaScript中的运算符种类及其规则介绍
2013/09/26 Javascript
javascript中文本框中输入法切换的问题
2013/12/10 Javascript
jquery bind(click)传参让列表中每行绑定一个事件
2014/08/06 Javascript
JavaScript弹出窗口方法汇总
2014/08/12 Javascript
avascript中的自执行匿名函数应用示例
2014/09/15 Javascript
nodejs URL模块操作URL相关方法介绍
2015/03/03 NodeJs
javascript去掉代码里面的注释
2015/07/24 Javascript
jquery实现的Accordion折叠面板效果代码
2015/09/02 Javascript
老生常谈遮罩层 滚动条的问题
2016/04/29 Javascript
JavaScript使用forEach()与jQuery使用each遍历数组时return false 的区别
2016/08/26 Javascript
node作为中间服务层如何发送请求(发送请求的实现方法详解)
2018/01/02 Javascript
vue iview组件表格 render函数的使用方法详解
2018/03/15 Javascript
JavaScript对象的浅拷贝与深拷贝实例分析
2018/07/25 Javascript
layer.open 获取不到表单信息的解决方法
2019/09/26 Javascript
JavaScript实现单图片上传并预览功能
2019/09/30 Javascript
[00:33]DOTA2上海特级锦标赛 CDEC战队宣传片
2016/03/04 DOTA
Python对ElasticSearch获取数据及操作
2019/04/24 Python
余弦相似性计算及python代码实现过程解析
2019/09/18 Python
pyCharm 实现关闭代码检查
2020/06/09 Python
Python中logging日志记录到文件及自动分割的操作代码
2020/08/05 Python
简单了解python关键字global nonlocal区别
2020/09/21 Python
详解HTML5中的标签
2015/06/19 HTML / CSS
Canvas引入跨域的图片导致toDataURL()报错的问题的解决
2018/09/19 HTML / CSS
荷兰网上买鞋:MooieSchoenen.nl
2017/09/12 全球购物
Johnston & Murphy官网: 约翰斯顿·墨菲牛津总统鞋
2018/01/09 全球购物
学习党章思想汇报
2014/01/07 职场文书
2014领导班子正风肃纪思想汇报
2014/09/18 职场文书
2016幼儿园中班开学寄语
2015/12/03 职场文书
使用Nginx搭载rtmp直播服务器的方法
2021/10/16 Servers