所以我理解了exec
和eval
以及compile
的所作所为。但为什么我需要使用它们呢?我对使用场景不清楚。
任何人都可以给我一些例子,以便我能更好地理解这个概念。因为我知道这完全是理论。
答案 0 :(得分:5)
我将举例说明我使用eval
并认为这是最佳选择。
我正在编写一个简单的软件测试实用程序......用于测试学生练习是否符合作业要求。目标是为简单的配置文件提供一种方法作为测试规范(解决使用编程语言描述/记录/实现基本编程分配的测试用例的“鸡与鸡蛋”问题)
我基于标准库中的ConfigParser。但是,我确实希望能够表示任意Python字符串(包括\ n,\ t的插值,尤其是从中读取的值中的任何插值十六进制编码的ASCII字符。
我的解决方案是try
围绕parsed_string=eval('''%s''' % cfg_read_item)
,然后是try
三重双引号版本(“”“%s”“”)。
这种情况下,替代方案可能是编写(或找到预先编写的)Python语言解析器,并弄清楚如何将其包含并调整到我的程序中。风险很小(我不担心学生提交的代码会欺骗我的解析器,如果它的监狱爆发,删除我的所有文件,将我的信用卡号码发送到罗马尼亚等等)*
*(部分原因是我在Linux下使用不受信任的无头用户帐户测试它们)。
正如其他人所说,还有其他一些用例,你根据输入数据从模板构建代码并需要执行该代码(元编程)。您应始终能够以其他方式完成这些任务。但是,每当该替代方案需要编写代码来编写通用编程语言解析器/编译器/解释器....那么eval
可能是更好的方法。
答案 1 :(得分:4)
标准库有一个如何使用exec
的指导性示例。 collections.namedtuple使用它动态构建一个类。
template = '''class %(typename)s(tuple):
'%(typename)s(%(argtxt)s)' \n
__slots__ = () \n
_fields = %(field_names)r \n
def __new__(_cls, %(argtxt)s):
'Create new instance of %(typename)s(%(argtxt)s)'
return _tuple.__new__(_cls, (%(argtxt)s)) \n
...'''
namespace = dict(_itemgetter=_itemgetter, __name__='namedtuple_%s' % typename,
OrderedDict=OrderedDict, _property=property, _tuple=tuple)
try:
exec template in namespace
except SyntaxError, e:
raise SyntaxError(e.message + ':\n' + template)
答案 2 :(得分:3)
ast
使用compile
从Python源代码生成抽象语法树。这些由pyflakes
等模块用于解析和验证Python。
def parse(expr, filename='<unknown>', mode='exec'):
"""
Parse an expression into an AST node.
Equivalent to compile(expr, filename, mode, PyCF_ONLY_AST).
"""
return compile(expr, filename, mode, PyCF_ONLY_AST)
答案 3 :(得分:1)
你不需要来使用它们,我认为你应该避免使用它们。
它们仅在您自己生成代码的情况下有用,最终很可能被视为不良实践。
如果您正在考虑将eval()用于数学表达式之类的东西,那么在评估输入之前,最好先对输入进行消毒。你永远不知道用户发送的那种“文本”可能会搞砸应用程序本身。
答案 4 :(得分:1)
我认为我有效使用。我在Blender 2.6.4中使用Python 3.2.1来修改一组带有x,y坐标的点(在z平面中)。
目标是在每个现有点周围添加新点的同心环,其中环表现为涟漪(就像当你在池塘里扔石头时)。问题在于我希望涟漪能够建设性地/破坏性地相互干扰,所以首先我要经历并构建一个以每个点为中心的“波纹方程”,并将所有波纹方程式汇总成一个巨大的数学方程式,然后,我将输入原始点,以生成正确的z值,将每个点分配给。
我的计划是将等式中的每个附加项附加到前一个字符串,然后使用eval()计算新点集的z值。
答案 5 :(得分:0)
你只是在问一个例子吗?您可以编写一个从标准读取的简单应用程序,并允许用户输入各种表达式,如(4*2)/8 - 1
。在其他语言(Java,C ++等)中,这几乎是不可能评估的,但在python中它很简单,只是:
eval((4*2)/8 - 1)
话虽如此,除非你小心,否则使用这些东西可能非常危险,因为它们(基本上)允许用户进行大量访问。
答案 6 :(得分:0)
这用于元编程(当程序自行编写时)。例如,你有不同种类的动物,用不同的类别描述:狮子,老虎,马,驴。并且你想模拟它们之间的杂交,例如Lion和Tiger之间的杂交。当你编写程序时,你无法确定用户如何穿越动物,但你可以动态创建新的动物类:
new_class_name = boy.class.to_str() + girl.class.to_str()
eval("class " + new_class_name + " extends " + boy.class.to_str() + ", " + girl.class.to_str())
P上。对不起,我忘记了一些Python。所以有一堆伪代码。
答案 7 :(得分:0)
这是一个有效的用例。在python paste中间件(用于web编程)中,当引发异常时,它会在浏览器中创建一个命令行。这可以使用这些方法。此外,在Blender中有一个使用python表达式为值设置动画的选项,这可以使用eval。