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

什么是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 可以使用类和类的实例调用。但是不依赖于类和类的实例的状态。
(0)

相关推荐

  • python下函数参数的传递(参数带星号的说明)

    函数参数的使用又有俩个方面值得注意:1.函数参数是如何定义的 2.在调用函数的过程中参数是如何被解析 先看第一个问题,在python中函数参数的定义主要有四种方式: 1.F(arg1,arg2,...) 这 是最常见的定义方式,一个函数可以定义任意个参数,每个参数间用逗号分割,用这种方式定义的函数在调用的的时候也必须在函数名后的小括号里提供个数相等的 值(实际参数),而且顺序必须相同,也就是说在这种调用方式中,形参和实参的个数必须一致,而且必须一一对应,也就是说第一个形参对应这第一个实参.例 如

  • Python def函数的定义、使用及参数传递实现代码

    Python编程中对于某些需要重复调用的程序,可以使用函数进行定义,基本形式为: def 函数名(参数1, 参数2, --, 参数N): 执行语句函数名为调用的表示名,参数则是传入的参数,可以更具需要定义,也可以没有. # 例1:简单的函数使用 # coding=gb2312 # 定义函数 def hello(): print 'hello python!' # 调用函数 hello() >>> hello python! 函数可以带参数和返回值,参数将按从左到右的匹配,参数可设置默认值

  • 跟老齐学Python之总结参数的传递

    就前面所讲,函数的基本内容已经完毕.但是,函数还有很多值得不断玩味的细节.这里进行阐述. 参数的传递 python中函数的参数通过赋值的方式来传递引用对象.下面总结通过总结常见的函数参数定义方式,来理解参数传递的流程. def foo(p1,p2,p3,...) 这种方式最常见了,列出有限个数的参数,并且彼此之间用逗号隔开.在调用函数的时候,按照顺序以此对参数进行赋值,特备注意的是,参数的名字不重要,重要的是位置.而且,必须数量一致,一一对应.第一个对象(可能是数值.字符串等等)对应第一个参数,

  • Python中函数的参数传递与可变长参数介绍

    1.Python中也有像C++一样的默认缺省函数 复制代码 代码如下: def foo(text,num=0):     print text,num foo("asd")  #asd 0 foo("def",100)  #def 100 定义有默认参数的函数时,这些默认值参数 位置必须都在非默认值参数后面. 调用时提供默认值参数值时,使用提供的值,否则使用默认值. 2.Python可以根据参数名传参数 复制代码 代码如下: def foo(ip,port):   

  • python黑魔法之参数传递

    我们都听说,python世界里面,万物皆对象. 怎么说万物皆对象呢?最常见的: > class A: pass > a = A() 我们说a是一个对象. 那么既然是万物了,其实A也是对象.3 也是对象.True 也是对象."hello" 也是对象. > def Func(): pass o~yee, Func 也是对象. 那么对象之间的传递是如何呢?我们看看下面两个简单的例子: > a = 3 > b = a > b = 3 + 1 > pri

  • python进阶教程之函数参数的多种传递方法

    我们已经接触过函数(function)的参数(arguments)传递.当时我们根据位置,传递对应的参数.我们将接触更多的参数传递方式. 回忆一下位置传递: 复制代码 代码如下: def f(a,b,c):     return a+b+c print(f(1,2,3)) 在调用f时,1,2,3根据位置分别传递给了a,b,c. 关键字传递 有些情况下,用位置传递会感觉比较死板.关键字(keyword)传递是根据每个参数的名字传递参数.关键字并不用遵守位置的对应关系.依然沿用上面f的定义,更改调用

  • Python函数可变参数定义及其参数传递方式实例详解

    本文实例讲述了Python函数可变参数定义及其参数传递方式.分享给大家供大家参考.具体分析如下: python中 函数不定参数的定义形式如下: 1.func(*args) 传入的参数为以元组形式存在args中,如: def func(*args): print args >>> func(1,2,3) (1, 2, 3) >>> func(*[1,2,3]) #这个方式可以直接将一个列表的所有元素当作不定参数 传入(1, 2, 3) 2.func( **kwargs)

  • python传递参数方式小结

    本文实例总结了python传递参数方式.分享给大家供大家参考.具体分析如下: 当形参如*arg时表示传入数组,当形参如**args时表示传入字典. def myprint(*commends,**map): for comm in commends: print comm for key in map.keys(): print key,map[key] myprint("hello","word",username="tian",name=&q

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

    什么是method? function就是可以通过名字可以调用的一段代码,我们可以传参数进去,得到返回值.所有的参数都是明确的传递过去的. method是function与对象的结合.我们调用一个方法的时候,有些参数是隐含的传递过去的.下文会详细介绍. instancemethod In [5]: class Human(object): ...: def __init__(self, weight): ...: self.weight = weight ...: def get_weight(

  • 浅谈Python中函数的参数传递

    1.普通的参数传递 >>> def add(a,b): return a+b >>> print add(1,2) 3 >>> print add('abc','123') abc123 2.参数个数可选,参数有默认值的传递 >>> def myjoin(string,sep='_'): return sep.join(string) >>> myjoin('Test') 'T_e_s_t' >>>

  • 实例分析javascript中的异步

    js 异步解析 一 .js单线程分析 我们都知道js的一大特点是单线程,也就是同一时间点,只能处理一件事,一句js代码.那为什么js要设计成单线程而不是多线程呢?这主要和js的用途有关,js作为浏览器端的脚本语言,主要的用途为用户与服务端的交互与操作dom.而操作dom就注定了js只能是单线程语言.假如js才取多线程将会出现,多个线程同时对一个dom进行操作的情况,浏览器将无法判断如何渲染.不仅js是单线程,浏览器渲染dom也是单线程的,js的执行和浏览器渲染dom共用的一个线程,这就导致了在h

  • 实例解析Python中的__new__特殊方法

    __new__ 方法是什么? 如果将类比喻为工厂,那么__init__()方法则是该工厂的生产工人,__init__()方法接受的初始化参 数则是生产所需原料,__init__()方法会按照方法中的语句负责将原料加工成实例以供工厂出货.而 __new__()则是生产部经理,__new__()方法可以决定是否将原料提供给该生产部工人,同时它还决定着出 货产品是否为该生产部的产品,因为这名经理可以借该工厂的名义向客户出售完全不是该工厂的产品. __new__()方法的特性: 1.__new__()方

  • 实例分析浏览器中“JavaScript解析器”的工作原理

    浏览器在读取HTML文件的时候,只有当遇到<script>标签的时候,才会唤醒所谓的"JavaScript解析器"开始工作. JavaScript解析器工作步骤: 1."找一些东西": var. function. 参数:(也被称之为预解析) 备注:如果遇到重名分为以下两种情况: 遇到变量和函数重名了,只留下函数 遇到函数重名了,根据代码的上下文顺序,留下最后一个 2.逐行解读代码. 备注:表达式可以修改预解析的值 JS解析器在执行第一步预解析的时候,会

  • 实例讲解Python中的私有属性

    在Python中可以通过在属性变量名前加上双下划线定义属性为私有属性,如例子: 复制代码 代码如下: #! encoding=UTF-8   class A:     def __init__(self):                  # 定义私有属性         self.__name = "wangwu"                  # 普通属性定义         self.age = 19          a = A()   # 正常输出 print a.ag

  • 实例讲解Python中global语句下全局变量的值的修改

    Python的全局变量:int string, list, dic(map) 如果存在global就能够修改它的值.而不管这个global是否是存在于if中,也不管这个if是否能够执行到. 但是,如果没有 if bGlobal: global g_strVal; int string 将会报错.而list dic(map)是ok的. #!/usr/bin/dev python import sys import os g_nVal = 0; g_strVal = "aaaa"; g_m

  • 实例讲解Python中整数的最大值输出

    在Python中可以存储很大的值,如下面的Python示例程序: x = 10000000000000000000000000000000000000000000; x = x + 1 print (x) 输出: 10000000000000000000000000000000000000000001 在Python中,整数的值不受位数的限制,可以扩展到可用内存的限制.因此,我们永远不需要任何特殊的安排来存储大数字(想象一下在C / C ++中进行上述算术). 在Python 3中,对于所有类型

  • 实例介绍Python中整型

    Python中有以下几个基本的数据类型: 整数 int 字符串 str 浮点数 float 集合 set 列表 list 元组 tuple 字典 dict 布尔类型 bool 日期 date 其中可变数据类型有:list(列表).dict(字典).set(集合): 不可变数据类型有:int(整型).float(浮点型).str(字符串).bool(布尔类型).tuple(元组): 什么可变对象及不可变对象? 不可变对象:就是说该对象所指向的内存中的值不能被改变.当改变某个变量时候,由于其所指的值

随机推荐