Вопрос

Я пишу игровой движок, используя 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 перед программированием.

    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top