解释器或编译器上下文中的单元是什么?

问题描述

Python 代码对象有一个属性 co_cellvars.PyPy 的字节码解释器的文档经常使用术语细胞.

Python code objects have an attribute co_cellvars. The documentation to PyPy's bytecode interpreter often uses the term Cell.

在其他语言中,Rust 提供 Cell 数据类型.谷歌搜索表明它们以某种方式与闭包有关.

Among other langauges, Rust provides a Cell datatype. Googling suggests they relate to closures somehow.

在编程语言实现的上下文中,cell 是什么?细胞解决了什么问题?

What is a cell, in the context of a programming language implementation? What problem do cells solve?


解决方案

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

In Python, cell objects are used to store the free variables of a closure.

假设您想要一个始终返回其参数的特定部分的函数.您可以使用闭包来实现:

Let's say you want a function that always returns a particular fraction of its argument. You can use a closure to achieve this:

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 函数的参数,它们不是在 multiply 中定义的局部变量,它们不是全局变量,而且由于 multiplier 已经终止了,它的局部变量已经不存在了,对吧?

How does two_thirds remember the values of n and d? They aren't arguments to the multiply function that multiplier defined, they aren't local variables defined inside multiply, they aren't globals, and since multiplier has already terminated, its local variables no longer exist, right?

multiplier 被编译时,解释器注意到 multiply 稍后将要使用它的局部变量,所以它会记下它们:

What happens is that when multiplier is compiled, the interpreter notices that multiply is going to want to use its local variables later, so it keeps a note of them:

>>> multiplier.__code__.co_cellvars
('d', 'n')

然后当 multiplier 被调用时,那些外部局部变量的值被存储在返回函数的 __closure__ 属性中,作为 cell 对象:

Then when multiplier is called, the value of those outer local variables is stored in the returned function's __closure__ attribute, as a tuple of cell objects:

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

... __code__ 对象中的名称为 co_freevars:

... with their names in the __code__ object as co_freevars:

>>> two_thirds.__code__.co_freevars
('d', 'n')

您可以使用单元格的 cell_contents 属性获取单元格的内容:

You can get at the contents of the cells using their cell_contents attribute:

>>> {v: c.cell_contents for v, c in zip(
        two_thirds.__code__.co_freevars,
        two_thirds.__closure__
)}
{'d': 3, 'n': 2}

您可以在介绍闭包的 Python 增强提案中阅读更多关于闭包及其实现的信息:PEP 227 — 静态嵌套作用域.

You can read more about closures and their implementation in the Python Enhancement Proposal which introduced them: PEP 227 — Statically Nested Scopes.

相关文章