`import module`和`from package import module`之间的区别

时间:2012-03-22 21:44:45

标签: python

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

我创建了一个包含四个文件的测试脚本(类似于我想要实现的设置)

文件树如下所示:

  • 测试(主包)
    • sup(包,插件文件夹)
      • __初始化__。PY
      • uber.py(插件)
    • __初始化__。PY
    • bar.py('main'-program)
    • 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

3 个答案:

答案 0 :(得分:3)

我假设你在'test'目录中并且有环境变量PYTHONPATH = ..(所以你可以同时'import foo'和'from test import foo')。

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

test.poo模块中的

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

答案 1 :(得分:1)

你是如何执行bar.py的?我假设你将把它作为一个包运行,因为这就是你设计它的方式。或者,第二版bar.py中的from test import foo没有多大意义,因为bar.py无法识别test,除非它作为包运行。

查看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来运行,

我在bar.py

中使用了这两个版本的foo.py
__import__(("%s.%s" % ('test.'+plugindir, f))[0:-3])

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

答案 2 :(得分:0)

对你的问题的简短回答:

  

是否有人可以在他的机器上复制这个并且可以解释为什么会发生这种情况?

是。 : - )

稍长一点:

是的 - 我能够重现它。

我的解释是:

在第一种情况下(发生错误的地方),python包含模块foo两次(您可以使用print语句轻松检查)。类Foo是第二次创建的,aFunction被添加到第二个版本 - 主程序仍然使用第一个。

在第二种情况下,模块foo仅被读入一次 - 因此Foo类仅存在一次。该类的相同版本用于添加aFunction和主要。

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

(我使用了很多print id(foo.Foo)globals()来解决这个问题。)