zoukankan      html  css  js  c++  java
  • 使用MethodType函数将方法绑定到类或实例上

    在开始正文之前,需要了解下Python的绑定方法(bound method)和非绑定方法。

    简单做个测试:

    定义一个类,类中由实例方法、静态方法和类方法。

    class ClassA:
    
        def instance_method(self):
            print('instance_method', self)
    
        @classmethod
        def cls_method(cls):
            print('cls_method', cls)
    
        @staticmethod
        def static_method():
            print('static_method')

    逐个测试,测试的结果在注释说说明。

        class_a = ClassA()
    
        print('测试实例方法、静态方法、类方法与实例和类的关系')
        # 类中的实例方法,与类本身并没有绑定关系
        # <function ClassA.instance_method at 0x0000022744592488>
        print(ClassA.instance_method)
        # 类中的静态方法,与类也没有绑定关系
        # <function ClassA.static_method at 0x0000027A5F6D0598>
        print(ClassA.static_method)
        # 而类中的类方法,是和这个类存在绑定关系的
        # <bound method ClassA.cls_method of <class '__main__.ClassA'>>
        print(ClassA.cls_method)
    
        print('-' * 50)
    
        # 实例中的实例方法,与实例存在绑定关系
        # 因为当通过一个实例去访问类中的某方法时,会形成绑定关系,将实例作为第一个参数self传入。
        # <bound method ClassA.instance_method of <__main__.ClassA object at 0x000001B117D07710>>
        print(class_a.instance_method)
        # 类方法与实例也存在绑定关系,所以实例可以直接调用类方法
        # <bound method ClassA.cls_method of <class '__main__.ClassA'>>
        print(class_a.cls_method)
        # 静态方法与实例没有绑定关系
        # <function ClassA.static_method at 0x0000027D36340620>
        print(class_a.static_method)

    接着尝试把一个函数,绑定到类或者实例上。

    第一种方法,直接将函数赋值给类。

    # 创建实例 class_a
    class_a = ClassA()
    
    # 直接给类属性赋值
    ClassA.func_a = func_a
    
    # 输出结果,没有绑定关系
    #  <function func_a at 0x10e41ff28>
    print(ClassA.func_a)
    
    # 通过实例访问之前赋值的类属性
    # 对于赋值之前创建得实例,因为是通过实例访问,所以也会存在绑定关系
    # <bound method func_a of <__main__.ClassA object at 0x10e4330b8>>
    print(class_a.func_a)

    上面这种方法,存在一些局限性。比如把一个函数直接赋值给实例时,无法正常创建绑定关系。

    # 把函数赋值给实例
    class_a.func_c = func_c
    # 没有形成绑定关系
    # <function func_c at 0x10e59f1e0>
    print(class_a.func_c)

    所以,就需要引入MethodType,将一个可调用对象,这里是个函数,绑定到实例或类上,形成绑定关系。

    MethodType 会在类内部创建一个链接,指向外部的的可调用对象,在创建实例的同时,这个绑定后的方法也会复制到实例中。MethodType 接受两个参数,第一个是被绑定的可调用对象,第二个是需要绑定到的对象。

    class ClassB:
        pass
    
    class_b = ClassB()
    
    class_b.func_a = MethodType(func_a, class_b)
    
    print(class_b.func_a)
    # <bound method func_a of <__main__.ClassB object at 0x0000021706F6B780>>
    
    ClassB.func_b = MethodType(func_b, ClassB)
    print(ClassB.func_b)
    # <bound method func_b of <class '__main__.ClassB'>>

    经过代码测试,成功把函数绑定到了类和实例上。

    之前说过,MethodType只是一个链接指向外部可调用对象,而不是把外部可调用对象复制到类内部。

    关于这点,可以用一个闭包来验证。

    # 闭包
    def func_d(a):
        def _func_d(self, b):
            nonlocal a
            a = a + b
            print(a)
            print(self)
        return _func_d
    
    # a 初始值为1
    test_func_d = func_d(1)

    将闭包分别绑定到两个截然不同的类创建出的实例上

    class_a.test_func_d = MethodType(test_func_d, class_a)
    class_b.test_func_d = MethodType(test_func_d, class_b)

    两个不同的实例的test_func_d,实际上是指向同一个函数。

    分别调用两个实例的test_func_d方法,得到3、6两个结果。

    class_a.test_func_d(2)
    # 3
    class_b.test_func_d(3)
    # 6

    第一次执行class_a.test_func_d(1)时,闭包中的变量 a 已经由 1 变为 1+2=3,第二次执行class_b.test_func_d(3)时,闭包中的变量 a 已经由 3 变为 3+3=6。

    可见两个实例执行的是同一个函数,共享闭包内的变量a,所以说是创建一个链接,指向函数,而不是把函数复制到类内部。

  • 相关阅读:
    Knockout.Js官网学习(模版绑定)
    Knockout.Js官网学习Demo(使用VS2012或者VS2013均可打开)
    Knockout.Js官网学习(Mapping高级用法一)
    Knockout.Js官网学习(Mapping高级用法二)
    Knockout.Js官网学习(Mapping插件)
    Knockout.Js官网学习(加载或保存JSON数据)
    Knockout.Js官网学习(创建自定义绑定)
    Knockout.Js官网学习(selectedOptions绑定、uniqueName 绑定)
    Knockout.Js官网学习(options绑定)
    Knockout.Js官网学习(checked 绑定)
  • 原文地址:https://www.cnblogs.com/blackmatrix/p/7100889.html
Copyright © 2011-2022 走看看