2012-03-22 79 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()得到這個整理出來。)

相關問題