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

<p>я хотел бы загрузить файл <code>.py</code> во время выполнения. этот файл <code>.py</code> в основном является файлом конфигурации в следующем формате:</p><pre><code>var1=value var2=value predicate\_function=func line : <return true or false> </code></pre><p>после загрузки этого файла я хотел бы получить доступ к <code>var1</code>, <code>var2</code> и <code>predicate\_function</code>. для каждой строки я передам ее функции предиката, и если она вернет false, я ее проигнорирую.</p><p>в любом случае, я не уверен, как загрузить файл python во время выполнения и получить доступ к его переменным.</p><p>пояснение: может быть любое количество этих конфигурационных файлов, которые мне нужно передать основной программе, и я не буду знать их имена до времени выполнения. google говорит мне, что я должен использовать <code>\_\_import\_\_</code>. я не уверен, как правильно использовать этот метод, а затем получить доступ к переменным импортированного файла.</p>

<p>вам просто нужно иметь возможность динамически определять импорт, а затем динамически получать переменные.</p><p>допустим, ваш конфигурационный файл bar.py и выглядит так:</p><pre><code>x = 3 y = 4 def f(x): return (x<4) </code></pre><p>тогда ваш код должен выглядеть так:</p><pre><code>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] </code></pre><p>я получаю этот вывод:</p><pre><code>bar f <function f at 0x7f2354eb4cf8> bar x 3 bar y 4 </code></pre><p>тогда у вас как минимум есть все переменные и функции. я не совсем получил то, что вы хотели от функций предикатов, но, возможно, вы можете получить это самостоятельно.</p>

<p>как написано в <a href="http://docs.python.org/library/functions.html#\_\_import\_\_">официальная документация python</a> , если вы просто хотите импортировать модуль по имени, вы можете найти его в словаре <code>sys.modules</code> после использования <code>\_\_import\_\_</code>.</p><p>предположим, что ваша конфигурация находится в <code>myproject.mymodule</code>, вам нужно сделать так:</p><pre><code>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... </code></pre><p>вы также можете использовать возвращаемое значение оператора <code>\_\_import\_\_</code>, но вам необходимо полностью понять <a href="http://docs.python.org/reference/executionmodel.html">как python работает с пространствами имен и областями видимости</a> .</p>

<p>если импортированный модуль находится на обычном пути поиска, вы можете использовать <a href="http://docs.python.org/library/functions.html?highlight=\_\_import\_\_#\_\_import\_\_"><code>\_\_import\_\_</code></a> .</p><p>если вам нужно загрузить модуль по произвольному пути в файловой системе, используйте <a href="http://docs.python.org/library/imp.html?highlight=\_\_import\_\_#imp.load\_module"><code>imp.load\_module</code></a> .</p><p>обязательно учтите последствия для безопасности загрузки произвольного пользовательского кода.</p>

<p>чтобы получить доступ к другому модулю python, вы <em>импортируете его</em>. <code>execfile</code> была упомянута парой людей, но это грязно и опасно. <code>execfile</code> загромождает ваше пространство имен, возможно, даже портит код, который вы запускаете. если вы хотите получить доступ к другому исходному файлу python, используйте оператор <code>import</code>.</p><p>еще лучше было бы вообще не использовать файл python для конфигурации, а использовать встроенный модуль <code>configparser</code> или формат сериализации, такой как json. таким образом, ваши файлы конфигурации не позволяют выполнять произвольный (возможно, вредоносный) код, не требуют, чтобы люди знали python, чтобы сконфигурировать вашу программу, и могут быть легко изменены программно.</p>

<p>в python <code>2.*</code>, <a href="http://docs.python.org/library/functions.html?highlight=execfile#execfile">execfile</a> работает (я рекомендую передать определенный словарь и получить доступ к переменным оттуда - как говорится в примечании в документации, <code>execfile</code> не может влиять на вызывающую функцию <code>locals()</code> словарь).</p><p>в python <code>3.*</code> execfile был удален, так что вместо этого:</p><pre><code>with open('thefile.py') as f: exec(f.read(), somedict) </code></pre>

<p>я опаздываю на вечеринку, но, тем не менее, хочу представить альтернативный ответ.</p><p>если вы хотите импортировать код, не влияя на глобальное пространство имен модуля, вы можете создать анонимный модуль (используя <code>types.moduletype</code>) и загрузить в него произвольный код (используя <code>compile</code> и <code>exec</code>). например, вот так:</p><pre><code>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\_\_ </code></pre><p>затем вы можете получить доступ к переменным как <code>config\_module.var1</code>, & c.</p>

<p>если вы хотите иметь файл конфигурации, который будет редактироваться пользователем, только когда программа не запущена, просто импортируйте его как обычный python файл</p><p>то есть.</p><p>main.py:</p><pre><code>import config print config.var1 </code></pre><p>config.py:</p><pre><code>var="var12" var2 = 100.5 </code></pre>

<p>попробуйте модуль imp: <a href="http://docs.python.org/library/imp.html">http://docs.python.org/library/imp.html</a> </p>

<p>поскольку версия python четко не упомянута, стоит отметить, что модуль <strong> imp </strong> устарел в более новых python версии в пользу модуля <a href="https://docs.python.org/3/library/importlib.html"><strong> importlib </strong></a> . <a href="https://thomassileo.name/blog/2012/12/21/dynamically-load-python-modules-or-classes/">пример здесь.</a> </p>