23.绑定方法和非绑定方法

 

 

 

 

绑定和方法调用

1、首先,方法仅仅是类内部定义的函数。(这意味着方法是类属性而不是实例属性)
2、其次,方法只有在其所属的类拥有实例时,才能被调用。当存在一个实例时,方法才被认为是绑定到那个实例了。没有实例时方法就是未绑定的
3、最后,任何一个方法定义中的第一个参数都是变量 self,它表示调用此方法的实例对象

 

 

 

核心笔记:self 是什么?

1、self 变量用于在类实例方法中引用方法所绑定的实例。

2、因为方法的实例在任何方法调用中总是作为第一个参数传递的,self 被选中用来代表实例。

3、你必须在方法声明中放上 self(你可能已经注意到了这点),但可以在方法中不使用实例(self)。

4、如果你的方法中没有用到 self , 那么请考虑创建一个常规函数,除非你有特别的原因。

5、毕竟,你的方法代码没有使用实例,没有与类关联其功能,这使得它看起来更像一个常规函数

某个对象调用其方法时,python解释器会把这个对象作为第一个参数传递给self,所以开发者只需要传递后面的参数即可

 

 

Bound Method和Unbound Method

 

在Python中,当对作为属性的函数进行引用时,会有两种形式,一种称为Bound Method,这种形式是通过类的实例对象进行属性引用,而另一种则是通过类进行属性引用,称为Unbound Method

 

例子:

#!/usr/bin/env python
#coding:utf8


class A(object):
    def g(self, value):
        self.value = value
        print(self.value)


a = A()
A.g(a, 10)

 

 

在Python中,在对Unbound Method尽心调用时,我们必须显示地提供一个instance对象作为函数的第一个位置参数,因为g无论如何都需要一个self参数。所以才会有A.g(a, 10)这样的形式。而无论是对Unbound Method进行调用,还是对bound Method进行调用,Python虚拟机的动作在本质上都是一样的,都是调用带位置参数的一般函数,区别只在于:当调用Bound Method时,Python虚拟机帮我们完成了PyFunctionObject对象和instance对象的绑定,instance对象将自动成为self参数,而调用Unbound Method时,则没有这个绑定,需要我们自己传入self参数

 

 

bound和unbound方法是个很简单的概念。在许多语言当中,类似于a.b()这样的调用方法是一个整体,但在Python中,它其实是两部分:获取属性a.b,调用()。所以也可以写成:

c = a.b
c()

 

跟直接调用a.b()是等效的。当a是某个类的实例,b是这个类的方法的时候,a.b的返回值就是bound method,也就是绑定方法。它实际上是个bound method对象,这个对象提前将self参数进行了绑定。实际演示一下就很容易懂了:

例如:在python2中

#!/usr/bin/env python
#coding:utf8


class A(object):
    def b(self):
        pass

a = A()
print a.b
print A.b

 

执行结果:

<bound method A.b of <__main__.A object at 0x00000000031534E0>>
<unbound method A.b>

在python3中:

#!/usr/bin/env python
#coding:utf8


class A(object):
    def b(self):
        pass

a = A()
print(a.b)
print(A.b)

 

执行结果:

<bound method A.b of <__main__.A object at 0x0000028D2613C320>>
<function A.b at 0x0000028D2620B8C8>

 

相应的unbound method是没有绑定self的对象。在Python 3中,它就是普通的函数,在Python 2中则是unbound method类型,不过区别不大。
我们知道像A.b这样的方法实际上跟一个普通定义的函数没有本质区别,这个函数有一个参数self,所以实际上完全可以用A.b(a)的方式来调用,也就是手工将self参数指定为a。这也就是unbound method的用法。而相应的,bound method是一个实现了__call__的对象,它自动将调用这个对象的过程重定向到A.b(a)上面,相当于通过functools.partial绑定了第一个参数的效果,所以叫做bound method。


我们可以认为:当通过类来获取方法的时候,得到的是非绑定方法对象;当通过实例来获取方法的时候,得到的是绑定方法对象

 

 

 

 

调用绑定方法和非绑定方法

 

方法只有在其所属的类拥有实例时,才能被调用。当存在一个实例时,方法才被认为是绑定到那个实例了。没有实例时方法就是未绑定的。当没有实例并且需要调用一个非绑定方法的时候,则必须传递self 参数。
调用非绑定方法并不经常用到,主要应用场景:你在派生一个子类 ,而且你要覆盖父类的方法,这时你需要调用哪个父类中想要覆盖的构造方法。

 

 

 例子:调用非绑定方法

 

 

#!/usr/bin/env python
#coding:utf8


class Foo(object):
    def __init__(self,name,sex,age):
        self.name=name
        self.sex=sex
        self.age=age
    def show(self):
        print "name is %s,sex is %s"%(self.name,self.sex)

class Bar(Foo):
    def __init__(self,name,sex,age,id,salary):
        super(Bar,self).__init__(name,sex,age) #这就是在调用父类非绑定方法
        #或者Foo.__init__(self,name,sex,age)  现在不用了
        self.id=id
        self.salary=salary

    def info(self):
        print "name is %s salary is %s"%(self.name,self.salary)

f = Bar('cmustard', 'F', 22, 123123, 1000)
f.show()
f.info()

 

使用super()的漂亮之处在于,不需要明确提供父类。这意味着如果改变了类继承关系,只需要改一行代码(class 语句本身)而不必在大量代码中去查找所有被修改的那个类的名字。

 

执行结果:

name is cmustard,sex is F
name is cmustard salary is 1000

 

Bar是Foo子类,我们重载了构造器__init__()

我们通过父类名来调用它,并且传递给它 self 和其他所需要的参数。一旦调用返回,我们就能定义那些与父类不同的仅存在我们的子类中的实例定制 。

 

链接:https://www.zhihu.com/question/41006598/answer/148994582
https://www.cnblogs.com/cmustard/p/6769933.html

 

posted @ 2019-06-18 23:51  钟桂耀  阅读(153)  评论(0编辑  收藏  举报