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>
我们知道像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.cnblogs.com/cmustard/p/6769933.html