Выполнение кода Python, содержащегося в строке
Вопрос
Я пишу игровой движок, используя pygame и box2d, и в конструкторе персонажей я хочу написать код, который будет выполняться при событиях нажатия клавиш.
Я планировал создать текстовый редактор в конструкторе символов, который позволял бы писать код, подобный следующему:
if key == K_a:
## Move left
pass
elif key == K_d:
## Move right
pass
Я получу содержимое текстового редактора в виде строки и хочу, чтобы код выполнялся в методе этого метода Character:
def keydown(self, key):
## Run code from text editor
Какой лучший способ сделать это?
Решение
Вы можете использовать eval (string)
Способ сделать это. Р>
Определение
eval (code, globals = None, localals = None)
Код является просто стандартным кодом Python - это означает, что он все еще должен быть правильно отступ. Р>
Глобальные переменные могут иметь пользовательские __ builtins __
, которые могут быть полезны в целях безопасности.
Пример
eval("print('Hello')")
выведет hello
на консоль. Вы также можете указать локальные и глобальные переменные для используемого кода:
eval("print('Hello, %s'%name)", {}, {'name':'person-b'})
Проблемы безопасности
Будьте осторожны. Любой пользовательский ввод будет выполнен. Рассмотрим:
eval("import os;os.system('sudo rm -rf /')")
Есть несколько способов обойти это. Проще всего сделать что-то вроде:
eval("import os;...", {'os':None})
Который будет выбрасывать исключение, а не стирать ваш жесткий диск. В то время как ваша программа является настольной, это может быть проблемой, если люди распространяют сценарии, что, я думаю, предназначено. Р>
Странный пример
Вот пример довольно странного использования eval
:
def hello() : print('Hello')
def world() : print('world')
CURRENT_MOOD = 'happy'
eval(get_code(), {'contrivedExample':__main__}, {'hi':hello}.update(locals()))
Что это делает в строке eval:
<Ол> contrivedExample
для скрипта). Теперь потребитель может вызвать contrivedExample.hello ()
.) hi
как указывающий на привет
СБОЙ
Оказывается (спасибо, комментаторы!), что вам действительно нужно использовать оператор exec
. Большой ой. Пересмотренные примеры следующие:
exec
Определение
(это выглядит знакомо!)
Exec это заявление:
exec " code " [в области видимости]
Где область действия - это словарь локальных и глобальных переменных. Если это не указано, оно выполняется в текущей области.
Код является просто стандартным кодом Python - это означает, что он все еще должен быть правильно отступ. Р>
exec
Пример
exec "print('hello')"
выведет hello
на консоль. Вы также можете указать локальные и глобальные переменные для используемого кода:
eval "print('hello, '+name)" in {'name':'person-b'}
exec
Проблемы безопасности
Будьте осторожны. Любой пользовательский ввод будет выполнен. Рассмотрим:
exec "import os;os.system('sudo rm -rf /')"
<Ч>
Распечатать заявление
Как также отметили комментаторы, print
- это утверждение во всех версиях Python до 3.0. В 2.6 поведение можно изменить, набрав из __future__ import print_statement
. В противном случае используйте:
print "hello"
Вместо:
print("hello")
Другие советы
Как уже отмечали другие, вы можете загрузить текст в строку и использовать exec " codestring "
. Если он уже содержится в файле, использование execfile позволит избежать его загрузки. р>
Одно замечание по производительности: вам следует избегать многократного выполнения кода, так как разбор и компиляция исходного кода Python - это медленный процесс. то есть. не иметь:
def keydown(self, key):
exec user_code
Вы можете немного улучшить это, скомпилировав исходный код в объект кода (с помощью compile ()
и выполнив это, или лучше, создав функцию, которую вы храните, и собираете только один раз. Либо потребуйте, чтобы пользователь написал " def my_handler (args ...) ", либо добавьте его самостоятельно, и сделайте что-то вроде:
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']
Потом позже:
if key == K_a:
user_func(args)
Вы можете использовать eval ()
р>
eval или exec. Вы обязательно должны прочитать справочник по библиотеке Python перед программированием.