這篇文章討論了Python的from <module> import *
和from <package> import *
,它們怎麼執行以及為什麼使用這種語法(也許)是一個壞主意。
從一個模組匯入全部
from <module> import * means
意味著“我希望能訪問<module>
中我有許可權訪問的全部名稱”。例如以下程式碼something.py
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# something.py public_variable = 42 _private_variable = 141 def public_function(): print("I'm a public function! yay!") def _private_function(): print("Ain't nobody accessing me from another module...usually") class PublicClass(object): pass class _WeirdClass(object): pass |
在Python直譯器中,我們可以執行from something import *
,然後看到如下的內容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
>>> from something import * >>> public_variable 42 >>> _private_variable ... NameError: name '_private_variable' is not defined >>> public_function() "I'm a public function! yay!" >>> _private_function() ... NameError: name '_private_function' is not defined >>> c = PublicClass() >>> c <something.PublicClass object at ...> >>> c = _WeirdClass() ... NameError: name '_WeirdClass' is not defined |
from something import *
從something
中匯入了除了以_
開頭名稱外的其他所有名稱,按照規範,_
開始的名稱是私有的所以未被匯入。
嗯,不是特別糟!還有什麼?
上面沒提到__all__
是什麼。__all__
是一個字串列表,指定了當from <module> import *
被使用時,模組(或者如後文會提到的包)中的哪些符號會被匯出。如果我們不定義__all__
(我們在上面的something.py
就沒定義),import *
預設的匯入方式是匯入除了下劃線(_
)開頭的所有名稱。再說一次,程式設計慣例上下劃線表示一個符號是私有的,不匯入是合理的。讓我們來看看在something.py
中定義我們自己的__all__
會發生什麼。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
# something.py __all__ = ['_private_variable', 'PublicClass'] # The rest is the same as before public_variable = 42 _private_variable = 141 def public_function(): print("I'm a public function! yay!") def _private_function(): print("Ain't nobody accessing me from another module...usually") class PublicClass(object): pass class _WeirdClass(object): pass |
現在,我們期望from something import *
只會匯入_private_variable
和PublicClass
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
>>> from something import * >>> public_variable 42 >>> _private_variable ... NameError: name '_private_variable' is not defined >>> public_function() "I'm a public function! yay!" >>> _private_function() ... NameError: name '_private_function' is not defined >>> c = PublicClass() >>> c <something.PublicClass object at ...> >>> c = _WeirdClass() ... NameError: name '_WeirdClass' is not defined |
包是怎樣的呢?
當從一個包中匯入全部時,__all__
的做法和模組基本一樣,不過它處理的是包中的模組(而不是把模組中的名都匯入)。所以當我們使用from <package> import *.
時__all__
說明了所有需要被匯入當前名稱空間的模組。
不同之處在於,如果你在一個包的__init__.py
裡面沒有宣告__all__
,from <package> import *
語句不會匯入任何東西(這個說法也不全對,正確的說法在此)
但是,這有什麼不好?
繼續讀之前,在你的Python直譯器中,執行import this
,再讀一遍Python之禪(在你孩子每晚睡前也要讀給他們)。
明確比含糊要好。
from <module> import *
是不明確的。它沒告訴我們我們正在匯入什麼或者我們把什麼帶入當前名稱空間了。更好的做法是顯式地匯入我們需要的全部名稱。這種方式下,讀者(非常可能是未來的你自己)就不會困惑於你程式碼中使用的一個變數/方法/類/其他東西是哪兒來的,這也告訴了我們下一點:
可讀性很重要
即使你需要匯入很多東西,一個一個顯式地匯入也更清楚。使用PEP 328:
1 2 |
from Tkinter import (Tk, Frame, Button, Entry, Canvas, Text, LEFT, DISABLED, NORMAL, RIDGE, END) |
你現在就能明確知道你的名稱空間裡有什麼,使用ctrl+f
能很快地告訴你它們是哪兒來的。
同時,你還總是要承擔模組/包作者更改list內容(加/減東西)的風險。也就是下面兩者之一:
- 作者從
__all__
裡刪除了一個字串。如果你的程式碼使用了那個名字,你的程式碼就會報出NameError
的錯誤,並且很難發現為什麼。 - 作者在
__all__
里加入了很多東西。你也許不需要這些增加的內容,所以你只是讓這些你不關心的東西佔滿了你的名稱空間。他們甚至在你不注意的時候會替代其他同名內容。
當然,有時候從模組或者包中匯入全部內容是有用的。不過,這麼做之前三思。從我的經驗來看,這麼做通常只是因為懶。