2012-01-02 60 views
15

在下面的層次中,是否有一種方便和普遍的方式在下面的所有.py文件中使用通用術語來引用top_package?我希望有一個一致的方式來導入其他模塊,以便即使「top_package」更改名稱也不會中斷。如何在包內引用Python中的頂級模塊?

我不贊成使用像「..level_one_a」這樣的相對導入,因爲相對路徑將與下面的每個python文件不同。我正在尋找一種方法:

  1. 每個python文件可以具有相同的導入語句,用於包中的相同模塊。
  2. 在軟件包內的任何.py文件中對「top_package」的解耦引用,所以無論名稱「top_package」更改爲什麼,都不會中斷。

    top_package/ 
        __init__.py 
        level_one_a/ 
        __init__.py 
        my_lib.py 
        level_two/ 
         __init__.py 
         hello_world.py 
        level_one_b/ 
        __init__.py 
        my_lib.py 
        main.py 
    
+1

? (有時候這個答案揭示了真正的問題/解決方案。) – 2012-01-02 23:32:27

+1

我希望儘可能使包可重用,這樣當我重命名頂層模塊時,所有內容仍然可以正常工作,而無需更改每個導入名稱。 – hllau 2012-03-02 04:13:28

回答

10

這應該做的工作:

top_package = __import__(__name__.split('.')[0]) 

這裏的技巧是,每模塊__name__變量包含由圓點分隔,例如,例如模塊的完整路徑, top_package.level_one_a.my_lib。因此,如果您想獲取頂級包名稱,只需獲取路徑的第一個組件並使用__import__導入它。

儘管用於訪問軟件包的變量名仍稱爲top_package,但您可以重命名該軟件包,如果仍然可以使用。

+1

-1問題要求的解決方案不依賴於名稱「top_package」。 – 2012-01-02 23:29:20

+0

@ Jon-Eric感謝您的評論。我已經解決了我的答案,無論頂級包名是什麼。 – jcollado 2012-01-03 00:11:55

+1

這不完全正確;如果當前模塊沒有從頂層導入,它的'__name__'將不包含這個模塊的完整路徑,但只包含這個模塊的一部分,它將從導入該模塊的位置開始。 – thuzhf 2016-05-24 11:17:59

0

我相信#2是不可能的,而不使用相對導入或命名包。您必須通過顯式調用其名稱或使用相對導入來指定要導入的模塊。否則口譯員會如何知道你想要什麼?

如果你讓你的應用程序啓動上述top_level/一個級別,並將它import top_leve升然後你可以從TOP_LEVEL包內的任何地方引用top_level.*

(我可以告訴你從軟件我工作的一個例子:http://github.com/toddself/beerlog/

1

您可以使用__import__()功能的組合和包裝的__path__屬性。

例如,假設您希望從包中的其他位置導入<whatever>.level_one_a.level_two.hello_world。你可以這樣做:

import os 
_temp = __import__(__path__[0].split(os.sep)[0] + ".level_one_a.level_two.hello_world") 
my_hello_world = _temp.level_one_a.level_two.hello_world 

此代碼獨立於頂層包的名稱,可用於包中的任何位置。這也很醜陋。

5

把你的包和main腳本轉換成外部容器目錄,如:

container/ 
    main.py 
    top_package/ 
     __init__.py 
     level_one_a/ 
      __init__.py 
      my_lib.py 
      level_two/ 
       __init__.py 
       hello_world.py 
     level_one_b/ 
      __init__.py 
      my_lib.py 

當運行main.py,它的父目錄(container)將被自動添加到sys.path開始。由於top_package現在位於同一目錄中,因此可以從包樹的任何位置導入。

所以hello_world.py可以導入level_one_b/my_lib.py這樣的:

from top_package.level_one_b import my_lib 

無論在什麼容器目錄的名稱是,或者所在,進口將始終以這種安排工作。

但請注意,在您的原始示例中,top_package它可以很容易地用作容器目錄本身。你所要做的就是刪除top_package/__init__.py,而且你會被有效地排除在外。

前面的import語句會再換:

from level_one_b import my_lib 

,你就可以自由命名top_package但是你所願。

+0

如果刪除top_package/__ init__.py,則level_one_a和level_one_b將無法相互導入。 – DonGar 2017-03-25 18:48:04

+0

@DonGar。沒有 - 它會工作得很好。但請注意,我指的是OP問題中的結構,而不是我的答案中顯示的結構。關鍵的區別是'main.py'腳本的位置。 – ekhumoro 2017-03-25 23:02:02

+0

您的回答的主要部分我同意,但以「但請注意」開頭的段落是我不同意的。除非你也意味着將level_one_a和level_one_b都移動到top_container的新子模塊中。 – DonGar 2017-03-26 03:41:19

0

這個工作從庫模塊中:你爲什麼要到頂層模塊的引用

import __main__ as main_package 
TOP_PACKAGE = main_package.__package__.split('.')[0] 
相關問題