2012-03-22 80 views
4

我一直在学习python的一些动态'插件加载',并注意到import modulefrom package import module之间没有什么问题,而是一个有趣的区别。`import module`和`from package import module`之间的区别

我创建了由四个文件(就像我自己的设置为我想要达到的)

文件树看起来像这样一个测试脚本:

  • 测试(主包)
    • SUP(包,插件文件夹)
      • __init__.py
      • uber.py(插件)
    • __init__.py
    • bar.py('main'程序)
    • foo.py(需要动态地增加功能对象)
    • poo.py(装饰)

poo.py:

from test import foo 

def decorate(method): 
    print "before:", method.__name__ in dir(foo.Foo) 
    setattr(foo.Foo, method.__name__, method) 
    print "after :", method.__name__ in dir(foo.Foo) 
    return method 

foo.py:

import os 

class Foo(object): 

    def __init__(self): 
     self.__loadplugins("sup") 

    @classmethod 
    def __loadplugins(cls, plugindir): 
     for f in os.listdir(os.path.join(os.path.dirname(__file__), plugindir)): 
      if f.endswith(".py"): 
       __import__(("%s.%s" % (plugindir, f))[0:-3]) 

uber.py:

from test import poo 

@poo.decorate 
def aFunction(self, anArg): 
    print anArg 

我有bar.py的两个版本,这一个不工作:

import foo 

f = foo.Foo() 

f.aFunction("print goes here") # pylint: disable-msg=E1101 

这个人做的工作:

from test import foo 

f = foo.Foo() 

f.aFunction("print goes here") # pylint: disable-msg=E1101 

这两个柱之间的唯一区别是导入。一个是相对的,另一个不是。但是相对的不起作用,而绝对的起作用。有没有人可以在他的机器上复制这些信息,并且可以对它发生的原因进行某种解释?

更新
认为这将是有用的,也注意到我的Python版本: 使用普通的Python 2.7.2版本的x86

更新
输出 '错误' bar.py的:

before: False 
after : True 
Traceback (most recent call last): 
    File "C:\Users\Daan\workspace\python\mytests\src\test\bar.py", line 6, in <module> 
    f.aFunction("print goes here") # pylint: disable-msg=E1101 
AttributeError: 'Foo' object has no attribute 'aFunction' 

输出 '正确的' 的bar.py:

before: False 
after : True 
print goes here 
+0

尝试添加一个空文件名为test目录'__init __。py' – vascop 2012-03-22 21:48:48

+0

它们的存在。懒惰把它们放在那个List中。但特别为你我会添加它们。 – 2012-03-22 21:52:30

+0

你说第一个不起作用是什么意思?如果你看到一个例外,请包括回溯。 – subdir 2012-03-22 22:33:43

回答

3

我假设你在'test'目录内,并且有环境变量PYTHONPATH = ..(这样你就可以同时执行'import foo'和'test import foo')。

在这种情况下,foo和test.foo是两个不同的模块,分别加载(尽管事实上它们是从同一个文件加载的)。

test.poo模块的'decorate'函数向test.foo中的类'Foo'添加方法(第一行poo.py:“from test import foo”),同时'Foo'类从foo模块保持不变。

+0

是的,你的第一个假设是正确的。在Eclipse中有一个位于pythonpath中的'src'目录。测试是一个包,我运行bar.py作为python运行。 – 2012-03-23 10:28:38

+0

好吧,我想我回答你的问题? – subdir 2012-03-24 02:50:46

+0

我必须先测试他们,还没有时间来尝试所有的答案呢:-) – 2012-03-24 14:07:53

1

你是怎么执行bar.py的?我假设你将把它作为一个包来运行,因为这就是你设计它的方式。否则,在bar.py的第二个版本中,from test import foo没有什么意义,因为test不会被bar.py识别,除非它作为一个包运行。

查看关于Intra-package references的python文档。他们主要谈两种参考。说,你正试图从foo.py中导入uber.py。一种方法是通过明确的相关参考from .sup import uber。另一种方式来做到这一点,是绝对的参考,这将是形式from test.sup import uberimport test.sup.uber

它看起来像您正在使用除foo.py通过了绝对引用。在这里,你正在有效地呼叫__import__('sup.uber'),因为它应该是__import__('test.sup.uber')。我不确定是否这是导致您报告的错误的原因,但是我能够使用两个版本的bar.py来运行,使用

我在foo.py中使用这两个版本的bar.py

__import__(("%s.%s" % ('test.'+plugindir, f))[0:-3]) 

另外,你如何运行bar.py作为一个包?一种方法是在test目录之外的脚本中包含import test.bar行,然后运行它。

0

简短的回答你的问题:

是否有任何人谁可以在他的机器上复制这一点,可以给某种的原因是什么,解释?

是的。 :-)

稍长:

是的 - 我能够重现它。

这里我解释:

在第一种情况下(发生错误),蟒蛇包括模块foo两次(你可以检查,很容易使用打印语句)。第二次创建类FooaFunction被添加到第二个化身 - 仍然主程序使用第一个化身。

在第二种情况下,模块foo仅被读入一次 - 因此Foo类只存在一次。使用该类的相同化身添加aFunction并在主体中使用。

导入文件两次的原因是恕我直言模块有点奇怪的排列。看起来对于python而言,foo模块的内部使用路径/名称在第一个示例中有所不同。

(我用了很多的id(foo.Foo)printglobals()得到这个整理出来。)

相关问题