python-3.x 如何使用类型.方法类型?

kmb7vmvb  于 2023-03-04  发布在  Python
关注(0)|答案(4)|浏览(166)

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来curry self
  • types.MethodType(self, obj)如何创建和返回types.MethodType的示例?

谢谢。

v1uwarro

v1uwarro1#

通常你不需要自己创建types.MethodType的示例,相反,当你访问类示例的方法时,你会自动得到一个示例。
例如,如果我们创建一个类,创建它的一个示例,然后访问示例上的一个方法(不调用它),我们将得到types.MethodType的一个示例:

import types

class Foo:
    def bar(self):
        pass

foo = Foo()

method = foo.bar

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

你在问题中摘录的代码试图展示这通常是如何发生的。这不是你通常必须自己做的事情,尽管如果你真的想做的话,你可以做。例如,要创建另一个等价于上面methodtypes.MethodType的示例,我们可以这样做:

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")。

bbmckpt7

bbmckpt72#

简短回答:

types.MethodType的第一个参数self是否必须是可调用对象?换句话说,类Function是否必须是可调用类型,即Function是否必须具有方法__call__
是的
如果self是一个可调用对象,它是否至少需要一个参数?
取决于
types.MethodType(self,obj)是否意味着将obj作为可调用对象self的第一个参数,即用obj来修饰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中,它是这样工作的:
Function具有object时,types.MethodType()可以正常工作。
if obj is None应该是False
那么它是某个对象的方法,也就是绑定方法。
它解释了Python语法是如何工作的。作为一个函数,它可以通过以下两种方式调用。
some_func_()some_class.some_func()
前一部分www.example.com解释。https://docs.python.org/3.6/howto/descriptor.html#invoking-descriptors explained.
对于对象,机器在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"

pwuypxnk

pwuypxnk3#

文档没有说明太多,但是你可以随时查看它的源代码,MethodType构造函数的签名是:

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

它接受可调用对象和对象,并返回None。
MethodType可用于向对象添加示例方法,而不是函数;下面是一个例子:

from types import MethodType

class MyClass:
    language = 'Python'

def target_function(self):
    print(f'Hello {self.language}!')

# the function is not bound to the object, this is just an assignment
obj1 = MyClass()
obj1.say_hello = target_function
print('assignment:', type(obj1.say_hello))  # type is class 'function'
try:
    obj1.say_hello()
except Exception as e:
    print('exception:', str(e))

# a function is bound to obj2 and becomes a method
obj2 = MyClass()
# this is used to bind a function and make it a "method" to a specific object obj2
obj2.say_hello = MethodType(target_function, obj2)
print('MethodType:', type(obj2.say_hello))  # type is class 'method'
obj2.say_hello()
juud5qan

juud5qan4#

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

相关问题