【发布时间】:2019-11-27 14:53:30
【问题描述】:
在 cpython 中这段代码可以工作:
import inspect
from types import FunctionType
def f(a, b): # line 5
print(a, b)
f_clone = FunctionType(
f.__code__,
f.__globals__,
closure=f.__closure__,
name=f.__name__
)
f_clone.__annotations__ = {'a': int, 'b': int}
f_clone.__defaults__ = (1, 2)
print(inspect.signature(f_clone)) # (a: int = 1, b: int = 2)
print(inspect.signature(f)) # (a, b)
f_clone() # 1 2
f(1, 2) # 1 2
try:
f()
except TypeError as e:
print(e) # f() missing 2 required positional arguments: 'a' and 'b'
但是在 cython 中调用 f_clone 时,我得到:
XXX lineno: 5, opcode: 0
Traceback (most recent call last):
...
File "test.py", line 5, in f # line of f definitio
SystemError: unknown opcode
我需要这个来在每个类创建时创建类__init__ 方法的副本并修改其签名,但保持原始__init__ 签名不变。
编辑: 对复制对象的签名所做的更改不得影响运行时调用,并且仅用于检查目的。
【问题讨论】:
-
我认为这可能行不通。 Cython 函数类型与
types.FunctionType不同。__code__在很大程度上是一个虚拟对象,只是为了给它一个属性。更改__defaults__看起来不会影响调用的函数。我建议你要么放弃 Cython 来做这个程序,要么着眼于寻找一种截然不同的方法来实现这个功能(继承?创建一个委托给__init__的新函数?) -
实际上,我不希望更改影响运行时的函数调用。只需按原样复制它并声明指向假类型函数的
__wrapped__属性。该部分有效,但无法再调用复制的函数 -
您可能想查看问题的原始上下文:github.com/samuelcolvin/pydantic/pull/1034
-
这里有些奇怪,因为内置函数(以及 Cython 生成的 def-functions 被视为这样)没有
__code__,所以你应该无法创建f_clone.但我不确定以上是否适用于所有版本的 Python/Cython 版本 - 所以也许你应该分享你如何构建扩展以及你使用的版本。 -
@ead 带有 Cython 选项
binding=True它们是具有大多数正确属性的对象(尽管__code__是一个虚拟对象等)。我认为这个选项很快就会成为默认选项。我假设 OP 正在使用它(否则它会更早中断,如你所说)。然而,没有属性的“旧” Cython 版本可能也是他们必须处理的事情
标签: python metaprogramming cython opcode