编译后的函数从哪里得到它的 globals()?

Where does a compiled function get its globals()?

我发现如果我这样写:

code = f"lambda a, b: add(a, b)"
my_globals = globals().copy()
my_globals['add'] = operator.__add__
result = eval(code, my_globals, {})

然后 result(3, 5) 的值为 8,就像我想要的那样。

当我查看 result 的反汇编时,我看到:

 0 LOAD_GLOBAL              0 (add)
 2 LOAD_FAST                0 (a)
 4 LOAD_FAST                1 (b)
 6 CALL_FUNCTION            2
 8 RETURN_VALUE

LOAD_GLOBAL如何将add转换成operator.__add__?它显然必须在其自身或其 __code__ 对象的某处保存对 my_globals 的引用。但我一直无法找到它。

您查找的参考是函数对象的__globals__属性:

>>> result.__globals__
{'__name__': '__main__',
 # Many lines omitted
 'operator': <module 'operator' from '/usr/lib/python3.8/operator.py'>,
 'code': 'lambda a, b: add(a, b)',
 'add': <function _operator.add(a, b, /)>}

此属性记录在 Python Data model docs 中,在 user-defined 函数的特殊属性下:

__globals__:
A reference to the dictionary that holds the function’s global variables — the global namespace of the module in which the function was defined.
Read-only

如您所见,代码对象本身 (__code__) 不包含对适用的全局字典的引用。这在“代码对象”下的数据模型文档中明确提到:

Code objects represent byte-compiled executable Python code, or bytecode. The difference between a code object and a function object is that the function object contains an explicit reference to the function’s globals (the module in which it was defined), while a code object contains no context; also the default argument values are stored in the function object, not in the code object (because they represent values calculated at run-time). Unlike function objects, code objects are immutable and contain no references (directly or indirectly) to mutable objects.

globals(因此您的 my_globals)只是一本字典。它恰好是全局级别的默认字典搜索名称,LOAD_GLOBAL 知道如何查找。在您的示例中,主词典就是您的 my_globals。您不会找到对它的引用;它在解释器内部。