python中的回调和关于首参数的绑定的说法 !!-阿里云开发者社区

开发者社区> qun 634492606> 正文

python中的回调和关于首参数的绑定的说法 !!

简介: 函数参数的绑定和调用方式 这里想讨论的问题是,如果把python的方法作为参数传递给其他对象调用,那么相应的python实例是如何绑定的? class C: def callback(self): print('callback') @staticmethod .
+关注继续查看

函数参数的绑定和调用方式

这里想讨论的问题是,如果把python的方法作为参数传递给其他对象调用,那么相应的python实例是如何绑定的?

class C:
    def callback(self):
        print('callback')

    @staticmethod
    def sc():
        print('sc')

    @classmethod
    def cc(cls):
        print('cc')

def f():
    print('f')

def f_with_1_parameter(param):
    print(param)

def do_something(cb):
    print('do something')
    cb()

if __name__ == '__main__':
    instance = C()
    # 它们绑定的是谁?
    do_something(instance.callback)
    do_something(C.sc)
    do_something(C.cc)
    do_something(f)
    do_something(instance.f_with_1_parameter)
    do_something(C.f_with_1_parameter)

首参数绑定

python 有这样的约定,实例方法的第一个参数必然是self,名字可以不叫self,但是第一个参数总是调用方法的类实例。

类方法的第一个参数必然是cls,名字可以不叫cls,但是第一个参数总是调用该方法的类对象。

依照直觉,可以写出这样的代码 :


class C:
    @classmethod
    def class_method_1(cls):
        print('class method 1')

    def instance_method_1(self):
        print('instance method 1')

def do_something(cb):
    cb()

cb(C.class_method_1)
cb(C().instance_method_1)```
并且它们确实能很好地工作。

或许你们注意到了,C()创建了一个匿名的C类实例,然后将这个实例的instance_method_1交给了cb,这看起来是不安全的。

在C++中,相同的方法需要显式地将实例指针与实例方法绑定成一个函数对象。C++的实例方法确实是一个“函数”,它的this没有python的self那么魔幻。

直觉上感觉不安全,是因为 python 的对象是自动回收的,而且我们能看得出来:C()似乎没有引用了。

但其实不是,实例方法instance.method实际上已经绑定了instance和method,在实例方法也失去引用之前,instance不会被释放。

这也是为什么instance_method = instance.method后,instance_method()工作得和instance.method()一样好的原因:这是python的魔法,将实例和实例方法绑定在了一起。

![](https://yqfile.alicdn.com/fc1bfb301cd26b5df1dfdf2024f6e4e900856cb7.png)

**语法糖?**

那么这种绑定是不是语法糖呢...

我也不知道(诶嘿)。语言规范查阅起来太麻烦了,稍稍不求甚解一下,看看 CPython 这个官方的实现是怎么处理的吧。

**类.实例方法**

首先是第一问:实例方法如果用class.method的方式调用,self参数会绑定成类对象吗?

class C:

def method(self):
    print(self)

C.method()

输出是

Traceback (most recent call last):
File "打码:/打码/打码/打码/test.py", line 6, in

C.method()

TypeError: method() missing 1 required positional argument: 'self

看来并不会,class.method的方式并不会将class绑定为self传递给method,只有通过实例.方法的情况会绑定实例对象到self参数。

**实例.类方法**

class C:

@classmethod
def method(cls):
    print (cls)

instance = C()
instance.method()`
这次的结果比较神奇,因为它正常执行了。


<class '__main__.C'>```

并没有报错。

这应该是类似于原型链的机制在其中作祟:instance.class_field是可以正常访问的,不像是C++访问类变量时需要class::class_field这样的特殊语法。

classmethod 装饰器做的事情感觉像是给一个函数包了一层重载了__get__的类,然后这个包了__get__的descriptor打入另一个owner类里,可以参考下这篇文章Python3 Data Model。

做个具体的实例

def f(cls):

print(cls)

def C:

pass

C.f = classmethod(f)
C.f() # 正常执行 `
这应该是 classmethod装饰器实现的方式了(猜测)。

无论你是大牛还是小白,是想转行还是想入行都可以来了解一起进步一起学习!裙内有开发工具,很多干货和技术资料分享!

运行时改变类?
如果在运行时给类插入一个实例方法呢?如果插入的实例方法正常运作,说明这仅仅是一个语法糖:实例.方法会绑定self参数,仅此而已。


def f(self):
    print(self)

class C:
    pass

C.f = f
instance = C()
instance.f()```
输出是

<__main__.C object at 0x038262B0>

看起来没错了,这仅仅是一个语法糖。

**总结**
用实例.方法的形式访问到的其实是一个这样子的实例

class WhoCare:

def __init__(self, instance, method):
    """
    在调用 实例.方法时,实例.方法构成了这样的一个奇特对象

    当然了,别当真。只是为了说明这种语法背后做了什么的理解。
    """
    self._i=instance
    self._method=method

def __call__(self,*args,**kwargs):
    """
    反正固定了第一个 instance 参数,其他参数照样送进去就 ok
    """
    self._method(self._i, *args, **kwargs)```

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
9481 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
10841 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
13163 0
bboss mvc参数绑定注解RequestParam使用说明
bboss mvc参数绑定注解RequestParam使用说明 @RequestParam作为控制器方法参数、bean对象属性的注解,可以起到以下5个作用: 1.指定方法参数与request请求参数名称的映射关系 方法参数-当方法参数名称yournames和request参数名称name不...
707 0
elementUI table手动实现列宽改变数据绑定解决思路参考
element UI table文档:http://element-cn.eleme.io/#/zh-CN/component/table#table-events 根据文档我们发现可以通过header-dragend事件来获取列...
2605 0
浅析MicroPython系统底层回调机制
浅析MicroPython系统底层回调机制
98 0
SpringMVC自定义日期格式进行参数绑定
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.
556 0
42
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载