議題三:當寫好了一個module,還會有一個設計上的考量是我只希望提供module中的特定對象給使用者使用,對於一些只用於內部操作的變數、函數或是類別我不想要直接開放給使用者取用,所以應該要有一個限制使用者的機制,那實際上python有沒有這機制呢?
是有,但python似乎沒有很嚴格的限制使用者使用一些module內的對象,相對寬鬆的方法只要在變數名稱前面加一個'_',比如說:
In module.py:
pub_var = 'I\'m public variance.'
_pri_var = 'I\'m private variance.'
def pub_func():
return 'I\'m public func.'
def _pri_func():
return 'I\'m private func.'
class pub_obj():
def __init__():
self.str = 'I\'m public obj.'
class _pri_obj():
def __init__():
self.str = 'I\'m private obj.'
In python3 shell:
>>> from module import *
>>> dir() # 可以輸出目前可以使用的對象,可以看出_pri開頭的對象無法直接被使用
['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'pub_func', 'pub_obj', 'pub_var']
>>> _pri_var
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name '_pri_var' is not defined
>>> module._pri_var # 還是可以用這種方式取得pri資料
"I'm private variance."
另外除了'_'符號,也可以在module定義一個list對象__all__,當使用者利用"from [module_name] import *"這種語法時,__all__可以決定只對使用者提供某些對象:
In module.py:
pub_var = 'I\'m public variance.'
_pri_var = 'I\'m private variance.'
def pub_func():
return 'I\'m public func.'
def _pri_func():
return 'I\'m private func.'
class pub_obj():
def __init__():
self.str = 'I\'m public obj.'
class _pri_obj():
def __init__():
self.str = 'I\'m private obj.'
__all__ = [pub_var, pub_func, _pri_var]
In python3 shell:
>>> from module import *
>>> dir() # pub_obj不見了,但是多了_pri_var
['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', '_pri_var', 'pub_func', 'pub_var']
當然這兩種方式都只能對"from [module_name] import *"做出控制,呵呵,用了python就試著慷慨點吧。
議題四:在開發大型模組時,通常不是一個人單打獨鬥,而是一個團隊在進行,但當很多人想要共同開發模組時,我們想要在不同的路徑做開發,卻希望最後能直接整合在一起,甚至希望最後連合併的時間都沒有那就更好了,可以直接上線使用!這話聽起來頗神奇,但確實能夠辦到,實際上,這個需求只是要把不同路徑開發的模組歸到一個共同的命名空間霸了,python其實有不只一種方法能辦到這件事。(最近時間不多,只好先稍微抄一下cookbook範例,不要見怪嗚嗚)
在這裡我就介紹其中一個方法,就是使用'namespace package',假設A碼農和B碼農要讓彼此的模組都擁有一個共同的命名空間"lalala",可以這樣做:
A碼農:
A碼農的耕作目錄/lalala/
A/
├── __init__.py
├── A1.py
└── A2.py
B碼農:
B碼農的耕作目錄/lalala/
B/
├── __init__.py
├── B1.py
└── B2.py
注意到lalala底下並沒有__init__.py,也因為這樣,lalala變成了一個namespace package,那他有什麼好處呢?
當我們想要去import命名空間lalala裏面的模組A和模組B,我們可以先在sys.path來導入A碼農和B碼農耕作目錄:
In python3 shell:
>>> import sys
>>> sys.path.extend(['A碼農的耕作目錄/', 'B碼農的耕作目錄'])
>>> import lalala.A
>>> import lalala.B
來附個連結,以免變真抄襲:http://python3-cookbook-personal.readthedocs.io/zh_CN/latest/c10/p05_separate_directories_import_by_namespace.html