No livro que estou lendo sobre Python, ele continua usando o código eval(input('blah'))
Eu li a documentação e a compreendo, mas ainda não vejo como isso altera a input()
função.
O que isso faz? Alguém pode explicar?
No livro que estou lendo sobre Python, ele continua usando o código eval(input('blah'))
Eu li a documentação e a compreendo, mas ainda não vejo como isso altera a input()
função.
O que isso faz? Alguém pode explicar?
Respostas:
A função eval permite que um programa Python execute o código Python dentro de si.
exemplo eval (shell interativo):
>>> x = 1
>>> eval('x + 1')
2
>>> eval('x')
1
eval()
também pode ser usado para executar código altamente dinâmico, mas você deve se conscientizar completamente dos riscos de segurança e desempenho antes de usá-lo.
eval
, nem poderia fazer o que faz eval
.
eval
, além de inseguro, não pode executar programas inteiros como o codepad, porque só pode avaliar uma única expressão.
eval()
interpreta uma string como código. A razão pela qual tantas pessoas o alertaram sobre o uso disso é porque um usuário pode usá-lo como uma opção para executar código no computador. Se você tem eval(input())
e os
importados, uma pessoa poderia digitar em input()
os.system('rm -R *')
que iria apagar todos os seus arquivos em seu diretório home. (Supondo que você tenha um sistema unix). Usar eval()
é uma falha de segurança. Se você precisar converter seqüências de caracteres para outros formatos, tente usar coisas que fazem isso, como int()
.
eval
with input()
é uma falha de segurança. Não insira input()
uma declaração de avaliação e você ficará bem.
eval
ocorre com muitos problemas de segurança.
input
geralmente leva seus dados a partir do console o usuário poderia simplesmente sair do programa e digite rm -R *
qualquer maneira ...
Muitas respostas boas aqui, mas nenhuma descreve o uso de eval()
no contexto its globals
e locals
kwargs, isto é eval(expression, globals=None, locals=None)
(consulte a documentação eval
aqui ).
Eles podem ser usados para limitar as funções disponíveis através da eval
função. Por exemplo, se você carregar um intérprete python novo, o locals()
e globals()
será o mesmo e terá algo parecido com isto:
>>>globals()
{'__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__doc__': None,
'__spec__': None, '__builtins__': <module 'builtins' (built-in)>,
'__package__': None, '__name__': '__main__'}
Certamente, existem funções no builtins
módulo que podem causar danos significativos a um sistema. Mas é possível bloquear tudo e qualquer coisa que não queremos disponível. Vamos dar um exemplo. Digamos que queremos construir uma lista para representar um domínio dos núcleos disponíveis em um sistema. Para mim eu tenho 8 núcleos, então eu gostaria de uma lista [1, 8]
.
>>>from os import cpu_count
>>>eval('[1, cpu_count()]')
[1, 8]
Da mesma forma, tudo __builtins__
está disponível.
>>>eval('abs(-1)')
1
Está bem. Então, vemos uma função que queremos expor e um exemplo de um método (de muitos que pode ser muito mais complexo) que não queremos que seja exposto. Então, vamos bloquear tudo.
>>>eval('[1, cpu_count()]', {'__builtins__':None}, {})
TypeError: 'NoneType' object is not subscriptable
Bloqueamos efetivamente todas as __builtins__
funções e, como tal, trouxemos um nível de proteção ao nosso sistema. Nesse ponto, podemos começar a adicionar novamente funções que queremos que sejam expostas.
>>>from os import cpu_count
>>>exposed_methods = {'cpu_count': cpu_count}
>>>eval('cpu_count()', {'__builtins__':None}, exposed_methods)
8
>>>eval('abs(cpu_count())', {'__builtins__':None}, exposed_methods)
TypeError: 'NoneType' object is not subscriptable
Agora temos a cpu_count
função disponível enquanto ainda bloqueamos tudo o que não queremos. Na minha opinião, isso é super poderoso e claramente do escopo das outras respostas, não de uma implementação comum. Existem inúmeros usos para algo assim e, desde que seja manuseado corretamente, eu pessoalmente acho que eval
pode ser usado com segurança por um grande valor.
NB
Outra coisa interessante sobre isso kwargs
é que você pode começar a usar uma abreviação para seu código. Digamos que você use eval como parte de um pipeline para executar algum texto importado. O texto não precisa ter o código exato, ele pode seguir algum formato de arquivo de modelo e ainda executar o que você desejar. Por exemplo:
>>>from os import cpu_count
>>>eval('[1,cores]', {'__builtins__': None}, {'cores': cpu_count()})
[1, 8]
No Python 2.x input(...)
é equivalente eval(raw_input(...))
, no Python 3.x raw_input
foi renomeado input
, o que eu suspeito levar à sua confusão (você provavelmente estava procurando a documentação input
do Python 2.x). Além disso, eval(input(...))
funcionaria bem no Python 3.x, mas aumentaria um TypeError
no Python 2.
Nesse caso, eval
é usado para coagir a sequência retornada input
em uma expressão e interpretada. Geralmente, isso é considerado uma má prática.
input
significa o que raw_input
fez no 2.x.
Talvez um exemplo enganoso de ler e interpretar uma linha.
Experimente eval(input())
e digite "1+1"
- isso deve ser impresso 2
. Eval avalia expressões.
eval()
avalia a cadeia passada como uma expressão Python e retorna o resultado. Por exemplo, eval("1 + 1")
interpreta e executa a expressão "1 + 1"
e retorna o resultado (2).
Uma razão pela qual você pode estar confuso é porque o código que você citou envolve um nível de indireção. A chamada de função interna (entrada) é executada primeiro para que o usuário veja o prompt "blah". Vamos imaginar que eles respondem com "1 + 1" (aspas adicionadas para maior clareza, não as digitam ao executar o programa), a função de entrada retorna essa string, que é então passada para a função externa (eval) que interpreta a string e retorna o resultado (2).
Leia mais sobre eval aqui .
eval()
, como o nome sugere, avalia o argumento passado.
raw_input()
está agora input()
nas versões python 3.x. Portanto, o exemplo mais comumente encontrado para o uso de eval()
é seu uso para fornecer a funcionalidade input()
fornecida na versão 2.x do python. raw_input retornou os dados inseridos pelo usuário como uma sequência, enquanto a entrada avaliou o valor dos dados inseridos e os retornou.
eval(input("bla bla"))
assim, replica a funcionalidade do input()
2.x, isto é, da avaliação dos dados inseridos pelo usuário.
Em resumo: eval()
avalia os argumentos passados para ele e, portanto, eval('1 + 1')
retornou 2.
Uma das aplicações úteis de eval()
é avaliar expressões python da string. Por exemplo, carregar da representação de sequência de arquivos do dicionário:
running_params = {"Greeting":"Hello "}
fout = open("params.dat",'w')
fout.write(repr(running_params))
fout.close()
Leia-o como uma variável e edite-o:
fin = open("params.dat",'r')
diction=eval(fin.read())
diction["Greeting"]+="world"
fin.close()
print diction
Resultado:
{'Greeting': 'Hello world'}
eval
faz?
Estou atrasado para responder a essa pergunta, mas ninguém parece dar uma resposta clara à pergunta.
Se um usuário digitar um valor numérico, input()
retornará uma sequência.
>>> input('Enter a number: ')
Enter a number: 3
>>> '3'
>>> input('Enter a number: ')
Enter a number: 1+1
'1+1'
Portanto, eval()
avaliaremos o valor retornado (ou expressão) que é uma string e retornará um número inteiro / float.
>>> eval(input('Enter a number: '))
Enter a number: 1+1
2
>>>
>>> eval(input('Enter a number: '))
Enter a number: 3.14
3.14
É claro que essa é uma prática ruim. int()
ou float()
deve ser usado em vez de eval()
neste caso.
>>> float(input('Enter a number: '))
Enter a number: 3.14
3.14
Outra opção se você deseja limitar a cadeia de avaliação a literais simples é usar ast.literal_eval()
. Alguns exemplos:
import ast
# print(ast.literal_eval('')) # SyntaxError: unexpected EOF while parsing
# print(ast.literal_eval('a')) # ValueError: malformed node or string
# print(ast.literal_eval('import os')) # SyntaxError: invalid syntax
# print(ast.literal_eval('1+1')) # 2: but only works due to a quirk in parser
# print(ast.literal_eval('1*1')) # ValueError: malformed node or string
print(ast.literal_eval("{'a':1}")) # {'a':1}
Dos documentos :
Avalie com segurança um nó de expressão ou uma sequência que contém um literal Python ou exibição de contêiner. A cadeia ou nó fornecido pode apenas consistir nas seguintes estruturas literais do Python: cadeias, bytes, números, tuplas, listas, dictos, conjuntos, booleanos e Nenhum.
Isso pode ser usado para avaliar com segurança seqüências de caracteres contendo valores Python de fontes não confiáveis, sem a necessidade de analisar os próprios valores. É não capaz de avaliar expressões complexas arbitrariamente, por exemplo envolvendo operadores ou indexação.
Por que é tão limitado, na lista de discussão :
Permitir expressões de operador com literais é possível, mas muito mais complexo que a implementação atual. Uma implementação simples não é segura: você pode induzir basicamente o uso ilimitado da CPU e da memória sem esforço (tente "9 ** 9 ** 9" ou "[None] * 9 ** 9").
Quanto à utilidade, esta função é útil para "ler de volta" valores literais e contêineres, conforme especificado por repr (). Por exemplo, isso pode ser usado para serialização em um formato semelhante, mas mais poderoso que o JSON.
ast.literal_eval
não suporta operadores, ao contrário do seu '1+1'
exemplo. No entanto, ele suporta listas, números, seqüências de caracteres etc, e, portanto, é uma boa alternativa para eval
casos de uso comuns .