用实例分析Python中method的参数传递过程


Posted in Python onApril 02, 2015

什么是method?

function就是可以通过名字可以调用的一段代码,我们可以传参数进去,得到返回值。所有的参数都是明确的传递过去的。
method是function与对象的结合。我们调用一个方法的时候,有些参数是隐含的传递过去的。下文会详细介绍。
instancemethod
 

In [5]: class Human(object):
  ...:   def __init__(self, weight):
  ...:     self.weight = weight
  ...:   def get_weight(self):
  ...:     return self.weight
  ...:  
 
In [6]: Human.get_weight
Out[6]: <unbound method Human.get_weight>

这告诉我们get_weight是一个没有被绑定方法,什么叫做未绑定呢?继续看下去。
 

In [7]: Human.get_weight()
---------------------------------------------------------------------------
TypeError                 Traceback (most recent call last)
/home/yao/learn/insight_python/<ipython-input-7-a2b2c5cd2f8d> in <module>()
----> 1 Human.get_weight()
 
TypeError: unbound method get_weight() must be called with Human instance as first argument (got nothing instead)

未绑定的方法必须使用一个Human实例作为第一个参数来调用啊。那我们来试试
 

In [10]: Human.get_weight(Human(45))
Out[10]: 45

果然成功了,但是一般情况下我们习惯这么使用。
 

In [11]: person = Human(45)
 
In [12]: person.get_weight()
Out[12]: 45

这两种方式的结果一模一样。我们看下官方文档是怎么解释这种现象的。
 
When an instance attribute is referenced that isn't a data attribute, its class is searched.
If the name denotes a valid class attribute that is a function object, a method object is
created by packing (pointers to) the instance object and the function object just found together
in an abstract object: this is the method object. When the method object is called with an
argument list, a new argument list is constructed from the instance object and the argument list,
and the function object is called with this new argument list.

原来我们常用的调用方法(person.get_weight())是把调用的实例隐藏的作为一个参数self传递过去了, self 只是一个普通的参数名称,不是关键字。
 

In [13]: person.get_weight
Out[13]: <bound method Human.get_weight of <__main__.Human object at 0x8e13bec>>
 
In [14]: person
Out[14]: <__main__.Human at 0x8e13bec>

我们看到get_weight被绑定在了 person 这个实例对象上。
总结下

  1.     instance method 就是实例对象与函数的结合。
  2.     使用类调用,第一个参数明确的传递过去一个实例。
  3.     使用实例调用,调用的实例被作为第一个参数被隐含的传递过去。

classmethod
 

In [1]: class Human(object):
  ...:   weight = 12
  ...:   @classmethod
  ...:   def get_weight(cls):
  ...:     return cls.weight
 
In [2]: Human.get_weight
Out[2]: <bound method type.get_weight of <class '__main__.Human'>>

我们看到get_weight是一个绑定在 Human 这个类上的method。调用下看看
 

In [3]: Human.get_weight()
Out[3]: 12
In [4]: Human().get_weight()
Out[4]: 12

类和类的实例都能调用 get_weight 而且调用结果完全一样。
我们看到 weight 是属于 Human 类的属性,当然也是 Human 的实例的属性。那传递过去的参数 cls 是类还是实例呢?
 

In [1]: class Human(object):
  ...:   weight = 12
  ...:   @classmethod
  ...:   def get_weight(cls):
  ...:     print cls
 
In [2]: Human.get_weight()
<class '__main__.Human'>
 
In [3]: Human().get_weight()
<class '__main__.Human'>

我们看到传递过去的都是 Human 类,不是 Human 的实例,两种方式调用的结果没有任何区别。cls 只是一个普通的函数参数,调用时被隐含的传递过去。
总结起来

  1.     classmethod 是类对象与函数的结合。
  2.     可以使用类和类的实例调用,但是都是将类作为隐含参数传递过去。
  3.     使用类来调用 classmethod 可以避免将类实例化的开销。

staticmethod
 

In [1]: class Human(object):
  ...:   @staticmethod
  ...:   def add(a, b):
  ...:     return a + b
  ...:   def get_weight(self):
  ...:     return self.add(1, 2)
 
In [2]: Human.add
Out[2]: <function __main__.add>
 
In [3]: Human().add
Out[3]: <function __main__.add>
 
In [4]: Human.add(1, 2)
Out[4]: 3
 
In [5]: Human().add(1, 2)
Out[5]: 3

我们看到 add 在无论是类还是实例上都只是一个普通的函数,并没有绑定在任何一个特定的类或者实例上。可以使用类或者类的实例调用,并且没有任何隐含参数的传入。
 

In [6]: Human().add is Human().add
Out[6]: True
 
In [7]: Human().get_weight is Human().get_weight
Out[7]: False

