В эти выходные я разрывал на куски Michele Simionato модуль декоратора, который создает декораторы, сохраняющие подпись. В основе всего этого есть динамически сгенерированная функция, которая работает с чем-то подобным...
src = """def function(a,b,c) :\n return _caller_(a,b,c)\n"""
evaldict = {'_caller_' : _caller_}
code = compile(src, '<string>', 'single')
exec code in evaldict
new_func = evaldict[function]
Я нашел, обманывая этим кодом, что шаг компиляции можно полностью избежать и перейти на один:
exec src in evaldict
Теперь я уверен, что есть веская причина для этого дополнительного шага, но я не смог найти, какая разница между обоими подходами. Производительность?
И так как я спрашиваю, может ли что-то подобное, т.е. определить новую функцию и получить ручку к ней, достичь с помощью eval? Я попытался, но не мог заставить это работать...
Есть несколько различий, которые я вижу. Во-первых, compile
имеет немного лучшую семантику перед ошибками синтаксиса, чем exec
. Я подозреваю, что истинная причина в том, что определение compile
очень явное в отношении обработки новых символов строки, где exec
является немного менее точным.
Мне было любопытно, почему compile
и exec
, где используются вместо внутренних функций. Я не знал, что compile
/exec
позволяет вам контролировать, какие глобальные значения доступны. Очень интересно.
compile() позволяет вам управлять созданным объектом кода и его именем и источником, в то время как exec не является настолько гибким. это также стоит сделать так, чтобы другие, читая ваш код, узнали, что они являются отдельными шагами, и подумайте об этом позже, когда им нужно выполнить один и тот же код более одного раза (где compile() один раз, exec несколько раз будет быстрее), и написав свой код для обучения следующего, кто читает, он всегда оказывает достойное влияние на выбор дизайна.
compile
будет быстрее, если вы вызываетеexec
несколько раз с одним и тем же источником.exec
вызванный со строкой, скомпилирует строку в байтовый код и затем выполнит ее. Компиляция будет происходить при каждом вызове.