管理模組名稱
May 5, 2022在〈簡介模組〉談過,可以使用 from import
直接將模組中指定的名稱匯入。
from import
事實上,from import
會將被匯入模組中之名稱參考值,指定給目前模組中建立的新名稱。例如,也許有個 foo.py 檔案裏頭定義了一個 x
變數:
# foo.py
x = 10
若在另一個 main.py 檔案中執行 from foo import x
,實際上會在 main
模組中建立一個 x
變數,然後將 foo
中的 x
的值 10 指定給 main
中的 x
變數,因此會產生以下的結果:
>>> from foo import x
>>> x
10
>>> x = 20
>>> import foo
>>> foo.x
10
>>>
簡單來說,在 from foo import x
時,就是在模組中建立了新變數,而不是使用原本的 foo.x
變數,只是一開始兩個變數參考同一個值。若是參考了可變動物件,就要特別小心了。例如,若 foo.py 中撰寫了:
# foo.py
lt = [10, 20]
就會產生以下的結果:
>>> from foo import lt
>>> lt
[10, 20]
>>> lt[0] = 15
>>> import foo
>>> foo.lt
[15, 20]
>>>
這是因為 lt
變數與 foo.lt
都參考了同一個 list
物件,因此透過 lt
變數修改索引 0 的元素,透過 foo.lt
就會取得修改後的結果。
限制 from import *
使用 from import
語句時,若最後是 *
結尾,會將被匯入模組中所有變數,在當前模組中都建立相同的名稱。如果有些變數,不想被 from import *
建立同名變數,可以用底線作為開頭。例如,若 foo.py 中有以下內容:
# foo.py
x = 10
lt = [10, 20]
_y = 20
使用 from foo import *
時,目前模組中就不會建立 _y
變數。例如:
>>> from foo import *
>>> x
10
>>> lt
[10, 20]
>>> _y
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name '_y' is not defined
>>>
想避免 from import *
被濫用而污染了名稱空間時,可以使用這種方式,另一個方式是定義 __all__
清單,使用字串列出可被 from import *
的名稱,例如:
# foo.py
__all__ = ['x', 'lt']
x = 10
lt = [10, 20]
_y = 20
z = 30
如果模組中定義了 __all__
變數,就只有名單中的變數,才能被其他模組 from import *
。例如:
>>> from foo import *
>>> x
10
>>> lt
[10, 20]
>>> _y
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name '_y' is not defined
>>> z
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'z' is not defined
>>>
無論是底線開頭,或者是未被列入 __all__
清單的名稱,只是限制不被 from import *
,若使用者 import foo
,依舊可以使用 foo._y
或 foo.z
來存取。
>>> import foo
>>> foo._y
20
>>> foo.z
30
>>>
del 模組名稱
del
可以將已建立的變數刪除,被 import
的模組名稱,或者 from import
建立的名稱,實際上就是個變數,因此,可以使用 del
將模組名稱或者 from import
的名稱刪除。例如:
>>> import foo
>>> foo.x
10
>>> del foo
>>> foo.x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'foo' is not defined
>>> from foo import x
>>> x
10
>>> del x
>>> x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
>>>
del
是用來刪除指定的名稱,而不是刪除名稱參考的物件本身,舉個例子來說:
>>> lt1 = [1, 2]
>>> lt2 = lt1
>>> del lt1
>>> lt1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'lt1' is not defined
>>> lt2
[1, 2]
>>>
在上例中,雖然執行了 del lt1
,然而,lt2
還是參考著 list
實例。同樣的道理,del
時若指定了模組名稱,只是將該名稱刪除,而不是刪除 module
實例。實際上,想知道目前已載入的 module
名稱與實例有哪些,可以透過 sys.modules
,這是個 dict
物件,鍵的部份是模組名稱,值的部份是 module
實例。例如:
>>> import sys
>>> import foo
>>> 'foo' in sys.modules
True
>>> foo.x
10
>>> del foo
>>> foo.x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'foo' is not defined
>>> sys.modules['foo'].x
10
>>>
在上面的例子中可以看到,del foo
刪除了 foo
名稱,然而,還是可以透過 sys.modules['foo']
存取到 foo
原本參考的 module
實例。
模組名稱範圍
到目前為止,都是在全域範圍使用 import
、import as
、from import
,實際上,它們也可以出現在陳述句能出現的位置,例如 if/else
區塊或者函式之中,因此,能根據不同的情況進行不同的 import
。
而到目前為止你也知道了,當使用 import
、import as
、from import
時,建立的名稱其實就是變數名稱,因此,視使用 import
、import as
、from import
的位置,建立的名稱也會有其作用範圍。例如,也許在函式中使用了 import foo
,那麼 foo
名稱的範圍,就只會在函式之中。
>>> def qoo():
... import foo
... print(foo.x)
...
>>> qoo()
10
>>> foo.x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'foo' is not defined
>>>