如何创建新的闭包对象?
How to create new closure cell objects?
我需要对我的库进行 monkey-patch 以替换一个符号的实例,它正被一些函数闭包引用。我需要复制这些函数(因为我也需要访问该函数的原始未修补版本),但是 __closure__
是不可变的,我不能 copy.copy
它,所以我如何创建新的Python 2.7?
中的闭包单元对象
例如我给出了这个函数
def f():
def incorrectfunction():
return 0
def g():
return incorrectfunction()
return g
def correctfunction():
return 42
func = f()
patched_func = patchit(f) # replace "incorrectfunction"
print func(), patched_func()
而且我想看
0, 42
制作闭包单元格的简单方法是制作闭包:
def make_cell(val=None):
x = val
def closure():
return x
return closure.__closure__[0]
如果您想重新分配现有单元格的内容,您需要进行 C API 调用:
import ctypes
PyCell_Set = ctypes.pythonapi.PyCell_Set
# ctypes.pythonapi functions need to have argtypes and restype set manually
PyCell_Set.argtypes = (ctypes.py_object, ctypes.py_object)
# restype actually defaults to c_int here, but we might as well be explicit
PyCell_Set.restype = ctypes.c_int
PyCell_Set(cell, new_value)
当然只有 CPython。
在 lambda 中:
def make_cell(value):
fn = (lambda x: lambda: x)(value)
return fn.__closure__[0]
从https://github.com/nedbat/byterun/blob/master/byterun/pyobj.py#L12
得到了答案
如果你想要一个空单元格(这就是我发现这个问题的原因)(引用它会引发 NameError: free variable '...' referenced before assignment in enclosing scope
并访问它的 cell.cell_contents
会引发 ValueError: Cell is empty
),你可以使一个值成为一个局部变量,但永远不要让它被赋值:
def make_empty_cell():
if False:
# Any action that makes `value` local to `make_empty_cell`
del value
return (lambda: value).__closure__[0]
你可以这样组合它们:
_SENTINEL = object()
def make_cell(value=_SENTINEL):
if value is not _SENTINEL:
x = value
return (lambda: x).__closure__[0]
因此不带参数调用 returns 一个空单元格,并使用任何值调用具有该值的单元格。
如果你不关心空单元格,你可以这样做:
def make_cell(value):
return (lambda: value).__closure__[0]
请注意,它在旧的 Python 2 中是 func_closure
,而不是 __closure__
。
我需要对我的库进行 monkey-patch 以替换一个符号的实例,它正被一些函数闭包引用。我需要复制这些函数(因为我也需要访问该函数的原始未修补版本),但是 __closure__
是不可变的,我不能 copy.copy
它,所以我如何创建新的Python 2.7?
例如我给出了这个函数
def f():
def incorrectfunction():
return 0
def g():
return incorrectfunction()
return g
def correctfunction():
return 42
func = f()
patched_func = patchit(f) # replace "incorrectfunction"
print func(), patched_func()
而且我想看
0, 42
制作闭包单元格的简单方法是制作闭包:
def make_cell(val=None):
x = val
def closure():
return x
return closure.__closure__[0]
如果您想重新分配现有单元格的内容,您需要进行 C API 调用:
import ctypes
PyCell_Set = ctypes.pythonapi.PyCell_Set
# ctypes.pythonapi functions need to have argtypes and restype set manually
PyCell_Set.argtypes = (ctypes.py_object, ctypes.py_object)
# restype actually defaults to c_int here, but we might as well be explicit
PyCell_Set.restype = ctypes.c_int
PyCell_Set(cell, new_value)
当然只有 CPython。
在 lambda 中:
def make_cell(value):
fn = (lambda x: lambda: x)(value)
return fn.__closure__[0]
从https://github.com/nedbat/byterun/blob/master/byterun/pyobj.py#L12
得到了答案如果你想要一个空单元格(这就是我发现这个问题的原因)(引用它会引发 NameError: free variable '...' referenced before assignment in enclosing scope
并访问它的 cell.cell_contents
会引发 ValueError: Cell is empty
),你可以使一个值成为一个局部变量,但永远不要让它被赋值:
def make_empty_cell():
if False:
# Any action that makes `value` local to `make_empty_cell`
del value
return (lambda: value).__closure__[0]
你可以这样组合它们:
_SENTINEL = object()
def make_cell(value=_SENTINEL):
if value is not _SENTINEL:
x = value
return (lambda: x).__closure__[0]
因此不带参数调用 returns 一个空单元格,并使用任何值调用具有该值的单元格。
如果你不关心空单元格,你可以这样做:
def make_cell(value):
return (lambda: value).__closure__[0]
请注意,它在旧的 Python 2 中是 func_closure
,而不是 __closure__
。