2011-03-10 79 views
10

我想要某個模塊的接口包含一定數量的函數和類(而不是其他)。我可以在一個文件中實現所有這些,並且很容易獲得我想要的接口。但是,由於有大量的代碼,我寧願分裂了整個事情分成幾個文件,說如何將子模塊名稱保留在Python包的名稱空間之外?

mypackage/ 
    __init__.py 
    a.py 
    b.py 
    c.py 
    d.py 

如果想獲得理想的界面,我定義一個__init__.py文件爲導入所有公共包從abcd符號:

from a import func_a1, func_a2, ClassA1, ClassA2 
from b import func_b1, func_b2, ClassB1, ClassB2 
from c import func_c1, func_c2, ClassC1, ClassC2 
from d import func_d1, func_d2, ClassD1, ClassD2 

如果我導入使用

import mypackage 

包名稱空間還包含符號a,b,cd。這些名稱是實現細節,不屬於我的界面。我不希望它們顯示爲「公共」符號。什麼是擺脫他們的最佳方式?

我考慮的選擇是

  1. 使用一個單獨的模塊,而不是包裝。界面看起來很好,但是實現會比現在更清晰。

  2. del a, b, c, d 
    

    加入的__init__.py末。工作正常,但看起來像一個黑客。 (例如,你不能import __init__更多,如果沒有此項線路正常。)

  3. 重命名abcd_a_b_c_d。現在它們被包含在mypackage的命名空間中作爲「私有」符號,我很好,但它感覺有點奇怪,我的文件名以開頭, )。

有什麼更好的建議嗎?或者想要選擇哪個選項?

或者我只是爲了肛門,不應該關心整個事情?

+2

不妨去喝蘇打水。也就是說,除了你以外,沒有人真正關心包的命名空間中的內容。 – 2011-03-10 20:29:24

+2

@Ignacio:可能你是對的:)例如在交互式使用中,當不需要的名稱會干擾標籤擴展時,它會讓我感到惱火。 – 2011-03-10 20:37:21

+0

這只是我的看法,但是'import __init__'在選項2中似乎更加駭人聽聞,所有事情都考慮到了。 – JAB 2012-06-07 15:09:20

回答

4

如果你真的要刪除從命名空間中的名字,那麼你可以只使用他們的del聲明,他們會消失,像風。

0

http://docs.python.org/tutorial/modules.html

import語句使用 以下約定:如果一個包的 __init__.py代碼定義了一個名爲列表__all__,它被認爲是應導入模塊的名稱列表 當從包導入*時遇到 。

在你mypackage/__init__.py,嘗試添加此:

# add this line, replace "..." with the rest of the definitions 
# you want made public 
__all__ = ['func_a1', 'func_a2', 'ClassA1', 'ClassA2', ...] 

from a import func_a1, func_a2, ClassA1, ClassA2 
from b import func_b1, func_b2, ClassB1, ClassB2 
from c import func_c1, func_c2, ClassC1, ClassC2 
from d import func_d1, func_d2, ClassD1, ClassD2 
+1

但是,這不會直接訪問它時影響名稱空間的內容。 – 2011-03-10 20:40:15

+0

Gah,我誤解了你的問題......如果你正在從'mypackage import *'執行操作,我認爲你是這樣的。在這種情況下,它似乎不起作用,即使你在你的模塊中定義了'__all__',''''''''''' – dcrosta 2011-03-10 20:41:54

0

這是一個被單一的Javascript功能模塊啓發的解決方案:

def __init__module(): 
    from os import path 

    def _module_export_1(): 
     return path.abspath('../foo') 

    def _module_export_2(): 
     return path.relpath('foo/bar', 'foo') 

    g = globals() 
    g['module_export_1'] = _module_export_1 
    g['module_export_2'] = _module_export_2 

__init__module() 

雖然模塊需要進口從OS「路徑」,「路徑」不污染模塊命名空間。模塊名稱空間中唯一的殘留是__init_module(),它明顯由雙下劃線前綴標記爲私有。

另一種選擇是在每個功能的頂部導入所需的模塊,而不是模塊的頂部。第一次導入模塊後,後續導入只是sys.modules字典中的查找。

但我同意其他評論者的意見 - Python約定不擔心模塊名稱空間污染,只是讓模塊的用戶明白哪些部分名稱空間是公共API,哪些是內部的。

+0

不幸的是,這種方法不起作用。正如你在我的文章中所看到的,我從來沒有將名稱'a'導入到包的名稱空間中 - 我只是從'import func_a1,...'中使用''。如果我在普通模塊中這樣做,只會在模塊的名稱空間中顯示名稱'func_a1,..'。但是由於'a'是一個包的子模塊,它的名稱'a'被插入到包的名稱空間中。如果我從一個函數中導​​入所有東西,會發生同樣的事情。 – 2011-04-04 18:46:08

8

如果包中的某些文件確實是實現細節,請繼續並在它們前面加上下劃線 - 這就是我們使用它們的原因。

例如,如果你在​​看你會看到

__init__.py 
================================================== 
"""create and manipulate C data types in Python""" 

import os as _os, sys as _sys 

__version__ = "1.1.0" 

from _ctypes import Union, Structure, Array 
from _ctypes import _Pointer 
from _ctypes import CFuncPtr as _CFuncPtr 
... 

正如你可以看到,即使ossys成了該文件的實施細則。

相關問題