什么是eval呢?

问题描述 投票:1回答:2

在尝试完成对Codeignal的Reversing括号挑战大约2天并提出超过150行不起作用的代码之后,我使用eval()偶然发现了以下代码。

现在我明白eval()接受一个字符串并将其解释为好像已经输入控制台一样。但我真的不明白它是如何实现其目标的。有人可以一点一点地解决它,并解释发生了什么?

谢谢

我尝试使用谷歌搜索,阅读文档和搜索youtube以获得更好的理解。但无济于事。

def reverseInParentheses(s):
    return eval('"' + s.replace('(', '"+("').replace(')', '")[::-1]+"') + '"')
 inputString = "(bar)"
 reverseInParentheses(inputString)  # output: "rab"

 inputString = "foo(bar)baz"
 reverseInParentheses(inputString)  # output: "foorabbaz"

 inputString = "foo(bar)baz(blim)"
 reverseInParentheses(inputString)  # output: "foorabbazmilb"

 inputString = "foo(bar(baz))blim"
 reverseInParentheses(inputString)  # output: "foobazrabblim"
python eval
2个回答
1
投票

让我们逐一解读:

eval('"' + s.replace('(', '"+("').replace(')', '")[::-1]+"') + '"')

这实际上与以下相同(可能更容易理解):

code = '"' + s.replace('(', '"+("').replace(')', '")[::-1]+"') + '"'
eval(code)

这与以下相同:

innerCode = s.replace('(', '"+("').replace(')', '")[::-1]+"')
code = '"' + innerCode + '"'
eval(code)

innerCode在那里进行简单的字符串操作:

  • (替换"+("
  • )替换")[::-1]+"

以你的例子(bar)为例,这就是结果:"+("bar")[::-1]+"

如果再次添加引号,则会得到以下字符串:

  ""+("bar")[::-1]+""
= ("bar")[::-1]
= "bar"[::-1]

[::-1]对字符串的作用是反向的,主要是从后面迭代它(这就是-1所做的):

>>> 'foo'[::-1]
'oof'
>>> 'bar'[::-1]
'rab'

当使用eval执行生成的代码时,您将获得结果。

让我们看另一个例子:foo(bar)baz(blim)。更换括号后,这就是你得到的:

foo"+("bar")[::-1]+"baz"+("blim")[::-1]+"

添加引号并简化它,你得到这个:

  "foo"+("bar")[::-1]+"baz"+("blim")[::-1]+""
= "foo" + ("bar")[::-1] + "baz" + ("blim")[::-1]
= "foo" + "bar"[::-1] + "baz" + "blim"[::-1]

当你执行它时,你得到"foo" + "rab" + "baz" + "milb"


请注意,虽然这可以解决这个问题,但使用eval实际上是一个非常糟糕的主意。 eval执行任何代码,而不仅仅是字符串连接和字符串反转。因此,如果您从盲目信任的来源获取输入,攻击者可以使用它来执行错误的代码。

在没有eval的情况下实现这种行为是一个更好的主意,这并不困难,因为你毕竟只是操纵一个字符串。

例如,使用正则表达式快速查找括号:

import re
def reverseInParentheses(s):
    for m in re.findall('\((.*?)\)', s):
        s = s.replace('(' + m + ')', m[::-1])
    return s
>>> reverseInParentheses("(bar)")
'rab'
>>> reverseInParentheses("foo(bar)baz")
'foorabbaz'
>>> reverseInParentheses("foo(bar)baz(blim)")
'foorabbazmilb'
>>> reverseInParentheses("foo(bar(baz))blim")
'foozab(rab)blim'

请注意,这不适用于具有嵌套括号的最终示例。对于这样的情况,使用正确的解析器(如pyparsing)要好得多。这在this answer on a different question中有更详细的描述。

我强烈建议你不要在这里使用eval,即使它对你的情况有用。


1
投票

一步步

eval('"' + s.replace('(', '"+("').replace(')', '")[::-1]+"') + '"')
  • '"'开始一个字符串
  • s.replace('(', '"+("')replace char (with qazxsw poi基本上只是将字符串拆分为前一个+以下一个
  • '"+("'replace char replace(')', '")[::-1]+"')with )这反转括号之间的字符串,并添加以下内容。的确,)[::-1]+ = 'abc'[::-1]
  • 'cba'关闭字符串。

这样,“解析器”将每个字符串分隔成括号,将其反转,然后添加以下字符串。

© www.soinside.com 2019 - 2024. All rights reserved.