list comprehension in exec with empty locals: NameError

前端 未结 5 1200
清歌不尽
清歌不尽 2020-12-15 22:55

Consider the following snippet:

def bar():
    return 1
print([bar() for _ in range(5)])

It gives an expected output [1, 1, 1, 1, 1]<

5条回答
  •  旧巷少年郎
    2020-12-15 23:33

    Here's a solution!

    We needed to get the local namespace out after the exec() to track modifications. This doesn't work with only one namespace, so we did this:

     class MagickNameSpace(UserDict, dict):
        """A magic namespace for Python 3 exec().
        We need separate global and local namespaces in exec(). This does not
        work well in Python 3, because in Python 3 the enclosing namespaces are
        not used to look up variables, which seems to be an optimization thing
        as the exec'd code isn't available at module compilation.
    
        So we make a MagickNameSpace that stores all new variables in a
        separate dict, conforming to the local/enclosing namespace, but
        looks up variables in both.
        """
    
    
        def __init__(self, ns, *args, **kw):
            UserDict.__init__(self, *args, **kw)
            self.globals = ns
    
        def __getitem__(self, key):
            try:
                return self.data[key]
            except KeyError:
                return self.globals[key]
    
        def __contains__(self, key):
            return key in self.data or key in self.globals
    

    Replace the old code:

    exec(code, global_ns, local_ns)
    return local_ns
    

    with:

    ns = MagickNameSpace(global_ns)
    ns.update(local_ns)
    exec(code, ns)
    return ns.data
    

提交回复
热议问题