如果我使用自定义dict作为函数的全局变量,为什么我不能访问builtins?

Ara*_*Fey 7 python global cpython function

我有一个dict像这样的子类:

class MyDict(dict):
    def __getitem__(self, name):
        return globals()[name]
Run Code Online (Sandbox Code Playgroud)

这个类可以使用evalexec不使用问题:

>>> eval('bytearray', MyDict())
<class 'bytearray'>
>>> exec('print(bytearray)', MyDict())
<class 'bytearray'>
Run Code Online (Sandbox Code Playgroud)

但是如果我用types.FunctionType构造函数实例化一个函数对象,该函数就无法访问任何内置函数:

import types

func = lambda: bytearray
func_copy = types.FunctionType(func.__code__,
                              MyDict(),
                              func.__name__,
                              func.__defaults__,
                              func.__closure__)

print(func_copy())
# Traceback (most recent call last):
#   File "untitled.py", line 16, in <module>
#     print(func_copy())
#   File "untitled.py", line 8, in <lambda>
#     func = lambda: bytearray
# NameError: name 'bytearray' is not defined
Run Code Online (Sandbox Code Playgroud)

替换MyDict()globals()or dict(globals())或event {'__builtins__': __builtins__}会使代码<class 'bytearray'>按预期打印.

我不明白这个例外的来源.谁能解释这种行为?为什么它适用于eval但不适用于函数对象?

Ara*_*Fey 1

这不是一个完整的答案,但似乎发生的情况是 CPython__getitem__在访问内置函数时忽略了自定义。它似乎像一个普通的(没有子类的)字典一样对待MyDict。如果'__builtins__'密钥实际上存在于字典中,那么一切正常:

class MyDict(dict):
    def __getitem__(self, name):
        return globals()[name]


import types

globs = MyDict()
globs['__builtins__'] = __builtins__

func = lambda: bytearray
func_copy = types.FunctionType(func.__code__,
                              globs,
                              func.__name__,
                              func.__defaults__,
                              func.__closure__)

print(func_copy())
# output: <class 'bytearray'>
Run Code Online (Sandbox Code Playgroud)

问题仍然是为什么这只发生在FunctionType,而不是eval和上exec