Como executo uma string contendo código Python no Python?
Como executo uma string contendo código Python no Python?
Respostas:
Para instruções, use exec(string)
(Python 2/3) ou exec string
(Python 2):
>>> mycode = 'print "hello world"'
>>> exec(mycode)
Hello world
Quando você precisar do valor de uma expressão, use eval(string)
:
>>> x = eval("2+2")
>>> x
4
No entanto, o primeiro passo deve ser se perguntar se você realmente precisa. A execução do código geralmente deve ser a posição de último recurso: é lento, feio e perigoso se puder conter código inserido pelo usuário. Você deve sempre procurar alternativas primeiro, como funções de ordem superior, para ver se elas podem atender melhor às suas necessidades.
if s=='foo': x.foo = 42 elif s=='bar': x.bar = 42
etc, que pode ser escrito como exec ("x.%s = 42" % s)
. Nesse caso comum (em que você só precisa acessar o atributo de um objeto armazenado em uma string), há uma função muito mais rápida, mais limpa e segura getattr
: basta escrever getattr(x, s) = 42
para significar a mesma coisa.
setattr(x, s, 42)
? Eu tentei getattr(x, 2) = 42
e falhou com #can't assign to function call: <string>, line 1
setattr(x, s, 42)
é a sintaxe correta. Surpreso, demorou tanto tempo para que esse erro fosse detectado. De qualquer forma, a questão é essa getattr
e setattr
é uma alternativa para exec
quando tudo o que você deseja é obter um membro arbitrário, procurado por string.
No exemplo, uma sequência é executada como código usando a função exec.
import sys
import StringIO
# create file-like string to capture output
codeOut = StringIO.StringIO()
codeErr = StringIO.StringIO()
code = """
def f(x):
x = x + 1
return x
print 'This is my output.'
"""
# capture output and errors
sys.stdout = codeOut
sys.stderr = codeErr
exec code
# restore stdout and stderr
sys.stdout = sys.__stdout__
sys.stderr = sys.__stderr__
print f(4)
s = codeErr.getvalue()
print "error:\n%s\n" % s
s = codeOut.getvalue()
print "output:\n%s" % s
codeOut.close()
codeErr.close()
exec
(a menos que saiba que a cadeia de código vem de uma fonte confiável).
eval
e exec
são a solução correta e podem ser usadas de maneira mais segura .
Conforme discutido no manual de referência do Python e explicado claramente neste tutorial, as funções eval
e exec
usam dois parâmetros extras que permitem ao usuário especificar quais funções e variáveis globais e locais estão disponíveis.
Por exemplo:
public_variable = 10
private_variable = 2
def public_function():
return "public information"
def private_function():
return "super sensitive information"
# make a list of safe functions
safe_list = ['public_variable', 'public_function']
safe_dict = dict([ (k, locals().get(k, None)) for k in safe_list ])
# add any needed builtins back in
safe_dict['len'] = len
>>> eval("public_variable+2", {"__builtins__" : None }, safe_dict)
12
>>> eval("private_variable+2", {"__builtins__" : None }, safe_dict)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1, in <module>
NameError: name 'private_variable' is not defined
>>> exec("print \"'%s' has %i characters\" % (public_function(), len(public_function()))", {"__builtins__" : None}, safe_dict)
'public information' has 18 characters
>>> exec("print \"'%s' has %i characters\" % (private_function(), len(private_function()))", {"__builtins__" : None}, safe_dict)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1, in <module>
NameError: name 'private_function' is not defined
Em essência, você está definindo o espaço para nome no qual o código será executado.
eval
ou exec
se destina a ser usado como exec(input("Type what you want"))
? Existem muitos casos em que um programa pode escrever um procedimento ou uma função como resultado de uma computação; as funções resultantes serão tão seguras e rápidas (uma vez avaliadas) quanto qualquer outra parte de um programa bom e bem escrito. Um programa inseguro contendo exec
não é mais perigoso do que um programa inseguro, causando o dano por si só, pois exec
não concede nenhum novo privilégio ao programa.
exec
eeval
exec
e eval
em Python é altamente desaprovado.Da resposta superior (ênfase minha):
Para instruções, use
exec
.Quando você precisar do valor de uma expressão, use
eval
.No entanto, o primeiro passo deve ser se perguntar se você realmente precisa. A execução do código geralmente deve ser a posição de último recurso : é lento, feio e perigoso se puder conter código inserido pelo usuário. Você deve sempre procurar alternativas primeiro, como funções de ordem superior , para ver se elas podem atender melhor às suas necessidades.
Das alternativas ao exec / eval?
definir e obter valores de variáveis com os nomes em strings
[enquanto
eval
] funcionaria, geralmente não é aconselhável usar nomes de variáveis que tenham significado para o próprio programa.Em vez disso, use melhor um ditado.
De http://lucumr.pocoo.org/2011/2/1/exec-in-python/ (ênfase minha)
Python não é PHP
Não tente burlar expressões idiomáticas do Python porque alguma outra linguagem o faz de maneira diferente. Os namespaces estão no Python por um motivo e apenas porque ele fornece a ferramenta
exec
, não significa que você deve usá-la.
De http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html (ênfase minha)
Portanto, eval não é seguro, mesmo que você remova todos os globals e os builtins!
O problema com todas essas tentativas de proteger eval () é que elas são listas negras . Eles explicitamente removem coisas que podem ser perigosas. Essa é uma batalha perdida porque se houver apenas um item da lista, você poderá atacar o sistema .
Então, a avaliação pode ser feita em segurança? Difícil de dizer. Neste ponto, meu melhor palpite é que você não pode causar nenhum dano se não puder usar sublinhados duplos; talvez, se você excluir qualquer string com sublinhados duplos, esteja seguro. Talvez...
Em http://stupidpythonideas.blogspot.it/2013/05/why-evalexec-is-bad.html (ênfase minha):
Primeiro,
exec
torna mais difícil para os seres humanos ler seu código . Para descobrir o que está acontecendo, eu não preciso apenas ler seu código, preciso ler seu código, descobrir qual string ele irá gerar e ler esse código virtual. Portanto, se você estiver trabalhando em equipe, publicando software de código aberto ou pedindo ajuda em algum lugar como o StackOverflow, está dificultando a ajuda de outras pessoas. E se houver alguma chance de você depurar ou expandir esse código daqui a seis meses, você estará dificultando diretamente a si mesmo.
cfg.yaml
):, reldir : ../my/dir/
e reldir = cfg[reldir]
. No entanto, como esse código python deve ser executado no Windows e Linux, eu preciso disso para ajustar os diferentes divisores de caminho dos sistemas operacionais; ou \\
ou /
. Então eu uso reldir : os.path.join('..','my','dir')
no arquivo de configuração. Mas isso só resulta em reldir
ser essa sequência literal, não sendo avaliada, portanto não consigo abrir um arquivo reldir
. Você tem uma sugestão?
Você executa a execução de código usando exec, como na seguinte sessão IDLE:
>>> kw = {}
>>> exec( "ret = 4" ) in kw
>>> kw['ret']
4
Como os outros mencionaram, é "exec" ..
mas, se o seu código contiver variáveis, você poderá usar "global" para acessá-lo, também para impedir que o compilador gere o seguinte erro:
NameError: o nome 'p_variable' não está definido
exec('p_variable = [1,2,3,4]')
global p_variable
print(p_variable)
Vale ressaltar, que esse exec
irmão existe também chamadoexecfile
se você quiser chamar um arquivo python. Às vezes, isso é bom se você estiver trabalhando em um pacote de terceiros com IDEs terríveis incluídos e quiser codificar fora do pacote.
Exemplo:
execfile('/path/to/source.py)'
ou:
exec(open("/path/to/source.py").read())
Confira eval :
x = 1
print eval('x+1')
->2
Eu tentei algumas coisas, mas a única coisa que funcionou foi a seguinte:
temp_dict = {}
exec("temp_dict['val'] = 10")
print(temp_dict['val'])
resultado:
10
Ok .. Eu sei que isso não é exatamente uma resposta, mas possivelmente uma nota para as pessoas que olham para isso como eu. Eu queria executar código específico para diferentes usuários / clientes, mas também queria evitar o exec / eval. Inicialmente, eu procurei armazenar o código em um banco de dados para cada usuário e fazer o acima.
Acabei criando os arquivos no sistema de arquivos em uma pasta 'customer_filters' e usando o módulo 'imp', se nenhum filtro foi aplicado a esse cliente, ele continuou
import imp
def get_customer_module(customerName='default', name='filter'):
lm = None
try:
module_name = customerName+"_"+name;
m = imp.find_module(module_name, ['customer_filters'])
lm = imp.load_module(module_name, m[0], m[1], m[2])
except:
''
#ignore, if no module is found,
return lm
m = get_customer_module(customerName, "filter")
if m is not None:
m.apply_address_filter(myobj)
para que customerName = "jj" execute o apply_address_filter a partir do arquivo customer_filters \ jj_filter.py