【问题标题】:How is types.MethodType used?types.MethodType 是如何使用的?
【发布时间】:2017-10-02 12:01:31
【问题描述】:

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)
  • types.MethodType 的第一个参数 self 必须是可调用对象吗?换句话说,Function 类必须是可调用类型,即Function 必须有方法__call__

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

  • types.MethodType(self, obj) 是否意味着将obj 作为可调用对象self 的第一个参数,即用obj 柯里化self

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

谢谢。

【问题讨论】:

标签: python python-3.x


【解决方案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()

【讨论】:

    【解决方案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 为前缀的变量的工作方式完全相同(当您调用它们时,它们都会以Foo2 作为cls 参数调用baz)。这次手动方法唯一的问题是,如果不使用绑定方法,很难获得原始的 baz 函数,所以我从其他绑定方法对象之一中找出了它。

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

    【讨论】:

      【解决方案3】:

      简答:

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

      是的

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

      视情况而定

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

      是的

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

      这样不行。


      长答案:

      代码

      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)
      

      正如丹尼尔解释的主要是为了演示

      为了支持方法调用,函数包括__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"

      【讨论】:

      • 我认为你最后两个“较短”的答案是完全错误的。绑定方法确实类似于currying,types.MethodType(self, obj)创建绑定方法是因为你调用的是带参数的类,就像list(something)创建列表,str(something)创建字符串一样。
      • 感谢您的评论。查看问题后,我发现我错过了ie. curring ... 部分。我会更新那部分。如果您同意types.MethodType(self, obj) create and return an instance of types.MethodType,您愿意提供一些演示代码吗?
      • 嗯,我不确定如何提供一个已经是示例的示例,如果您运行它(链接中的 Function 类文档旨在演示普通函数如何作为描述符表现,但它确实起作用)。如果您想要更简单的东西,请尝试m = types.MethodType(lambda self: print(self), [1, 2, 3])。变量m 将被分配一个可调用对象,当没有对象调用时打印列表[1, 2, 3]m 的类型是types.MethodType
      • 对不起,这里有 Python 2 和 Python 3。错误地使用了 Python 2。 &gt;&gt;&gt; m = types.MethodType(lambda self: print(self), [1,2,3]) &gt;&gt;&gt; type(m) &lt;class 'method'&gt; &gt;&gt;&gt; m &lt;bound method &lt;lambda&gt; of [1, 2, 3]&gt; 这很有启发性。
      【解决方案4】:

      这不是你会打电话的东西。与types 模块中的大多数类一样,它更多地用于与现有对象进行比较(例如在isinstance 中)。

      【讨论】:

      • 谢谢。您如何理解types.MethodType(self, obj) 的论点及其作用?
      • 我不明白你的问题。 MethodType 是一个类。该代码从函数__get__ 方法传递selfobj。但请再次注意,这不是真正的代码;正如评论所说,它只是模拟底层 C 实现为创建方法所做的工作。
      • 我只是尝试编辑我的问题以使其更清晰。
      • 不幸的是,他们仍然无法回答。 “self 是否接受参数” - 这取决于函数。 “它如何创建实例” - 就像任何其他类一样。但再一次,这段代码是虚构的,不是你会运行的。
      • MethodType 实际上除了比较之外确实有使用案例。例如,使用实例绑定生成动态类方法。见:stackoverflow.com/questions/14526652/…
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-11-05
      • 2015-05-04
      • 2014-07-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多