что делает eval? - PullRequest
       13

что делает eval?

1 голос
/ 02 апреля 2019

После двухдневных попыток решить проблему с обращающимися скобками в Codesignal и найти более 150 строк кода, которые не работали, я наткнулся на следующий код, используя eval ().

Теперь я понимаю, что eval () берет строку и интерпретирует ее так, как если бы она была введена в консоль.Но я действительно не понимаю, как он достигает своей цели здесь.Может кто-то, пожалуйста, пройти это постепенно и объяснить, что происходит?

Спасибо

Я попробовал поискать в Google, читать документы и искать на 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"

Ответы [ 2 ]

1 голос
/ 02 апреля 2019

Давайте рассмотрим это одно за другим:

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

Это фактически то же самое, что и следующее (что может облегчить понимание):

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

То же самоеas:

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, что не так.t , что сложно, поскольку вы все-таки просто манипулируете строкой.

Например, используя регулярные выражения для быстрого поиска скобок:

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.Это более подробно описано в этом ответе на другой вопрос .

Я бы настоятельно рекомендовал вам не использовать eval здесь, хотя даже если это работает для вашего случая.

1 голос
/ 02 апреля 2019

Шаг за шагом

eval('"' + s.replace('(', '"+("').replace(')', '")[::-1]+"') + '"')
  • '"' Начало строки
  • s.replace('(', '"+("') замените символ ( на '"+("' просто разделив строку на предыдущую + следующую
  • replace(')', '")[::-1]+"') замените символ ) на )[::-1]+, чтобы перевернуть строку в скобках и добавить следующее. Действительно, 'abc'[::-1] = 'cba'
  • + '"' Закрыть строку.

Таким образом «парсер» разделяет каждую строку на квадратные скобки, переворачивает ее, а затем добавляет следующую строку.

...