Pergunta

Eu estou escrevendo um motor de jogo usando pygame e box2d, e no construtor personagem, eu quero ser capaz de escrever o código que será executado em eventos keydown.

Meu plano era ter um editor de texto no construtor de caráter que lhe permitem escrever código semelhante a:

if key == K_a:
    ## Move left
    pass
elif key == K_d:
    ## Move right
    pass

Vou recuperar o conteúdo do editor de texto como uma string, e eu quero o código para ser executado em um método neste método de caracteres:

def keydown(self, key):
    ## Run code from text editor

Qual é a melhor maneira de fazer isso?

Foi útil?

Solução

Você pode usar o método eval(string) para fazer isso.

Definição

eval(code, globals=None, locals=None)
O código é um código Python apenas padrão - isso significa que ele ainda precisa ser devidamente recuadas.

Os globals pode ter um __builtins__ personalizado definido, que poderia ser útil para fins de segurança.

Exemplo

eval("print('Hello')")

Será que hello de impressão para o console. Você também pode especificar variáveis ??locais e globais para o código para uso:

eval("print('Hello, %s'%name)", {}, {'name':'person-b'})

preocupações de segurança

Tenha cuidado, no entanto. Qualquer entrada do usuário será executado. Considere o seguinte:

eval("import os;os.system('sudo rm -rf /')")

Há uma série de maneiras de contornar isso. O mais fácil é fazer algo como:

eval("import os;...", {'os':None})

O que irá lançar uma exceção, em vez de apagar seu disco rígido. Enquanto o seu programa é desktop, este poderia ser um problema se as pessoas redistribuído scripts, que eu imagino se destina.

estranho Exemplo

Aqui está um exemplo do uso eval em vez estranhamente:

def hello() : print('Hello')
def world() : print('world')
CURRENT_MOOD = 'happy'

eval(get_code(), {'contrivedExample':__main__}, {'hi':hello}.update(locals()))

O que isto significa na linha eval é:

  1. Dá o módulo atual outro nome (torna-se contrivedExample para o script). O consumidor pode chamar contrivedExample.hello() agora.)
  2. Define hi como apontando para hello
  3. Combinou que dicionário com a lista de globals atuais no módulo de execução.

FALHA

Acontece (comentadores obrigado!) Que você realmente precisa usar a declaração exec. Big oops. Os exemplos revistos são os seguintes:


exec Definição

(Esta aparência! Familiarizado) Exec é uma declaração:
exec "code" [in scope] Onde escopo é um dicionário de ambas as variáveis ??locais e globais. Se isso não for especificado, ele é executado no escopo atual.

O código é o código Python apenas padrão - isso significa que ele ainda precisa ser devidamente recuadas.

exec Exemplo

exec "print('hello')"

Será que hello de impressão para o console. Você também pode especificar variáveis ??locais e globais para o código para uso:

eval "print('hello, '+name)" in {'name':'person-b'}

exec Preocupações com a segurança

Tenha cuidado, no entanto. Qualquer entrada do usuário será executado. Considere o seguinte:

exec "import os;os.system('sudo rm -rf /')"

Declaração de impressão

Como também observado por comentaristas, print é uma declaração em todas as versões do Python antes de 3.0. No 2.6, o comportamento pode ser alterado por from __future__ import print_statement digitação. Caso contrário, use:

print "hello"

Em vez de:

print("hello")

Outras dicas

Como outros apontaram, você pode carregar o texto em uma seqüência e uso exec "codestring". Se contido em um arquivo já, usando execfile vai evitar ter que carregá-lo.

Uma nota de desempenho: Você deve evitar execing as múltiplas código vezes, como analisar e compilar a fonte python é um processo lento. ie. não tem:

def keydown(self, key):
    exec user_code

Você pode melhorar esta um pouco a compilar a fonte em um objeto de código (com compile() e exec que, ou melhor, através da construção de uma função que você mantenha ao redor, e só construir uma vez. Ou exigir que o usuário escrever "def my_handler (args ...)", ou preceder-lo sozinho, e fazer algo como:

user_source = "def user_func(args):\n" + '\n'.join("    "+line for line in user_source.splitlines())

d={}
exec user_source in d
user_func = d['user_func']

Então, mais tarde:

if key == K_a:
   user_func(args)

Você pode usar eval()

eval ou exec. Você deve definitivamente ler referência da biblioteca Python antes da programação.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top