【发布时间】:2012-05-24 01:05:57
【问题描述】:
考虑一个简单的函数
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 中,我们可以通过以下方式将函数转换为未绑定的方法:
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)
有没有更有效的方法?
【问题讨论】:
-
我在尝试使用丑陋的
heapq模块构建 Heapq 类时遇到了这个问题。你的解决方案很好。可以一行完成,但效率相同:def method_wraper(f): return functools.wraps(f)(lambda *a, **kw: f(*a, **kw)) -
...有趣的是,如果函数是在同一个模块中定义的(未绑定的方法被分配给一个类并在实例化时绑定),那么分配似乎可以正常工作。所以这只是 C 扩展的问题,还是不同模块中的函数的问题?无论如何,您可能想查看stackoverflow.com/questions/7490879/…,这也可以帮助您一点。
-
另外,docs.python.org/py3k/howto/…“在 Objects/classobject.c 中 PyMethod_Type 的实际 C 实现是具有两种不同表示的单个对象,具体取决于 im_self 字段是否设置或为 NULL(C 等效于没有任何)。”这使得这个问题看起来根本不应该发生,除非 Python 在实例化对象时不直接为对象的方法更新该字段。
-
问题在于运行时对内置函数和 python 函数的处理方式不同,与位于不同的模块中无关。关于 PyMethod_Type 的评论并不真正适用,因为它代表了在 python 中定义的方法,而不是内置函数/方法。
-
不应该是“将函数转换为绑定方法”吗?
标签: python python-3.x cython