【问题标题】:Python: How can I run eval() in the local scope of a functionPython:如何在函数的本地范围内运行 eval()
【发布时间】:2016-04-14 07:44:39
【问题描述】:

我尝试在函数的本地范围内使用 eval()。但是它总是在全局范围内进行评估。

自包含示例:

1- 此代码有效:

var1 = 1
var2 = 2
var3 = 3    
myDict = dict((name, eval(name)) for name in ["var1",
                                              "var2",
                                              "var3"])
print(myDict["var1"])

2- 为 lvar1 抛出 NameError

def test1():
   lvar1 = 1
   lvar2 = 2
   lvar3 = 3
   myDict = dict((name, eval(name)) for name in ["lvar1",
                                                 "lvar2",
                                                 "lvar3"])
   print(myDict["lvar1"])

3- 与 2 相同的结果。

def test2():
    lvar1 = 1
    lvar2 = 2
    lvar3 = 3
    myDict = dict((name, eval(name), locals()) for name in ["lvar1",
                                                            "lvar2",
                                                            "lvar3"])
    print(myDict["lvar1"])

【问题讨论】:

  • 或许这里更重要的问题是do you really need eval?
  • @cjahangir 那是¯\_(ツ)_/¯ 建议
  • @Adib,它可以在我的电脑上运行
  • @joost 我尝试仅在测试 pytest 的夹具时使用 eval()。所以这不会是一个安全漏洞,你是对的,我找到了另一种方法,但我仍然对如何做到这一点感兴趣。因为一定是python有这个内置的原因
  • @cjahangir python中的“string”和“string”没有任何区别,你的python解释器是什么?

标签: python scope eval


【解决方案1】:

保存locals()(或vars())调用的结果以返回函数的本地范围。否则,生成器表达式中的locals() 将返回 gen-expr 的本地范围。

def test3():
    lvar1 = 1
    lvar2 = 2
    lvar3 = 3
    scope = locals()
    myDict = dict((name, eval(name, scope)) for name in [
                  "lvar1", "lvar2", "lvar3"])
    print(myDict["lvar1"])

顺便说一句,您不需要明确的理解来构建该字典:

# copy() avoids quirky, unexpected updates if something else (like a debugger)
# accesses locals() or f_locals
myDict = locals().copy()  # or vars().copy()

【讨论】:

  • 谢谢。在这种特殊情况下可能不相关,但是这种方式本地人被解释为全局变量(因为 eval 的第二个参数)?如何将他们指定为本地人? eval(name, locals=scope) 似乎不起作用。
  • @SearchSpace,eval的第三个参数是locals。因此,如果我正确解释了您的评论,eval(expression_you_want_to_evaluate, {}, scope) 会给您您想要的。 docs.python.org/3/library/functions.html#eval
【解决方案2】:

首先重要的是read this

表达式参数被解析和评估为 Python 表达式 (从技术上讲,条件列表)使用全局变量和局部变量 字典作为全局和本地命名空间。如果全局字典 存在且缺少‘__builtins__’,当前全局变量被复制 在解析表达式之前进入全局变量。这意味着表达式 通常可以完全访问标准__builtin__ 模块和 传播受限环境。如果本地字典是 省略它默认为全局字典。如果两个字典 被省略,表达式在环境中执行 eval() 被调用。返回值是评估的结果 表达式`。

首先要注意,生成器表达式有自己的范围(对于 dict-comprehension 也是如此),因此它有自己的 locals() 字典。

  1. 之所以有效,是因为在全局范围内,globals()locals() dict 都指向同一个字典,因此 dict 构造函数可以访问这些变量。

  2. 这里我们再次调用 eval() 没有 globals()locals() dict 因此它最终使用全局范围和它自己的本地范围(它是空的)并且没有这样的变量可用任何这些范围。

  3. 记住生成器有自己的作用域,所以在这里调用 locals() 几乎没有任何区别,它是一个空字典。

解决方案:

def test1():
   lvar1 = 1
   lvar2 = 2
   lvar3 = 3
   test1_locals = locals()
   myDict = dict((name, eval(name, test1_locals)) for name in ["lvar1",
                                                 "lvar2",
                                                 "lvar3"])
   print myDict
   print(myDict["lvar1"])

这很有效,因为我们在一个变量中捕获了 test1 的 locals(),然后在字典理解中使用了该字典,因此它现在可以访问这些变量。

【讨论】:

  • 感谢您的解释!这很莫名其妙!如果我理解正确,您的意思是在dict() 命令中,它只考虑全局变量,这就是为什么它排除函数中的所有变量,因为它是本地的? (这就是为什么我们必须指定范围?)
  • 将生成器表达式视为具有自己的一组局部变量的新函数范围,test1 具有自己独立的局部变量。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-30
  • 2011-11-12
  • 2021-11-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多