用实例分析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 相关文章推荐
使用Python的Treq on Twisted来进行HTTP压力测试
Apr 16 Python
在Python中操作列表之List.pop()方法的使用
May 21 Python
python&amp;MongoDB爬取图书馆借阅记录
Feb 05 Python
Python常用知识点汇总
May 08 Python
Python实现修改IE注册表功能示例
May 10 Python
Python wxPython库Core组件BoxSizer用法示例
Sep 03 Python
Python+selenium 获取浏览器窗口坐标、句柄的方法
Oct 14 Python
python实现停车管理系统
Nov 30 Python
Python进程池Pool应用实例分析
Nov 27 Python
解决pycharm中导入自己写的.py函数出错问题
Feb 12 Python
想学画画?python满足你!
Dec 24 Python
python保存图片的四个常用方法
Feb 28 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
手把手教你使用DedeCms V3的在线采集图文教程
2007/04/03 PHP
在Mac OS上搭建Nginx+PHP+MySQL开发环境的教程
2015/12/21 PHP
详解php魔术方法(Magic methods)的使用方法
2016/02/14 PHP
js 获取浏览器版本以此来调整CSS的样式
2014/06/03 Javascript
JQEasy-ui在IE9以下版本中二次加载的问题分析及处理方法
2014/06/23 Javascript
兼容最新firefox、chrome和IE的javascript图片预览实现代码
2014/08/08 Javascript
javascript解析json实例详解
2014/11/05 Javascript
JS限制文本框只能输入数字和字母方法
2015/02/28 Javascript
jQuery层动画定位滑动效果的方法
2015/04/30 Javascript
基于javascript实现图片滑动效果
2016/05/07 Javascript
基于BootStrap Metronic开发框架经验小结【四】Bootstrap图标的提取和利用
2016/05/12 Javascript
easyui-datagrid特殊字符不能显示的处理方法
2017/04/12 Javascript
vue实现记事本功能
2019/06/26 Javascript
jquery使用echarts实现有向图可视化功能示例
2019/11/25 jQuery
python使用在线API查询IP对应的地理位置信息实例
2014/06/01 Python
python动态参数用法实例分析
2015/05/25 Python
尝试用最短的Python代码来实现服务器和代理服务器
2016/06/23 Python
Mac中升级Python2.7到Python3.5步骤详解
2017/04/27 Python
python读取与写入csv格式文件的示例代码
2017/12/16 Python
利用TensorFlow训练简单的二分类神经网络模型的方法
2018/03/05 Python
Python zip()函数用法实例分析
2018/03/17 Python
解决已经安装requests,却依然提示No module named requests问题
2018/05/18 Python
python将秒数转化为时间格式的实例
2018/09/16 Python
python启动应用程序和终止应用程序的方法
2019/06/28 Python
python使用配置文件过程详解
2019/12/28 Python
英国一家集合了众多有才华设计师品牌的奢侈店:Wolf & Badger
2018/04/18 全球购物
东南亚排名第一的服务市场:kaodim
2019/03/28 全球购物
数据库面试要点基本概念
2013/10/31 面试题
我们在web应用开发过程中经常遇到输出某种编码的字符,如iso8859-1等,如何输出一个某种编码的字符串?
2014/03/30 面试题
开业庆典邀请函
2014/01/08 职场文书
先进党支部事迹材料
2014/01/13 职场文书
趣味游戏活动方案
2014/02/07 职场文书
司法所长先进事迹
2014/06/02 职场文书
幼儿园感恩节活动方案2014
2014/10/11 职场文书
2019年警察入党转正申请书最新范文
2019/09/03 职场文书
Go使用协程交替打印字符
2021/04/29 Golang