Let’s disect this one by one:
eval('"' + s.replace('(', '"+("').replace(')', '")[::-1]+"') + '"')
This is actually the same as the following (which may make it easier to understand):
code = '"' + s.replace('(', '"+("').replace(')', '")[::-1]+"') + '"'
eval(code)
Which is the same as:
innerCode = s.replace('(', '"+("').replace(')', '")[::-1]+"')
code = '"' + innerCode + '"'
eval(code)
innerCode
does simple string manipulation there:
- Replace
(
by "+("
- Replace
)
by ")[::-1]+"
So taking your example (bar)
as an example, this is the result: "+("bar")[::-1]+"
If you add the quotes again, you get this string:
""+("bar")[::-1]+""
= ("bar")[::-1]
= "bar"[::-1]
What [::-1]
does on a string is reverse it, essentially by iterating it from the back (that’s what the -1
does):
>>> 'foo'[::-1]
'oof'
>>> 'bar'[::-1]
'rab'
When that resulting code is then executed with eval
, you get your result.
Let’s look at another example: foo(bar)baz(blim)
. After replacing the parentheses, this is what you get:
foo"+("bar")[::-1]+"baz"+("blim")[::-1]+"
Add the quotes around and simplify it and you get this:
"foo"+("bar")[::-1]+"baz"+("blim")[::-1]+""
= "foo" + ("bar")[::-1] + "baz" + ("blim")[::-1]
= "foo" + "bar"[::-1] + "baz" + "blim"[::-1]
When you execute that, you get "foo" + "rab" + "baz" + "milb"
.
Note that while this works to solve the job, using eval
is actually a very bad idea. eval
executes any code, not just string concatenations and string reversals. So if you take the input from a source you don’t trust blindly, attackers could use this to execute bad code.
It’s a much better idea to implement this behavior without eval
at all, which isn’t that difficult since you are just manipulating a string after all.
For example, using regular expressions to quickly find the parentheses:
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'
Note that this does not correctly work for the final example that has nested parentheses. For cases like this, it’s much better to use a proper parser, like pyparsing
. This is described in more detail in this answer on a different question.
I would strongly advise you not to use eval
here though even if it does work for your case.