2013-01-20 43 views
2

我正在開發具有類似如下的文件結構的包:如何導入模塊成員包內

test.py 
package/ 
    __init__.py 
    foo_module.py 
    example_module.py 

如果我調用test.py import package,我想封裝模塊出現與此類似:

>>> vars(package) 
mapping_proxy({foo: <function foo at 0x…}, {example: <function example at 0x…}) 

換句話說,我希望所有的模塊在package成員在package的命名空間,我不希望這些模塊本身是在命名空間。 package不是一個子包。

比方說,我的文件是這樣的:

foo_module.py:

def foo(bar): 
    return bar 

example_module.py:

def example(arg): 
    return foo(arg) 

test.py:

print(example('derp')) 

如何我是否構造進口? test.py,example_module.py和__init__.py中的聲明可以從package目錄之外工作(即, test.py)和包內部(即foo_module.py和example_module.py)?我嘗試的所有東西都給出Parent module '' not loaded, cannot perform relative importImportError: No module named 'module_name'

另外,作爲一個旁註(按照PEP 8):「對於包內導入的相對導入是非常不鼓勵的,總是對所有導入使用絕對包路徑,即使現在PEP 328已經在Python中完全實現2.5,其顯式相對進口的風格是積極的阻止;絕對進口更便攜,通常更具可讀性。「

我正在使用Python 3.3。

+0

我只是把它放在這裏不盲目嘗試:怎麼樣'從包導入*'? – Skyler

+0

@Skyler,在哪個文件? –

回答

1

你說:

我想在包中的所有模塊的成員是在包裝的 命名空間,我不希望這些模塊本身是在 命名空間。

我能夠做到這一點適應的東西我在Python 2已經使用自動導入插件能在Python 3

也工作概括地說,這裏是它的工作原理是:包的__init__.py文件將所有其他Python文件導入同一軟件包目錄中的所有不以「_」(下劃線)字符開頭的Python文件。之後,它將導入模塊名稱空間中的所有名稱添加到__init__模塊(也是該包的名稱空間)中。注意我必須從foo_module明確 example_module模塊。

以這種方式做事的一個重要方面是意識到它是動態的,並且不需要將包模塊名稱硬編碼到__init__.py文件中。當然,這需要更多的代碼來完成,但也使它非常通用,並且能夠處理幾乎任何(單級)包 - 因爲它會在添加新模塊時自動導入並停止導入從目錄。

test.py

from package import * 

print(example('derp')) 

__init__.py

def _import_all_modules(): 
    """dynamically imports all modules in the package""" 
    import traceback 
    import os 
    global __all__ 
    __all__ = [] 
    globals_, locals_ = globals(), locals() 

    # dynamically import all the package modules 
    for filename in os.listdir(__name__): 
     # process all python files in directory that don't start with underscore 
     # (which also keeps this module from importing itself) 
     if filename[0] != '_' and filename.split('.')[-1] in ('py', 'pyw'): 
      modulename = filename.split('.')[0] # filename without extension 
      package_module = '.'.join([__name__, modulename]) 
      try: 
       module = __import__(package_module, globals_, locals_, [modulename]) 
      except: 
       traceback.print_exc() 
       raise 
      for name in module.__dict__: 
       if not name.startswith('_'): 
        globals_[name] = module.__dict__[name] 
        __all__.append(name) 

_import_all_modules() 

foo_module.py

def foo(bar): 
    return bar 

example_module.py

from package.foo_module import foo # added 

def example(arg): 
    return foo(arg) 
2

我想通過使用from module import name樣式導入,您可以獲得所需的值,而不會混亂您的名稱空間。我想,這些進口會爲工作你問了:

進口example_module.py

from package.foo_module import foo 

進口__init__.py

from package.foo_module import foo 
from package.example_module import example 

__all__ = [foo, example] # not strictly necessary, but makes clear what is public 

進口test.py

from package import example 

請注意,這隻適用於你'重新運行test.py(或其他位於程序包層次結構相同級別的其他位置)。否則,您需要確保包含package的文件夾位於python模塊搜索路徑中(通過將該軟件包安裝在Python將查找它的地方,或者通過向sys.path添加適當的文件夾)。

+0

+1:例如[''multiprocessing'包來自stdlib](http://hg.python.org/cpython/file/3.3/Lib/multiprocessing/__init__.py)使用這種技術 – jfs

+0

如果我執行example_module.py或\ _ \ _ init \ _ \ _。py直接,我得到一個導入錯誤,但test.py的作品。獲取test.py顯然是最重要的工作,但有沒有辦法(沒有try/catch)讓其他兩個工作?我想這就是爲什麼我把這個問題放在第一位。 –

+0

這也將模塊保留在包的名稱空間中。現在我想到了,這是Python的一個要求嗎? –