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 相关文章推荐
CentOS 7下Python 2.7升级至Python3.6.1的实战教程
Jul 06 Python
python排序函数sort()与sorted()的区别
Sep 18 Python
Python3.5基础之函数的定义与使用实例详解【参数、作用域、递归、重载等】
Apr 26 Python
Python学习笔记之pandas索引列、过滤、分组、求和功能示例
Jun 03 Python
对numpy下的轴交换transpose和swapaxes的示例解读
Jun 26 Python
jupyter notebook 增加kernel教程
Apr 10 Python
Python+Kepler.gl轻松制作酷炫路径动画的实现示例
Jun 02 Python
pycharm 2020.2.4 pip install Flask 报错 Error:Non-zero exit code的问题
Dec 04 Python
详解python中的三种命令行模块(sys.argv,argparse,click)
Dec 15 Python
python实现进度条的多种实现
Apr 29 Python
Python进行区间取值案例讲解
Aug 02 Python
python机器学习实现oneR算法(以鸢尾data为例)
Mar 03 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 删除一个数组中的某个值.兼容多维数组!
2012/02/18 PHP
浅析iis7.5安装配置php环境
2015/05/10 PHP
Zend Framework基本页面布局分析
2016/03/19 PHP
yii2利用自带UploadedFile实现上传图片的示例
2017/02/16 PHP
javascript 表格内容排序 简单操作示例代码
2014/01/03 Javascript
javascript进行数组追加方法小结
2014/06/16 Javascript
jQuery实现Twitter的自动文字补齐特效
2014/11/28 Javascript
JS+CSS实现仿msn风格选项卡效果代码
2015/10/22 Javascript
理解JavaScript原型链
2016/10/25 Javascript
在html中引入外部js文件,并调用带参函数的方法
2016/10/31 Javascript
javascript常用经典算法详解
2017/01/11 Javascript
原生JS实现图片翻书效果
2017/02/16 Javascript
JS实现的贪吃蛇游戏完整实例
2019/01/18 Javascript
vue实现新闻展示页的步骤详解
2019/04/11 Javascript
JavaScript中的垃圾回收与内存泄漏示例详解
2019/05/02 Javascript
浅析js实现网页截图的两种方式
2019/11/01 Javascript
vue相同路由跳转强制刷新该路由组件操作
2020/08/05 Javascript
[01:09:23]KG vs TNC 2019国际邀请赛小组赛 BO2 第一场 8.15
2019/08/16 DOTA
[30:55]完美世界DOTA2联赛PWL S2 Magma vs LBZS 第二场 11.18
2020/11/18 DOTA
Python实现的txt文件去重功能示例
2018/07/07 Python
Python读取txt某几列绘图的方法
2018/10/14 Python
python实现批量nii文件转换为png图像
2019/07/18 Python
python 消除 futureWarning问题的解决
2019/12/25 Python
Python logging日志库空间不足问题解决
2020/09/14 Python
如何解决python多种版本冲突问题
2020/10/13 Python
CSS3之transition实现下划线的示例代码
2018/05/30 HTML / CSS
保加利亚手表、香水、化妆品和珠宝购物网站:Brasty.bg
2020/04/22 全球购物
后勤人员自我评价怎么写
2013/09/19 职场文书
原料仓管员岗位职责
2015/04/01 职场文书
承诺书范本大全
2015/05/04 职场文书
因公司原因离职的辞职信范文
2015/05/12 职场文书
社区低保工作总结2015
2015/07/23 职场文书
创业计划书之奶茶店开店方案范本!
2019/08/06 职场文书
win10+anaconda安装yolov5的方法及问题解决方案
2021/04/29 Python
iSCSI服务器CHAP双向认证配置
2022/04/01 Servers
Android Canvas绘制文字横纵向对齐
2022/06/05 Java/Android