Question

J'écris un moteur de jeu en utilisant pygame et box2d et, dans l'éditeur de personnages, je veux pouvoir écrire le code qui sera exécuté lors d'événements de raccourci.

Mon plan était d'avoir un éditeur de texte dans le générateur de caractères vous permettant d'écrire du code similaire à:

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

Je vais récupérer le contenu de l'éditeur de texte sous forme de chaîne et je veux que le code soit exécuté dans une méthode de cette méthode de Caractère:

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

Quelle est la meilleure façon de faire cela?

Était-ce utile?

La solution

Vous pouvez utiliser le eval (chaîne) méthode pour le faire.

Définition

eval (code, globals = None, locals = None)
Le code est simplement du code Python standard - cela signifie qu'il doit toujours être correctement mis en retrait.

Les globales peuvent avoir un __ intégré __ personnalisé, ce qui pourrait être utile à des fins de sécurité.

Exemple

eval("print('Hello')")

Affiche hello sur la console. Vous pouvez également spécifier des variables locales et globales pour le code à utiliser:

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

Problèmes de sécurité

Soyez prudent, cependant. Toute entrée de l'utilisateur sera exécutée. Considérez:

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

Il y a plusieurs façons de contourner ce problème. Le plus simple est de faire quelque chose comme:

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

Ce qui lancera une exception, plutôt que d’effacer votre disque dur. Bien que votre programme soit un ordinateur de bureau, cela pourrait poser un problème si les gens redistribuaient les scripts, ce que j’imagine bien vouloir.

Exemple étrange

Voici un exemple d'utilisation de eval plutôt étrange:

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

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

Ce que cela fait sur la ligne d'évaluation est:

  1. Donne un autre nom au module actuel (il devient contrivedExample dans le script). Le consommateur peut appeler contrivedExample.hello () maintenant.)
  2. Cela définit hi comme pointant sur hello
  3. Il a combiné ce dictionnaire avec la liste des globales actuelles du module en cours d'exécution.

ECHEC

Il s'avère (merci aux commentateurs!) que vous devez réellement utiliser l'instruction exec . Big oops. Les exemples révisés sont les suivants:

exec Définition

(Cela semble familier!) Exec est une déclaration:
exec " code " [dans le champ d'application] Où scope est un dictionnaire de variables locales et globales. S'il n'est pas spécifié, il s'exécute dans la portée actuelle.

Le code est simplement du code Python standard. Cela signifie qu'il doit encore être mis en retrait correctement.

exec Exemple

exec "print('hello')"

Affiche hello sur la console. Vous pouvez également spécifier des variables locales et globales pour le code à utiliser:

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

exec Problèmes de sécurité

Soyez prudent, cependant. Toute entrée de l'utilisateur sera exécutée. Considérez:

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

Imprimer la déclaration

Comme l'ont également noté les commentateurs, print est une instruction dans toutes les versions de Python antérieures à la version 3.0. En 2.6, le comportement peut être modifié en tapant à partir de __future__ import print_statement . Sinon, utilisez:

print "hello"

Au lieu de:

print("hello")

Autres conseils

Comme d'autres l'ont déjà fait remarquer, vous pouvez charger le texte dans une chaîne et utiliser exec "codestring" . S'il est déjà contenu dans un fichier, utilisez execfile pour éviter de le charger.

Une note de performance: évitez d'exécuter le code plusieurs fois, car l'analyse et la compilation de la source python sont des processus lents. c'est à dire. ne pas avoir:

def keydown(self, key):
    exec user_code

Vous pouvez améliorer un peu cela en compilant la source dans un objet code (avec compile () ) et l'exécuter, ou mieux, en construisant une fonction que vous conservez, et ne le construisez qu'une seule fois. Soit obliger l’utilisateur à écrire "def my_handler (args ...)" ou à l’ajouter soi-même et à faire quelque chose comme:

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']

Puis plus tard:

if key == K_a:
   user_func(args)

Vous pouvez utiliser eval ()

eval ou exec. Vous devez absolument lire les références de la bibliothèque Python avant de programmer.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top