python中eval(str)的演化过程

时间:2014-01-08 02:25:06

标签: python eval

我发现代码如下:

nav_str = "'\\'!@34QWer\\''"
native_structure = eval(nav_str, {'__builtins__':{'set' : set}}, {})

>>> native_structure
>>> '!@34QWer'

我只是想知道eval(nav_str, {'__builtins__':{'set' : set}}, {})如何将"'\\'!@34QWer\\''"转移到'!@34QWer'

更新
我试着了解@user2357112@Blender几分钟,但我仍然无法实现这一过程 作为回答者,我认为eval("'\\'!@34QWer\\''")应该返回'\\'!@34QWer\\'',但'\\'!@34QWer\\''无效。
在eval()中"'\\'!@34QWer\\''"的演变过程是什么?

2 个答案:

答案 0 :(得分:1)

让我们看看nav_str的内容,没有字符串文字的转义:

>>> print nav_str
'\'!@34QWer\''

这些是nav_str包含的文字字符。单引号,反斜杠,单引号,感叹号等。这些字符构成有效的Python字符串文字。 eval计算字符串文字,返回一个字符串。

答案 1 :(得分:1)

首先,我们来看看这部分:

eval(nav_str, {'__builtins__':{'set' : set}}, {})

通常,eval会评估您在正常环境中给出的表达式,因此这些表达式相同:

>>> def foo(): print 'Hi'
>>> foo()
Hi
>>> eval('foo()')
Hi

但有时候你不想那样。您可能不希望在正常环境中从网络中取出任意字符串并eval,除非您想让人们(例如__import__('os').system('rm -rf /'))。因此,您可以自定义评估表达式的环境。具体细节在上面的文档中描述,但这是一个简单的示例:

>>> def foo(): print 'Hi!'
>>> def bar(): print 'Bye!'
>>> eval('foo()')
Hi!
>>> eval('foo()', {'__builtins__': {}}, {})
NameError: name 'foo' is not defined
>>> eval('foo()', {'__builtins__': {'foo': bar}}, {})
Bye!

那么,为什么你会想要一个除了set之外没有名字的环境?

最有可能的原因是你想要像ast.literal_eval这样的东西,但这也提供了一些处理空集的方法。 literal_eval仅评估Python文字。但空集没有字面意思;你必须写set()。并且ast.literal_eval无法处理set()。但是,在您的示例中对eval的错综复杂的调用可以。

当然这并不完美。使用eval允许所有类型的表达式不使用名称 - 数学,列表推导,生成器表达式,......


现在,让我们看看你正在评估的字符串:

nav_str = "'\\'!@34QWer\\''"

嗯,那里没有set的电话。或者完全引用任何名称。所以额外的复杂性只是一个红色的鲱鱼。只用eval(nav_str)就可以得到完全相同的东西。

那么,该字符串的处理是什么?

好吧,比较一下:

>>> print '\'!@34QWer\''
'!@34QWer'
>>> print eval(r"'\'!@34QWer\''")
'!@34QWer'
>>> print eval("'\\'!@34QWer\\''")
'!@34QWer'

您需要的唯一理由

它看起来如此复杂的唯一原因是:(a)编写表达式的人坚持使用单引号,即使字符串本身内部有单引号,需要反斜杠转义,以及(b)编写存储表达式的代码的人在变量中坚持不使用原始字符串,需要将这些反斜杠加倍。

您可以编写一个没有反斜杠的等效表达式:

>>> nav_str = '''"'!@34QWer'"'''

(它不是相同的字符串文字表达式,但它是一个字符串文字表达式,其计算结果相同。)