【问题标题】:Use of eval in Python?在 Python 中使用 eval?
【发布时间】:2010-11-08 09:43:28
【问题描述】:

我在玩游戏时偶然发现了 Python 中有一个 eval() 函数。我想不出需要这个函数的情况,除了可能作为语法糖。谁能举个例子?

【问题讨论】:

  • '作为语法糖'——这是什么意思?

标签: python dynamic eval


【解决方案1】:

evalexec 是动态获取一些源代码的方便快捷的方法,也许稍微修改一下,然后执行它——但它们几乎不是最好的方法,尤其是在生产中代码而不是“快速而肮脏”的原型等。

例如,如果我必须处理此类动态 Python 源,我会使用 ast 模块 -- ast.literal_evaleval 安全得多(您可以直接以字符串形式调用它表达式,如果它是一次性的并且仅依赖于简单的常量,或者先执行node = ast.parse(source),然后将node 保留在周围,也许可以用合适的访问者来处理它,例如用于变量查找,然后是literal_eval 节点) - - 或者,一旦将节点置于适当的形状并对其进行安全问题审查,我可以compile 它(产生一个代码对象)并从中构建一个新的函数对象。远没有那么简单(除了ast.literal_eval 在最简单的情况下与eval 一样简单!)但在生产质量代码中更安全、更可取。

对于我见过的许多任务,我看到人们(ab-)使用execeval 来实现Python 强大的内置函数,例如getattrsetattr,索引到globals(),&c,提供更可取,实际上通常更简单的解决方案。对于解析 JSON 等特定用途,json 等库模块更好(例如,参见 SilentGhost 对耳鸣的评论对这个问题的回答)。等等等等……

