Загрузить код python во время выполнения

Я хочу загрузить файл .py во время выполнения. Этот файл .py представляет собой в основном конфигурационный файл со следующим форматом:

var1=value  
var2=value  
predicate_function=func line : <return true or false>  

Как только этот файл будет загружен, я хотел бы иметь доступ к var1, var2 и predicate_function. Для каждой строки я передам ее функции предиката, и если она вернет false, я проигнорирую ее.

В любом случае, я не уверен, как загрузить файл python во время выполнения и получить доступ к его переменным.

Разъяснение: может быть любое количество этих конфигурационных файлов, которые мне нужно передать в основную программу, и я не буду знать их имена до времени выполнения. Google говорит мне, что я должен использовать __import__. Я не уверен, как правильно использовать этот метод, а затем получить доступ к переменным импортируемого файла.

Ответы

Ответ 1

Вам просто нужно иметь возможность динамически указывать импорт, а затем динамически получать переменные.

Скажем, ваш файл конфигурации bar.py и выглядит так:

x = 3
y = 4
def f(x): return (x<4)

Затем ваш код должен выглядеть так:

import sys

# somehow modnames should be a list of strings that are the names of config files
#
# you can do this more dynamically depending on what you're doing                                                                                                     
modnames = ['bar']

for modname in modnames:
  exec('import %s' % modname)

for modname in modnames:
  mod = sys.modules[modname]
  for k in mod.__dict__:
    if k[:2] != '__':
      print modname, k, mod.__dict__[k]

Я получаю этот вывод:

bar f <function f at 0x7f2354eb4cf8>
bar x 3
bar y 4

Тогда вы, по крайней мере, имеете все переменные и функции. Я не совсем понял, что вы хотели от функций предиката, но, возможно, вы можете получить это самостоятельно.

Ответ 2

Как написано в официальной документации python, если вы просто хотите импортировать модуль по имени, вы можете найти его в sys.modules после использования __import__.

Предположим, что ваша конфигурация находится в myproject.mymodule, вы бы сделали так:

module_name = 'myproject.mymodule'

import sys
__import__(module_name)
mymodule = sys.modules[module_name]

# Then you can just access your variables and functions
print mymodule.var1
print mymodule.var2
# etc...

Вы также можете использовать возвращаемое значение оператора __import__, но вам нужно будет полностью понять как работает python с пространствами имен и областями.

Ответ 3

Чтобы получить доступ к другому модулю Python, вы импортируете его. execfile упоминается несколькими людьми, но это грязно и опасно. execfile помешает вашему пространству имен, возможно, даже испортить код, который вы используете. Если вы хотите получить доступ к другому исходному файлу Python, используйте оператор import.

Еще лучше было бы не использовать файл Python для конфигурации вообще, а скорее использовать встроенный модуль ConfigParser или формат сериализации, такой как JSON. Таким образом, ваши файлы конфигурации не позволяют выполнять произвольный (возможно, вредоносный) код, не требуют от людей знать Python для настройки вашей программы и могут легко изменяться программно.

Ответ 4

Если импортированный модуль находится на обычном пути поиска, вы можете использовать __import__.

Если вам нужно загрузить модуль с произвольного пути в файловой системе, используйте imp.load_module.

Обязательно учитывайте последствия для безопасности при загрузке произвольного пользовательского кода.

Ответ 5

В Python 2.*, execfile работает (я рекомендую передать конкретный словарь и получить доступ к переменным оттуда - в качестве примечание в документах говорит, execfile не может повлиять на функцию вызова locals()).

В Python 3.*, execfile был удален, так что, вместо этого:

with open('thefile.py') as f:
  exec(f.read(), somedict)

Ответ 6

Я немного опаздываю на вечеринку, но тем не менее я хочу представить альтернативный ответ.

Если вы хотите импортировать код, не затрагивая пространство имен глобальных модулей, вы можете создать анонимный модуль (используя types.ModuleType) и загрузить в него произвольный код (используя compile и exec). Например, например:

import types

filename = "/path/to/your/file.py"
with open(filename) as fp:
    code = compile(fp.read(), filename, "exec")
config_module = types.ModuleType("<config>")
exec code in config_module.__dict__

Затем вы можете получить доступ к переменным как config_module.var1, & c.

Ответ 7

Если вы хотите иметь файл конфигурации, который будет редактировать только пользователь, когда программа не будет запущена, просто импортируйте его как обычный файл python

т.

main.py:

import config
print config.var1

config.py:

var="var12"
var2 = 100.5

Ответ 9

Поскольку версия Python не была четко упомянута, стоит отметить, что модуль imp устарел в новых версиях Python в пользу importlib. Пример здесь.