如何使用types.MethodType?

时间:2017-10-02 12:01:31

标签: python python-3.x

types.MethodType期望什么参数以及它返回什么?  https://docs.python.org/3.6/library/types.html没有详细说明:

types.MethodType
     

用户定义的类实例的方法类型。

例如,来自https://docs.python.org/3.6/howto/descriptor.html

  

为了支持方法调用,函数包括__get__()方法   属性访问期间的绑定方法。这意味着所有功能   是非数据描述符,它返回绑定或未绑定的方法   取决于它们是从对象还是类中调用的。在纯粹   python,它的工作原理如下:

class Function(object):
    . . .
    def __get__(self, obj, objtype=None):
        "Simulate func_descr_get() in Objects/funcobject.c"
        if obj is None:
            return self
        return types.MethodType(self, obj)
  • self的第一个参数types.MethodType必须是可调用对象吗?换句话说,班级Function必须是可调用类型,即必须Function方法__call__吗?

  • 如果self是可调用对象,是否需要至少一个参数?

  • types.MethodType(self, obj)是否意味着将obj作为可调用对象self的第一个参数,即将selfobj进行合并?

  • types.MethodType(self, obj)如何创建并返回types.MethodType的实例?

感谢。

4 个答案:

答案 0 :(得分:2)

通常,您不需要自己创建types.MethodType的实例。而是在访问类实例上的方法时会自动获得一个。

例如,如果我们创建一个类,创建它的一个实例,然后访问该实例上的一个方法(不调用它),我们将获得一个types.MethodType的实例:

import types

class Foo:
    def bar(self):
        pass

foo = Foo()

method = foo.bar

print(type(method) == types.MethodType) # prints True

您在问题中摘录的代码试图显示这种情况通常如何发生。尽管您可以可以,但通常不必自己做这件事。例如,要创建与上述types.MethodType等效的method的另一个实例,我们可以这样做:

method_manual = types.MethodType(Foo.bar, foo)

MethodType的第一个参数是可调用对象(通常是一个函数,但可以是其他东西,例如您正在阅读的示例中的Function类的实例)。第二个参数是我们将函数绑定到什么。当您调用方法对象(例如method())时,绑定的对象将作为第一个参数传递到函数中。

通常,方法绑定到的对象是一个实例,尽管它可以是其他实例。例如,一个装饰classmethod的函数将绑定到被调用的类,而不是实例。这是一个示例(自动将方法绑定到类,然后自己手动完成):

class Foo2:
    @classmethod
    def baz(cls):
        pass

foo2 = Foo2()

method2 = Foo2.baz
method2_via_an_instance = foo2.baz
method2_manual = types.MethodType(method2.__func__, Foo2)

所有三个method2前缀变量的工作方式完全相同(当您调用它们时,它们都将以baz作为Foo2参数调用cls )。这次关于手动方法的唯一不便之处是,如果没有获取绑定方法就很难获得原始的baz函数,因此我将其从其他绑定方法对象之一中剔除了。

最后一点:名称types.MethodType是用于绑定方法的内部类型的别名,否则它没有可访问的名称。与许多类不同,实例的repr不是重新创建实例的表达式(它类似于"<bound method Foo.bar of <__main__.Foo object at 0x0000...>>")。该类型的repr也不是访问该类型所依据的有效名称(repr"method")。

答案 1 :(得分:1)

简短答案:

  

types.MethodType的第一个参数self必须是可调用对象吗?   换句话说,Function类必须是可调用的类型,即must   函数有方法__call__吗?

  

如果self是一个可调用对象,它是否至少接受一个参数?

取决于

  

types.MethodType(self,obj)是否意味着将obj作为第一个参数   到可调用对象的self,即使用obj进行currying self?

  

types.MethodType(self,obj)如何创建并返回一个实例   类型。方法类型?

它不是那样工作的。


长答案:

代码

class Function(object):
    . . .
    def __get__(self, obj, objtype=None):
        "Simulate func_descr_get() in Objects/funcobject.c"
        if obj is None:
            return self
        return types.MethodType(self, obj)

如丹尼尔(Daniel)所说,主要是为了演示

  

为支持方法调用,函数包括__get__()方法,用于   属性访问期间的绑定方法。这意味着所有功能   是返回绑定或未绑定方法的非数据描述符   取决于是从对象还是从类调用它们。纯属   python,它是这样的:

types.MethodType()具有Function时,object起作用。
if obj is None将是False
这就是某种对象的方法。绑定方法。

它解释了Python语法如何工作。作为功​​能,可以在 以下两种方式。

some_func_()some_class.some_func()

https://docs.python.org/3.6/howto/descriptor.html#invoking-descriptors的前一部分已解释。

  

对于对象,机器位于object.__getattribute__()中   将b.x转换为type(b).__dict__['x'].__get__(b, type(b))。的   通过提供数据的优先级链来实现   描述符优先于实例变量,实例变量   优先于非数据描述符,并将最低优先级分配给   __getattr__()(如果提供)。

这是一些演示代码

>>> import types
>>> types.MethodType
<type 'instancemethod'>
>>> def a(self):
...     print(1)
... 
>>> class B:
...     pass
... 
>>> types.MethodType(a,B)
<bound method ?.a of <class __main__.B at 0x7f4d3d5aa598>>
>>> B.t = types.MethodType(a,B)
>>> B.t()
1
>>> def s():
...     print(3)
... 
>>> B.r = types.MethodType(s,B)
>>> B.r
<bound method ?.s of <class __main__.B at 0x7f4d3d5aa598>>
>>> B.r()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: s() takes no arguments (1 given)

另请参见dynamically adding callable to class as instance "method"

答案 2 :(得分:1)

文档说明不多,但您可以随时查看其源代码。 MethodType 构造函数的签名是:

def __init__(self, func: Callable[..., Any], obj: object) -> None: ...

它接受一个可调用对象和对象,并返回 None。

MethodType 可用于向对象添加实例方法,而不是函数;这是一个例子:

from types import MethodType


class MyClass:
    language = 'Python'


# a function is bound to obj1
obj1 = MyClass()
obj1.say_hello = lambda: 'Hello World!'
print(type(obj1.say_hello))  # type is class 'function'
obj1.say_hello()

# a method is bound to obj2
obj2 = MyClass()
# this is used to bind a "method" to a specific object obj2, rather than a function
obj2.say_hello = MethodType(lambda self: f'Hello {self.language}!', obj2)
print(type(obj2.say_hello))  # type is class 'method'
obj2.say_hello()

答案 3 :(得分:0)

这不是你打算过的东西。与types模块中的大多数类一样,它与现有对象的比较更多(例如在isinstance中)。