gpt4 book ai didi

python - 将内置函数类型转换为方法类型(在 Python 3 中)

转载 作者:太空狗 更新时间:2023-10-29 16:58:19 26 4
gpt4 key购买 nike

考虑一个像这样的简单函数

def increment(self):
self.count += 1

它通过 Cython 运行并编译成扩展模块。假设现在我想让这个函数成为类的一个方法。例如:

class Counter:
def __init__(self):
self.count = 0

from compiled_extension import increment
Counter.increment = increment

现在这行不通了,因为 C 级别的调用约定将被打破。例如:

>>> c = Counter()
>>> c.increment()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: increment() takes exactly one argument (0 given)

但在 Python 2 中,我们可以通过以下方式将函数转换为未绑定(bind)方法:

Counter.increment = types.MethodType(increment, None, Counter)

我如何在 Python 3 中完成同样的事情?

一种简单的方法是使用纤细的包装器:

from functools import wraps
def method_wraper(f):
def wrapper(*args, **kwargs):
return f(*args, **kwargs)
return wraps(f)(wrapper)

Counter.increment = method_wrapper(increment)

有没有更有效的方法呢?

最佳答案

首先是正确获取名称:

>>> def increment(obj):
... obj.count += 1
...
>>> class A(object):
... def __init__(self):
... self.count = 0
...
>>> o = A()
>>> o.__init__
<bound method A.__init__ of <__main__.A object at 0x0000000002766EF0>>
>>> increment
<function increment at 0x00000000027797C8>

所以专有名称是函数绑定(bind)方法。现在您可以查看如何 Bind an Unbound Method你可能最终会读到关于 descriptors 的内容:

In general, a descriptor is an object attribute with "binding behavior", one whose attribute access has been overridden by methods in the descriptor protocol. Those methods are __get__, __set__, and __delete__. If any of those methods are defined for an object, it is said to be a descriptor.

只需使用不同的 __get__ 调用,您就可以轻松地将函数转换为方法

>>> increment.__get__(None, type(None))
<function increment at 0x00000000027797C8>
>>> increment.__get__(o, type(o))
<bound method A.increment of <__main__.A object at 0x00000000027669B0>>

它就像一个魅力:

>>> o = A()
>>> increment.__get__(None, type(None))(o)
>>> o.count
1
>>> increment.__get__(o, type(o))()
>>> o.count
2

您可以轻松地将这些新绑定(bind)的方法添加到对象:

def increment(obj):
obj.count += 1

def addition(obj, number):
obj.count += number

class A(object):
def __init__(self):
self.count = 0

o = A()
o.inc = increment.__get__(o)
o.add = addition.__get__(o)
print(o.count) # 0
o.inc()
print(o.count) # 1
o.add(5)
print(o.count) # 6

或者创建您自己的描述符,它将函数转换为绑定(bind)方法:

class BoundMethod(object):
def __init__(self, function):
self.function = function

def __get__(self, obj, objtype=None):
print('Getting', obj, objtype)
return self.function.__get__(obj, objtype)

class B(object):
def __init__(self):
self.count = 0

inc = BoundMethod(increment)
add = BoundMethod(addition)


o = B()
print(o.count) # 0
o.inc()
# Getting <__main__.B object at 0x0000000002677978> <class '__main__.B'>
print(o.count) # 1
o.add(5)
# Getting <__main__.B object at 0x0000000002677978> <class '__main__.B'>
print(o.count) # 6

而且您还可以看到这与 function/bound method principles 非常一致:

Class dictionaries store methods as functions. In a class definition, methods are written using def and lambda, the usual tools for creating functions. The only difference from regular functions is that the first argument is reserved for the object instance. By Python convention, the instance reference is called self but may be called this or any other variable name.

To support method calls, functions include the __get__() method for binding methods during attribute access. This means that all functions are non-data descriptors which return bound or unbound methods depending whether they are invoked from an object or a class.

并且函数在实例初始化期间成为绑定(bind)方法:

>>> B.add
# Getting None <class '__main__.B'>
<function addition at 0x00000000025859C8>
>>> o.add
# Getting <__main__.B object at 0x00000000030B1128> <class '__main__.B'>
<bound method B.addition of <__main__.B object at 0x00000000030B1128>>

关于python - 将内置函数类型转换为方法类型(在 Python 3 中),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10729909/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com