在解释器或编译器的上下文中,什么是“cell”?

13

1
在Rust中,Cell只是一种绕过继承的不可变性的方式,以便您可以修改数据,尽管对其具有不可变引用。这与Python的含义相当不同。 “Cell”是一个非常通用的术语,你知道的。 - Chris Morgan
@ChrisMorgan 看起来你对我提到的两个上下文中的 Cell 都很熟悉。您愿意提交一个答案吗? - Wilfred Hughes
我并不太熟悉 Python 代码对象表示的内部结构,但是我可以根据“cell”的含义进行猜测。 - Chris Morgan
1个回答

21

在Python中,cell对象用于存储自由变量,这些变量属于闭包

假设你想要一个函数,它总是返回其参数的特定分数。你可以使用闭包来实现:

def multiplier(n, d):
    """Return a function that multiplies its argument by n/d."""
    def multiply(x):
        """Multiply x by n/d."""
        return x * n / d
    return multiply

这是如何使用它的方法:

>>> two_thirds = multiplier(2, 3)
>>> two_thirds(7)
4.666666666666667
two_thirds如何记住nd的值?它们既不是multiplier函数的参数,也不是在multiply内部定义的局部变量,也不是全局变量,而且由于multiplier已经终止,它的局部变量也不存在了,对吗?
实际上,在编译multiplier时,解释器注意到multiply稍后要使用它的局部变量,因此它会记录下它们的值:
>>> multiplier.__code__.co_cellvars
('d', 'n')

当调用multiplier函数时,外部局部变量的值将存储在返回的函数的__closure__属性中,以cell对象的元组形式:

>>> two_thirds.__closure__
(<cell at 0x7f7a81282678: int object at 0x88ef60>,
 <cell at 0x7f7a81282738: int object at 0x88ef40>)

...使用__code__对象中的名称作为co_freevars

>>> two_thirds.__code__.co_freevars
('d', 'n')
您可以使用单元格的cell_contents属性获取其内容:
>>> {v: c.cell_contents for v, c in zip(
        two_thirds.__code__.co_freevars,
        two_thirds.__closure__
)}
{'d': 3, 'n': 2}

您可以在引入它们的Python Enhancement Proposal中了解有关闭包及其实现的更多信息:PEP 227 — Statically Nested Scopes


是否可能修改这些存储的变量中的一个来在创建后修改函数?(例如,d = 5) - Edward Garemo
@EdwardGaremo 是的,你可以这样做:c.cell_contents = 5。更一般的情况是:func.__closure__[func.__code__.co_freevars.index(name)].cell_contents = value - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接