add 在两个实例上也是同一个对象。instancemethod 就不一样了,每次都会创建一个新的 get_weight 对象。
总结下

  1.     当一个函数逻辑上属于一个类又不依赖与类的属性的时候,可以使用 staticmethod。
  2.     使用 staticmethod 可以避免每次使用的时都会创建一个对象的开销。
  3.     staticmethod 可以使用类和类的实例调用。但是不依赖于类和类的实例的状态。
Python 相关文章推荐
Tornado Web服务器多进程启动的2个方法
Aug 04 Python
高效使用Python字典的清单
Apr 04 Python
使用python3+xlrd解析Excel的实例
May 04 Python
详解python中的装饰器
Jul 10 Python
python实现名片管理系统项目
Apr 26 Python
如何通过雪花算法用Python实现一个简单的发号器
Jul 03 Python
Django错误:TypeError at / 'bool' object is not callable解决
Aug 16 Python
简单瞅瞅Python vars()内置函数的实现
Sep 27 Python
Python解压 rar、zip、tar文件的方法
Nov 19 Python
Windows上安装tensorflow  详细教程(图文详解)
Feb 04 Python
keras在构建LSTM模型时对变长序列的处理操作
Jun 29 Python
Python selenium模拟网页点击爬虫交管12123违章数据
May 26 Python
使用优化器来提升Python程序的执行效率的教程
Apr 02 #Python
使用Python脚本对Linux服务器进行监控的教程
Apr 02 #Python
在Python编程过程中用单元测试法调试代码的介绍
Apr 02 #Python
用Python的Django框架完成视频处理任务的教程
Apr 02 #Python
用map函数来完成Python并行任务的简单示例
Apr 02 #Python
对于Python异常处理慎用“except:pass”建议
Apr 02 #Python
Python的设计模式编程入门指南
Apr 02 #Python
You might like
在任意字符集下正常显示网页的方法二(续)
2007/04/01 PHP
js验证表单大全
2006/11/25 Javascript
AJAX的跨域与JSONP(为文章自动添加短址的功能)
2010/01/17 Javascript
Javascript学习笔记一 之 数据类型
2010/12/15 Javascript
Ajax同步与异步传输的示例代码
2013/11/21 Javascript
实现网页页面跳转的几种方法(meta标签、js实现、php实现)
2014/05/20 Javascript
jquery uploadify 在FF下无效的解决办法
2014/09/26 Javascript
JavaScript中return false的用法
2015/03/12 Javascript
JS实现鼠标滑过折叠与展开菜单效果代码
2015/09/06 Javascript
JavaScript 链式结构序列化详解
2016/09/30 Javascript
javascript实现下雨效果
2017/03/27 Javascript
JQuery 又谈ajax局部刷新
2017/11/27 jQuery
浅谈bootstrap layer.open中end的使用方法
2019/09/12 Javascript
layui prompt 设置允许空白提交的方法
2019/09/24 Javascript
vue+element 实现商城主题开发的示例代码
2020/03/26 Javascript
Vue Object 的变化侦测实现代码
2020/04/15 Javascript
[01:08:57]2014 DOTA2国际邀请赛中国区预选赛 5 23 CIS VS LGD第二场
2014/05/24 DOTA
[01:06]DOTA2小知识课堂 Ep.02 吹风竟可解梦境缠绕
2019/12/05 DOTA
在Python中使用成员运算符的示例
2015/05/13 Python
python搭建虚拟环境的步骤详解
2016/09/27 Python
Python WXPY实现微信监控报警功能的代码
2017/10/20 Python
Php多进程实现代码
2018/05/07 Python
Python 动态导入对象,importlib.import_module()的使用方法
2019/08/28 Python
PyTorch中permute的用法详解
2019/12/30 Python
详解Python openpyxl库的基本应用
2021/02/26 Python
CSS3 Media Queries(响应式布局可以让你定制不同的分辨率和设备)
2013/06/06 HTML / CSS
HTML5实时语音通话聊天MP3压缩传输3KB每秒
2019/08/28 HTML / CSS
移动端HTML5 input常见问题(小结)
2020/09/28 HTML / CSS
菲律宾领先的在线时尚商店:Zalora菲律宾
2018/02/08 全球购物
注塑工厂厂长岗位职责
2013/12/02 职场文书
《找不到快乐的波斯猫》教学反思
2014/02/24 职场文书
建国大业观后感800字
2015/06/01 职场文书
肖申克救赎观后感
2015/06/02 职场文书
会计继续教育培训心得体会
2016/01/19 职场文书
《正面管教》读后有感:和善而坚定的旅程
2019/12/19 职场文书
Python爬虫入门案例之爬取去哪儿旅游景点攻略以及可视化分析
2021/10/16 Python