文章作者:Tyan
博客:noahsnail.com | CSDN | 簡書
0. 測試環境
Python 3.6.9
1. 引言
Python代碼中,既可以導入模塊,也可以導入模塊中的對象,導入方式主要分爲兩種:import <module_name>
和from <module_name> import <name(s)>
。本文主要對二者進行比較。爲了之後測試,定義了一個module
模塊,module.py
文件定義如下:
a = [1, 2, 3]
b = 'abc'
class Test():
def __init__(self):
self.desc = 'Test'
def print_desc(self):
print(self.desc)
2. 兩種方式對比
2.1 import <module_name>
Python模塊導入的命令之一是import <module_name>
,執行了import <module_name>
命令之後,Python的運行過程如下:
- 首先在
sys.modules
中查找module_name
,sys.modules
中包含所有之前導入模塊的緩存。 - 如果在模塊緩存中沒找到
module_name
,Python會繼續查找內置模塊列表,這些是Python預先安裝的模塊,可以在Python標準庫中找到。 - 如果還沒找到,Python會在
sys.path
定義的目錄列表中查找。這個列表中通常包含當前目錄,會首先查找當前目錄。 - 如果找到了
module_name
,會將其綁定到局部命名空間中,後面可以使用。如果沒找到,則會拋出ModuleNotFoundError
。
注: 導入模塊之後,可以通過模塊的__file__
屬性來獲取模塊所在的目錄,其是sys.path
中的目錄之一。sys.path[0]
爲空,表示當前目錄。示例如下:
>>> import module
>>> module.__file__
'/workspace/heatmap/module.py'
>>> import re
>>> re.__file__
'/usr/lib/python3.6/re.py'
>>> sys.path
['', '/usr/lib/python36.zip', '/usr/lib/python3.6', '/usr/lib/python3.6/lib-dynload', '/usr/local/lib/python3.6/dist-packages', '/usr/local/lib/python3.6/dist-packages/warpctc_pytorch-0.1-py3.6-linux-x86_64.egg', '/usr/lib/python3/dist-packages']
>>> import os
>>> os.getcwd()
'/workspace/heatmap'
>>> import mod
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'mod'
import <module_name>
導入模塊之後,並不可以直接訪問模塊中的內容,每個模塊都有自己的私有符號表,其是模塊中定義的所有對象的全局符號表,模塊創建了一個單獨的命名空間。執行import <module_name>
之後,<module_name>
放到了調用者的局部符號表裏,但模塊中定義的對象仍在模塊的私有符號表裏。訪問模塊中定義的對象需要使用.
符號。示例如下:
>>> import module
>>> module
<module 'module' from '/workspace/heatmap/module.py'>
>>> a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
>>> b
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'b' is not defined
>>> module.a
[1, 2, 3]
>>> module.b
'abc'
import
導入模塊時,有時候模塊的名字非常長,每次訪問模塊的內容都很不方便,因此可以使用import ... as ...
的方式爲模塊重命名,便於使用,示例代碼如下:
>>> import module as mod
>>> module
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'module' is not defined
>>> mod
<module 'module' from '/workspace/heatmap/module.py'>
>>> module.a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'module' is not defined
>>> mod.a
[1, 2, 3]
2.2 from <module_name> import <name(s)>
from <module_name> import <name(s)>
命令可以直接導入模塊中的對象,命令執行之後,模塊中的對象被引用到調用者的環境中,可以直接對其訪問,而不需要添加模塊前綴。這是方式的導入會將模塊中的對象直接添加到調用者的符合表裏,並會覆蓋調用者符號表裏的同名對象。
>>> a = [1, 2]
>>> a
[1, 2]
>>> from module import a
>>> a
[1, 2, 3]
>>> from module import abc
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: cannot import name 'abc'
>>> from module import b
>>> b
'abc'
>>> module
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'module' is not defined
>>> from module import Test
>>> t = Test()
>>> t.print_desc()
Test
針對導入對象名稱較長問題,也可以使用from ... import ... as ...
對導入的對象進行重命名,這種方式也可以用來解決導入對象帶來的名稱衝突。
2.3 from <module_name> import *
from <module_name> import *
命令可以無差別導入模塊中的大部分對象(下劃線開頭的部分除外),風險較高且代碼閱讀不直觀,因此這裏不對其進行詳細介紹,也不推薦這種使用方式。
2.4 dir()
Python內置函數dir()
會返回命名空間定義的名稱列表,通過dir()
函數可以查看導入聲明前後局部符號表的變化情況,也可以用來查看模塊中定義的對象,示例如下:
>>> dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__']
>>> a = [1, 2]
>>> dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'a']
>>> from module import b
>>> dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'a', 'b']
>>> dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'a', 'b', 'module']
>>> from module import Test as t
>>> dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'a', 'b', 'module', 't']
>>> dir(module)
['Test', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'a', 'b']
>>> dir(module.Test)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'print_desc']