загрузить код Python во время выполнения - PullRequest
16 голосов
/ 14 февраля 2010

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

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

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

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

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

Ответы [ 9 ]

14 голосов
/ 14 февраля 2010

Как написано в официальной документации 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 работает с пространствами имен и областями действия .

10 голосов
/ 14 февраля 2010

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

Допустим, ваш конфигурационный файл 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

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

7 голосов
/ 14 февраля 2010

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

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

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

7 голосов
/ 14 февраля 2010

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

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

2 голосов
/ 09 апреля 2014

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

Если вы хотите импортировать код, не влияя на глобальное пространство имен модуля, вы можете создать анонимный модуль (используя 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.

2 голосов
/ 14 февраля 2010

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

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

with open('thefile.py') as f:
  exec(f.read(), somedict)
1 голос
/ 14 февраля 2010

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

т.

main.py:

import config
print config.var1
* 1007 config.py *:
var="var12"
var2 = 100.5
0 голосов
/ 02 октября 2016

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

0 голосов
/ 05 февраля 2011

попробуйте модуль imp: http://docs.python.org/library/imp.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...