用Python创建匿名模块

时间:2011-07-23 20:05:20

标签: python

编辑:我已经添加了一些关于我为什么要这样做的信息。

以下示例代码纯粹是出于示例目的。最后,我需要让我的代码遍历一个目录结构,当它找到一个python文件时,导入该文件以从中获取数据和可能的函数定义。然后在确定如何处理目录中的其余文件(HTML模板等)时使用它。

因为这个想法是为了使目录结构更适合于保存HTML模板和图像,而python文件实际上更像是一个数据容器(虽然每一次都会有一些功能方面的逻辑),我不想在所有地方都有__init__.py文件以确保python模块是包的一部分,我觉得搞乱sys.path是错误的解决方案(可能有“meta .py“多个目录中的文件。”

所以,我觉得加载一个python文件的源代码是最好的解决方案。这个问题就是我在下面展示的内容。

想象一下,我有代码执行以下操作:

main.py:

import imp

a = imp.load_source('blah', 'a.py')
print dir(a)
b = imp.load_source('blah', 'b.py')
print dir(b)

a.py:

a = 'a'

b.py:

b = 'b'

运行main.py的结果是:

['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'a']
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'a', 'b']

我希望发生的是第二次调用load_source会创建一个 new 模块并返回它,但看起来它实际上会覆盖现有模块。

目前,我的解决方案是将load_source函数中的'blah'字符串更改为这些模块不会共享的名称(例如文件名),但我想知道是否有更好的方法。< / p>

2 个答案:

答案 0 :(得分:6)

Mark,据我所知,如果imp.load_source()可以导入一个名为“blah”的模块覆盖以前的导入。好吧,你不能通过imp.load_source()来做到这一点,原因如下:

看一下Python的import.c源代码的一部分:

PyObject *
PyImport_ExecCodeModuleEx(char *name, PyObject *co, char *pathname)
{
   PyObject *modules = PyImport_GetModuleDict();
   PyObject *m, *d, *v;

   m = PyImport_AddModule(name);
   if (m == NULL)
       return NULL;
   /* If the module is being reloaded, we get the old module back
      and re-use its dict to exec the new code. */ 
   d = PyModule_GetDict(m);
   if (PyDict_GetItemString(d, "__builtins__") == NULL) {
       if (PyDict_SetItemString(d, "__builtins__",
                                PyEval_GetBuiltins()) != 0)
           goto error;
   }
   ...
   ...

您是否注意到有关重新加载模块的评论?因此,一种清晰且非hackish 的方式来做你要求的,就是在导入b.py时使用另一个名称而不是“blah”。

答案 1 :(得分:1)

不要对不同的模块使用相同的名称。你可以用例如os.path.splitext获取文件名并使用它,或者只是组成一个名称。

更具体地说,load_source的第一个参数是模块的名称,如ossys。您告诉imp导入它假定的相同模块,但是来自不同的文件。它有点奇怪,它不会从头重新导入它,但我想这是一个重新加载优化?请注意,sys.modules将填充新模块为“blah”,而不是“a”。


您确定要使用Python文件吗?在不了解你的模板引擎的情况下,我真的无法说出任何内容,但如果你只是如此,它可能会更简单。用于设置的目录层次结构中的csv或ini样式文件。