Como executo uma string contendo código Python no Python?

357

Como executo uma string contendo código Python no Python?

hekevintran
fonte
5
Para ser justo, ao contrário da outra pergunta, essa não é uma duplicata. E outros postaram perguntas muito mais básicas do que isso.
DNS
8
A resposta correta, é claro, é quase sempre "não!".
31909 bobince
23
@S. Lott: Você não leu o FAQ recentemente? "Também é perfeitamente bom perguntar e responder sua própria pergunta de programação, mas finja que você está no Jeopardy: expresse-o na forma de uma pergunta". Esta não é uma pergunta ruim. +1
Devin Jeanpierre
49
@ S.Lott: Você não. Você não precisa. Se a pergunta ainda não estiver no site, é um jogo justo (de acordo com o FAQ, como já apontado). Responda a todas as perguntas como se o OP precisasse de ajuda. Talvez não, mas o próximo cara que lê a pergunta provavelmente o fará. Apenas meus 2 centavos.
Bill o lagarto #
11
Para todos vocês que estão dizendo para não fazê-lo: eu tenho um caso em que eu absolutamente preciso. Envolve processamento distribuído.
Sudo

Respostas:

331

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.

Brian
fonte
11
mas e quanto ao escopo do código executado por 'exec'? está aninhado?
Jdinham #
21
Um caso comum em que alguém deseja usar 'exec' é algo como if s=='foo': x.foo = 42 elif s=='bar': x.bar = 42etc, 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) = 42para significar a mesma coisa.
ShreevatsaR
5
Como o exec é mais lento que o interpretador python?
precisa
6
@ShreevatsaR você não quer dizer setattr(x, s, 42)? Eu tentei getattr(x, 2) = 42e falhou com #can't assign to function call: <string>, line 1
Tanner Semerad 11/10
6
@ Tanner: Hmm. Sim, de fato, setattr(x, s, 42)é a sintaxe correta. Surpreso, demorou tanto tempo para que esse erro fosse detectado. De qualquer forma, a questão é essa getattre setattré uma alternativa para execquando tudo o que você deseja é obter um membro arbitrário, procurado por string.
ShreevatsaR
68

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()
hekevintran
fonte
11
trocar stdout e stderr assim me deixa muito nervoso. isso pode causar enormes problemas de segurança. Existe uma maneira de contornar isso?
Narcolapser 23/05
11
@Narcolapser, você deve se interessar mais em usar exec(a menos que saiba que a cadeia de código vem de uma fonte confiável).
bruno desthuilliers
27

evale execsã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 evale execusam 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.

Alan
fonte
9
Não é possível tornar eval seguro: Eval é realmente perigoso . Se você pegar o código de mim e avaliá-lo, posso segmentar o seu programa em Python. Fim de jogo.
Ned Batchelder
3
@ v.oddou Eu estava respondendo à declaração de Alan, "eval e exec .. podem ser usados ​​de maneira segura". Isto é falso. Se alguém dissesse "bash pode ser usado de maneira segura", isso também seria falso. Bash é perigoso. É um perigo necessário, mas perigoso, no entanto. Afirmar que a avaliação pode ser feita com segurança é simplesmente errado.
Ned Batchelder
11
@NedBatchelder sim, de fato. e o link para o qual você aponta é um bom material. com poder vem a responsabilidade, portanto, o ponto é simplesmente estar ciente do poder potencial de avaliar. e se decidirmos que poder = perigo.
precisa saber é o seguinte
3
@NedBatchelder Muitos trechos de código escritos em Python também podem ser perigosos, mas por que você está assumindo isso evalou execse 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 execnão é mais perigoso do que um programa inseguro, causando o dano por si só, pois execnão concede nenhum novo privilégio ao programa.
Thomas Baruchel
11
@ThomasBaruchel novamente, meu argumento é contrariar a noção de que eval ou exec possam ser salvaguardados. Em particular, esta resposta alega que controlar os globais e locais tornará possível usá-los com segurança. Isso é falso. Sempre que você usa exec e eval, precisa saber com precisão qual código está sendo executado. Caso contrário, você estará aberto a operações perigosas.
Ned Batchelder
21

Lembre-se de que a versão 3 execé uma função!
então sempre use em exec(mystring)vez de exec mystring.

bheks
fonte
11

eval()é apenas para expressões, enquanto eval('x+1')funciona, eval('x=1')não funciona, por exemplo. Nesse caso, é melhor usar exec, ou até melhor: tente encontrar uma solução melhor :)

LGB
fonte
11

Evite execeeval

Usar exece evalem Python é altamente desaprovado.

Existem melhores alternativas

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.

Não é idiomático

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.

É perigoso

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...

É difícil ler e entender

Em http://stupidpythonideas.blogspot.it/2013/05/why-evalexec-is-bad.html (ênfase minha):

Primeiro, exectorna 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.

Caridorc
fonte
"meu melhor palpite é que você não pode causar nenhum dano se não puder usar sublinhados duplos" - você pode construir uma sequência que contenha sublinhados duplos e, em seguida, chame eval dessa sequência.
Stanley Bak
um bom conselho, a menos que você esteja escrevendo um gerador de código, candidato a emprego ou semelhante ... o que a maioria das pessoas aqui provavelmente está fazendo.
Erik Aronesty
Eu tenho que importar um caminho relativo de um arquivo de configuração ( 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 reldirser essa sequência literal, não sendo avaliada, portanto não consigo abrir um arquivo reldir. Você tem uma sugestão?
Marie. P.
9

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
gus
fonte
11
Isso não funciona em python normal. Ao não menos importante em python 3.
Thomas Ahle
6

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)
Ghanem
fonte
5

Use eval .

Pablo Santa Cruz
fonte
7
Eval () não executa instruções.
precisa saber é o seguinte
4

Vale ressaltar, que esse execirmã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())

user1767754
fonte
3

Confira eval :

x = 1
print eval('x+1')
->2
ryeguy
fonte
10
Eval () não executa instruções.
precisa saber é o seguinte
1

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

paul-shuvo
fonte
0

A solução mais lógica seria usar a função eval () integrada. Outra solução é gravar essa sequência em um arquivo python temporário e executá-la.

John T
fonte
0

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

Brian
fonte
11
Como você gerencia a segurança? Como você sabe que os clientes não abusarão desse privilégio?
JSBach 14/05