简体   繁体   English

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

[英]Why can't I access builtins if I use a custom dict as a function's globals?

I have a dict subclass like this: 我有一个像这样的dict子类:

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

This class can be used with eval and exec without issues: 这个类可以与evalexec一起使用而不会出现问题:

>>> eval('bytearray', MyDict())
<class 'bytearray'>
>>> exec('print(bytearray)', MyDict())
<class 'bytearray'>

But if I instantiate a function object with the types.FunctionType constructor, the function can't access any builtins: 但是如果我使用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

Replacing MyDict() with globals() or dict(globals()) or event {'__builtins__': __builtins__} makes the code print <class 'bytearray'> as expected. globals()dict(globals())或event {'__builtins__': __builtins__}替换MyDict()会使代码按预期打印<class 'bytearray'>

I don't understand where this exception is coming from. 我不明白这个例外的来源。 Can anyone explain this behavior? 谁能解释这种行为? Why does it work with eval but not with a function object? 为什么它与eval但不与函数对象一起使用?

Not a complete answer, but what seems to be happening is that CPython ignores the custom __getitem__ when it accesses the builtins. 不是一个完整的答案,但似乎正在发生的是CPython在访问内置函数时忽略了自定义__getitem__ It seems to treat MyDict like a normal (not subclassed) dict. 它似乎将MyDict视为正常( MyDict类)dict。 If the '__builtins__' key is actually present in the dict, then everything works correctly: 如果'__builtins__'键实际存在于dict中,那么一切正常:

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'>

The question remains why this only happens with FunctionType , and not with eval and exec . 问题仍然是为什么这只发生在FunctionType ,而不是发生在evalexec

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM