Python模塊基礎(chǔ)指南之import的四種導(dǎo)入方式全對比
一、開篇:同一種需求,四種寫法
Python提供了四種導(dǎo)入模塊的方式,每種都有不同的適用場景:
# 方式一:導(dǎo)入整個模塊 import math # 方式二:導(dǎo)入模塊并起別名 import math as m # 方式三:從模塊中導(dǎo)入特定名稱 from math import sqrt, pi # 方式四:導(dǎo)入模塊中的所有公開名稱 from math import *
這四種方式表面上看都能讓你使用math模塊的功能,但它們在命名空間、內(nèi)存占用、代碼可讀性和潛在風(fēng)險上有著本質(zhì)區(qū)別。選擇哪種方式,直接影響代碼的質(zhì)量。
二、四種方式逐一詳解
2.1 方式一:import 模塊名
# import 模塊名 —— 導(dǎo)入整個模塊對象 import math # 這創(chuàng)建了一個變量 math,指向整個math模塊對象 print(type(math)) # <class 'module'> print(dir(math)[:10]) # ['__doc__', ..., 'acos', 'acosh', ...] # 使用:必須通過模塊名訪問 print(math.pi) # 3.141592653589793 print(math.sqrt(16)) # 4.0 print(math.sin(math.pi / 2)) # 1.0 # ? 優(yōu)點: # 1. 命名空間清晰——math.sqrt一看就知道哪來的 # 2. 不會污染當(dāng)前命名空間 # 3. 不會和已有的變量名沖突 # ? 缺點: # 1. 每次都寫模塊名——如果模塊名很長會比較啰嗦 # 2. 導(dǎo)入了整個模塊(雖然通常不是問題) # ?? 適用場景: # - 大多數(shù)情況下的默認選擇 # - 模塊名不太長時 # - 需要模塊中多個功能時
2.2 方式二:import 模塊名 as 別名
# import 模塊名 as 別名 —— 給模塊起一個短名字 import numpy as np import pandas as pd import matplotlib.pyplot as plt import tensorflow as tf # 使用別名訪問 arr = np.array([1, 2, 3, 4, 5]) print(np.mean(arr)) # 3.0 # ? 優(yōu)點: # 1. 輸入更少(某些庫的名字本身就很長) # 2. 符合社區(qū)約定(np是指numpy幾乎已成標(biāo)準(zhǔn)) # 3. 解決命名沖突(兩個模塊有相同的名字) # ? 缺點: # 1. 如果用了非標(biāo)準(zhǔn)的別名,降低可讀性 # import math as pineapple # 不要這樣! # pineapple.sqrt(16) # 這段代碼會讓同事困惑 # ? 不推薦的用法 # 除非有明確的重命名理由(如避免沖突),否則不要隨意起別名 import json as js # 不推薦——json本身就不長 # ? 推薦的用法(社區(qū)約定) import numpy as np # 標(biāo)準(zhǔn)約定 import pandas as pd # 標(biāo)準(zhǔn)約定 import matplotlib.pyplot as plt # 標(biāo)準(zhǔn)約定
2.3 方式三:from 模塊名 import 名稱
# from 模塊名 import 名稱 —— 將特定名稱導(dǎo)入當(dāng)前命名空間
from math import sqrt, pi, sin, cos
# 可以直接使用這些名稱,不需要模塊名前綴
print(sqrt(16)) # 4.0
print(pi) # 3.141592653589793
print(sin(pi / 2)) # 1.0
# 未導(dǎo)入的名稱仍然需要通過模塊名訪問
# print(math.ceil(3.14)) # NameError! math沒有被導(dǎo)入
import math # 如果需要其他功能,單獨導(dǎo)入模塊
print(math.ceil(3.14)) # 4
# 可以同時導(dǎo)入多個名稱
from os.path import join, exists, isfile
print(join("dir", "file.txt")) # dir/file.txt
# ? 優(yōu)點:
# 1. 代碼更簡潔——不需要寫模塊名
# 2. 明確導(dǎo)入了什么——讀者知道你用了模塊的哪些功能
# 3. 可以只導(dǎo)入需要的——雖然不會減少內(nèi)存占用
# ? 缺點和陷阱:
# 1. 可能和已有的變量名沖突
pi = "我自定義的pi"
from math import pi # 覆蓋了上面的pi!
print(pi) # 3.141592653589793 —— 不是 "我自定義的pi"!
# 2. 導(dǎo)入太多名稱會讓命名空間混亂
from math import sin, cos, tan, asin, acos, atan, sqrt, pi, e, floor, ceil, ...
# 如果都是從不同模塊導(dǎo)入的,閱讀者很難知道每個名稱來自哪里
# 3. 變量綁定問題——from import導(dǎo)入的是值的引用
# 如果源模塊中的值改變了,from導(dǎo)入的變量不會自動更新
2.4 方式四:from 模塊名 import *
# from 模塊名 import * —— 導(dǎo)入模塊的所有"公開"名稱
# ?? 這是最不推薦的方式!原因如下:
# 1. 你不知道導(dǎo)入了什么
from math import *
# 現(xiàn)在你有:sin, cos, tan, sqrt, pi, e, floor, ceil, ...
# 以及你不經(jīng)意間覆蓋的:pow, abs, sum, ...(任何同名變量)
# 2. 污染命名空間——導(dǎo)致難以發(fā)現(xiàn)的命名沖突
def sin(x):
"""我自己寫的sin函數(shù):返回字符串"""
return "這不是正弦"
from math import * # 剛才定義的sin被覆蓋了!
print(sin(0)) # 0.0 —— 不是 "這不是正弦"
# 3. 可讀性極差
# 讀代碼的人不知道sum來自哪里——是內(nèi)置的?math的?還是你定義的?
# from math import *
# from statistics import *
# sum(...) # 這是哪個sum?
# 4. PEP 8強烈不推薦
# "Wildcard imports (from <module> import *) should be avoided"
# ? 唯一可接受的例外:
# 在 __init__.py 中控制包的公開API
# mypackage/__init__.py:
# from .module_a import ClassA, func_b
# from .module_b import ClassC
# __all__ = ["ClassA", "func_b", "ClassC"]
2.5 __all__控制from import *的行為
# __all__是一個模塊級變量
# 定義了 from module import * 時哪些名稱會被導(dǎo)入
# 假設(shè)有一個模塊 my_module.py:
"""
__all__ = ["public_func", "PublicClass"] # 白名單
def public_func():
'''這個函數(shù)會被導(dǎo)出'''
pass
def _private_func():
'''下劃線開頭的默認不會被導(dǎo)出'''
pass
class PublicClass:
'''這個類會被導(dǎo)出'''
pass
class _PrivateClass:
'''下劃線開頭的默認不會被導(dǎo)出'''
pass
internal_data = "不會被導(dǎo)出" # 不在__all__中
"""
# 使用:
# from my_module import *
# public_func() # ? 可用(在__all__中)
# PublicClass() # ? 可用(在__all__中)
# _private_func() # ? 不可用(_開頭,且不在__all__中)
# internal_data # ? 不可用(不在__all__中)
# ?? __all__是一種顯式聲明模塊"公開API"的方式
# 即使不用from import *,__all__也能作為文檔告訴使用者哪些是公開的
三、四種方式的對比
# ?? 完整對比 # 假設(shè)要使用math、os、json三個模塊的功能 # 方式一:import —— 命名空間最清晰 import math import os import json # 使用:math.sqrt(), os.path.join(), json.dumps() # 一目了然——每個函數(shù)來自哪個模塊 # 方式二:import as —— 最靈活 import numpy as np import pandas as pd # 使用:np.array(), pd.DataFrame() # 在保持清晰的同時簡化了輸入 # 方式三:from import —— 在簡潔和清晰間平衡 from math import sqrt, pi from os.path import join from json import dumps, loads # 使用:sqrt(), join(), dumps() —— 簡潔 # 但讀者需要記住sqrt來自math,join來自os.path # 方式四:from import * —— 簡潔但危險的 # from math import * # from os import * # ?? os沒有__all__,會導(dǎo)入所有名稱! # 不到萬不得已不要用
四、最佳實踐
# ? 推薦做法一:默認使用 import 模塊名 import math import json import os # 清晰、安全、不會污染命名空間 # ? 推薦做法二:社區(qū)標(biāo)準(zhǔn)的別名 import numpy as np import pandas as pd import matplotlib.pyplot as plt # ? 推薦做法三:from import 特定名稱——只導(dǎo)入幾個時 from collections import defaultdict, Counter from pathlib import Path from typing import Optional, List # ? 推薦做法四:導(dǎo)入子模塊 import os.path # 導(dǎo)入子模塊 from os import path # 另一種方式 # ? 避免的做法 # 1. 不要用 from module import *(除非在__init__.py中) # 2. 不要給模塊起奇怪的別名 # 3. 不要同時用多種導(dǎo)入方式從同一個模塊導(dǎo)入 # 不好的例子: # import math # from math import sqrt # 重復(fù)了
五、總結(jié)
四種導(dǎo)入方式各有適用場景??傮w原則是:以代碼可讀性為第一優(yōu)先。
選型速查:
| 方式 | 適用場景 | 風(fēng)險 |
|---|---|---|
import math | 默認選擇,使用模塊中多個功能 | 低 |
import numpy as np | 長模塊名,社區(qū)約定 | 低 |
from math import sqrt | 只用到1-2個功能 | 中——命名沖突 |
from math import * | 幾乎只在__init__.py中 | 高——不推薦 |
黃金法則:寧可多寫幾個字符,也別讓讀代碼的人猜每個名字來自哪里。
到此這篇關(guān)于Python模塊基礎(chǔ)指南之import的四種導(dǎo)入方式全對比的文章就介紹到這了,更多相關(guān)Python import模塊導(dǎo)入內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Python使用from...import...模塊導(dǎo)入指定內(nèi)容的方法詳解
- 一文詳解Python import導(dǎo)入模塊與模塊的搜索路徑
- Python from import導(dǎo)入模塊所有內(nèi)容的方法
- Python使用from?import導(dǎo)入模塊中的指定內(nèi)容
- Python基礎(chǔ)之import導(dǎo)入模塊并調(diào)用其函數(shù)的完整指南
- Python模塊導(dǎo)入之import、from、相對導(dǎo)入與?init.py詳解
- Python中ImportError:無法導(dǎo)入模塊的問題解決辦法
- 詳解Python中import模塊導(dǎo)入的實現(xiàn)原理
- Python importlib動態(tài)導(dǎo)入模塊實現(xiàn)代碼
相關(guān)文章
python 生成正態(tài)分布數(shù)據(jù),并繪圖和解析
這篇文章主要介紹了python 生成正態(tài)分布數(shù)據(jù),并繪圖和解析,幫助大家更好的利用python進行數(shù)據(jù)分析,感興趣的朋友可以了解下2020-12-12