【讨论】:

    【解决方案2】:

    Wikipedia article on eval 内容丰富,详细介绍了各种用途。

    它建议的一些用途是:

    【讨论】:

    • 看了这篇文章还是没看懂……这有点像计算算术表达式的函数!
    • @ooboo: eval 理论上可以运行任何代码(因此存在文章中指出的安全风险)。
    【解决方案3】:

    您可能希望使用它来允许用户输入他们自己的“scriptlet”:small 表达式(甚至是小函数),可用于自定义 complex 的行为 系统。
    在这种情况下,如果您不必太在意安全隐患(例如,您拥有受过良好教育的用户群),那么 eval() 可能是一个不错的选择。

    【讨论】:

      【解决方案4】:

      过去我曾使用 eval() 向我的应用程序添加调试接口。我创建了一个 telnet 服务,它让你进入正在运行的应用程序的环境中。输入通过 eval() 运行,因此您可以在应用程序中以交互方式运行 Python 命令。

      【讨论】:

      • 我已经为 Enterprise Architect 编写了类似的 COM 接口脚本,以尝试不同的查询
      【解决方案5】:

      在我曾经编写的一个程序中,您有一个输入文件,您可以在其中指定几何参数作为值和先前值的 python 表达式,例如:

      a=10.0
      b=5.0
      c=math.log10(a/b)
      

      python 解析器读取此输入文件并使用 eval() 获得评估值和表达式的最终数据。

      我不认为这是一个好的编程,但我不必驱动核反应堆。

      【讨论】:

        【解决方案6】:

        我将它用作快速 JSON 解析器 ...

        r='''
        {
            "glossary": {
                "title": "example glossary"
                }
        }
        '''
        
        print eval(r)['glossary']['title']
        

        【讨论】:

        • 别这样。 eval("""{"glossary": {"death" : false}}""") --> NameError: name 'false' is not defined
        • @SilentGhost:这很好,我用你的例子回答了一个问题; stackoverflow.com/questions/1083250/…
        • 使用 real JSON 解析器会更少错误且更安全。
        • 总体上不错的想法:),可以应用于不同的东西,但是,我不会将它与 JSON 一起使用,有工具。
        【解决方案7】:

        你可以在装饰器中使用 eval:

        #this replaces the original printNumber with a lambda-function,
        #which takes no arguments and which calls the old function with
        #the number 10
        @eval("lambda fun: lambda: fun(10)")
        def printNumber(i: int) -> None:
            print("The number is %i", i)
        
        #call
        printNumber()
        

        虽然你不能使用复杂的表达式,例如

        @lambda fun: lambda: fun(10)
        def ...
        

        也没有

        @(lambda fun: lambda: fun(10))
        def ...
        

        你不能在那里使用 lambda 表达式,因为装饰器应该是一个标识符:

        @myModule.functionWithOneArg
        

        或函数调用:

        @functionReturningFunctionWithOneArg(any, "args")
        

        您会看到这里使用字符串调用函数 eval 具有有效的语法,但 lambda 表达式却没有。 (->https://docs.python.org/3/reference/compound_stmts.html#function-definitions)

        【讨论】:

          【解决方案8】:

          eval() 通常不是很有用。我使用它的少数几件事之一(嗯,实际上是exec(),但它非常相似)是允许用户编写我用 Python 编写的应用程序的脚本。如果它是用 C++ 之类的东西编写的,我将不得不在应用程序中嵌入一个 Python 解释器。

          【讨论】:

            【解决方案9】:

            Eval 是一种在程序中与 Python 解释器交互的方法。您可以将文字传递给 eval,它会将它们评估为 python 表达式。

            例如——

            print eval("__import__('os').getcwd()")
            

            将返回当前工作目录。

            干杯

            【讨论】:

              【解决方案10】:

              eval() 是单句,exec() 是多句。

              通常我们使用它们来添加或访问一些脚本,就像 bash shell。

              因为它们可以在内存中运行一些字节脚本,所以如果您有一些重要的数据或脚本,您可以解码并解压缩您的“秘密”,然后做任何您想做的事情。

              【讨论】:

                【解决方案11】:

                我刚刚发现了一个很好的 eval 用法。我正在为一些代码编写一个测试套件,并创建了一个测试类,其中每个方法都是要运行的测试。我想要一种方法,这样我就可以运行所有的测试方法,而不必单独调用每个方法。所以,我写了一些比较脏的东西。

                class Test:
                    def __init__(self, *args):
                       #bs
                
                    def test1(self):
                       #bs
                
                    def test2(self):
                       #bs
                
                if __name__ == "__main__":
                    import argparse
                    #argparse bs
                    test = Test(*bs_args)
                    for func in (i for i in dir(test) if i[0] != '_' and i not in test.__dict__):
                        print(eval('test.{func}()'.format(func = func)))
                

                任意测试用例的动态评估非常酷。我只需要编写方法,保存后我可以将方法包含在我的测试套件中。至于代码,我基本上只是检查测试对象中定义的方法,并确保它们不是默认的 Python“魔术”方法或 Test 对象的属性。之后我可以假设它们是方法并且可以被评估。

                【讨论】:

                  【解决方案12】:

                  我用它给主程序输入变量值:

                  test.py var1=2 var2=True

                  ...

                  var1=0
                  var2=False
                  for arg in sys.argv[1:]:
                      exec(arg)
                  

                  在主程序中允许关键字 args 的粗略方法。如果有更好的方法请告诉我!

                  【讨论】:

                    【解决方案13】:

                    我有一个案例,我将 eval 与一个 informix 数据库结合使用。由于某种原因,查询返回了一个像这样形成的字符串

                    query_result = "['1', '2', '3']"
                    

                    我只是在查询结果上使用了 eval,因此 python 将其解释为字符串列表。

                    [int(i) for i in eval(query_result)]
                    > [1,2,3]
                    

                    我无法更改数据库,因此这是获取整数的一种快速(且肮脏)的方法。

                    【讨论】:

                      【解决方案14】:

                      我使用exec 在 Python 中创建一个插件系统。

                      尝试: exec ("from " + plugin_name + "import Plugin") 我的插件 = 插件(模块选项,配置 = 配置) 除了 ImportError,消息: 致命的(“没有这样的模块” + plugin_name + \ " (或没有插件构造函数) 在我的 Python 路径中:" + str(message)) 除了例外: 致命(“模块”+插件名称+“无法加载:”+\ str(sys.exc_type) + ":" + str(sys.exc_value) + \ ".\n 可能是一个缺失或错误的选项?")

                      使用如下插件:

                      类插件: def __init__ (自我): 经过 def 查询(自我,arg): ...

                      你可以这样称呼它:

                      结果 = myplugin.query("something")

                      如果没有exec/eval,我认为你不能在 Python 中拥有插件。

                      【讨论】:

                      • 这不好。您应该使用__import__ 内置函数,该函数由from ... import ... 语句调用。
                      猜你喜欢
                      • 2013-11-23
                      • 1970-01-01
                      • 1970-01-01
                      • 2022-11-02
                      • 1970-01-01
                      • 2013-02-18
                      • 2021-12-17
                      相关资源
                      最近更新 更多