I'm writing a game engine using pygame and box2d, and in the character builder, I want to be able to write the code that will be executed on keydown events.
My plan was to have a text editor in the character builder that let you write code similar to:
if key == K_a:
## Move left
pass
elif key == K_d:
## Move right
pass
I will retrieve the contents of the text editor as a string, and I want the code to be run in a method in this method of Character:
def keydown(self, key):
## Run code from text editor
What's the best way to do that?
You can use the
eval(string)
method to do this.Definition
eval(code, globals=None, locals=None)
The code is just standard Python code - this means that it still needs to be properly indented.
The globals can have a custom
__builtins__
defined, which could be useful for security purposes.Example
Would print
hello
to the console. You can also specify local and global variables for the code to use:Security Concerns
Be careful, though. Any user input will be executed. Consider:
There are a number of ways around that. The easiest is to do something like:
Which will throw an exception, rather than erasing your hard drive. While your program is desktop, this could be a problem if people redistributed scripts, which I imagine is intended.
Strange Example
Here's an example of using
eval
rather strangely:What this does on the eval line is:
contrivedExample
to the script). The consumer can callcontrivedExample.hello()
now.)hi
as pointing tohello
FAIL
It turns out (thanks commenters!) that you actually need to use the
exec
statement. Big oops. The revised examples are as follows:exec
Definition(This looks familiar!) Exec is a statement:
exec "code" [in scope]
Where scope is a dictionary of both local and global variables. If this is not specified, it executes in the current scope.The code is just standard Python code - this means that it still needs to be properly indented.
exec
ExampleWould print
hello
to the console. You can also specify local and global variables for the code to use:exec
Security ConcernsBe careful, though. Any user input will be executed. Consider:
Print Statement
As also noted by commenters,
print
is a statement in all versions of Python prior to 3.0. In 2.6, the behaviour can be changed by typingfrom __future__ import print_statement
. Otherwise, use:Instead of :
As others have pointed out, you can load the text into a string and use
exec "codestring"
. If contained in a file already, using execfile will avoid having to load it.One performance note: You should avoid execing the code multiple times, as parsing and compiling the python source is a slow process. ie. don't have:
You can improve this a little by compiling the source into a code object (with
compile()
and exec that, or better, by constructing a function that you keep around, and only build once. Either require the user to write "def my_handler(args...)", or prepend it yourself, and do something like:Then later:
You can use
eval()
eval or exec. You should definitely read Python library reference before programming.