Python 中的 import 与 from import 区别
對不少 Python 初學(xué)者來說,Python 導(dǎo)入其他模塊的方式讓他們很難理解。什么時候用import xxx?什么時候用from xxx import yyy?什么時候用from xxx.yyy import zzz?什么時候用from xxx import *?
系統(tǒng)自帶的模塊
以正則表達式模塊為例,我們經(jīng)常這樣寫代碼:
import retarget = 'abc1234xyz' re.search('(\d+)', target)但有時候,你可能會看到某些人這樣寫代碼:
from re import search target = 'abc1234xyz' search('(\d+)', target)那么這兩種導(dǎo)入方式有什么區(qū)別呢?
我們分別使用type函數(shù)來看看他們的類型:
>>> import re >>> type(re) <class 'module'> >>> from re import search >>> type(search) <class 'function'>如下圖所示:
可以看到,直接使用import re導(dǎo)入的re它是一個module類,也就是模塊。我們把它成為正則表達式模塊。而當(dāng)我們from re import search時,這個search是一個function類,我們稱呼它為search 函數(shù)。
一個模塊里面可以包含多個函數(shù)。
如果在你的代碼里面,你已經(jīng)確定只使用search函數(shù),不會再使用正則表達式里面的其他函數(shù)了,那么你使用兩種方法都可以,沒什么區(qū)別。
但是,如果你要使用正則表達式下面的多個函數(shù),或者是一些常量,那么用第一種方案會更加簡潔清晰。
例如:
import rere.search('c(.*?)x', flags=re.S) re.sub('[a-zA-Z0-9]', '***', target, flags=re.I)在這個例子中,你分別使用了re.search,re.sub,re.S和re.I。后兩者是常量,用于忽略換行符和大小寫。
但是,如果你使用from re import search, sub, S, I來寫代碼,那么代碼就會變成這樣:
import research('c(.*?)x', flags=S) sub('[a-zA-Z0-9]', '***', target, flags=I)看起來雖然簡潔了,但是,一旦你的代碼行數(shù)多了以后,你很容易忘記S和I這兩個變量是什么東西。而且我們自己定義的函數(shù),也很有可能取名為sub或者search,從而覆蓋正則表達式模塊下面的這兩個同名函數(shù)。這就會導(dǎo)致很多難以覺察的潛在 bug。
再舉一個例子。Python 的?datetime模塊,我們可以直接import datetime,此時我們導(dǎo)入的是一個datetime模塊,如下圖所示:
但是如果你寫為from datetime import datetime,那么你導(dǎo)入的datetime是一個type類:
因為這種方式導(dǎo)入的datetime,它就是Python 中的一種類型,用于表示包含日期和時間的數(shù)據(jù)。
這兩種導(dǎo)入方式導(dǎo)入的datetime,雖然名字一樣,但是他們的意義完全不一樣,請大家觀察下面兩種寫法:
import datetimenow = datetime.datetime.now() one_hour_ago = now - datetime.timedelta(hours=1) from datetime import datetime, timedelta now = datetime.now() one_hour_ago = now - timedelta(hours=1)第二種寫法看似簡單,但實則改動起來卻更為麻煩。例如我還需要增加一個變量today用于記錄今日的日期。
對于第一段代碼,我們只需要增加一行即可:
today = datetime.date.today()但對于第二行來說,我們需要首先修改導(dǎo)入部分的代碼:
from datetime import datetime, timedelta, date然后才能改代碼:today = date.today()
這樣一來你就要修改兩個地方,反倒增加了負(fù)擔(dān)。
第三方庫
在使用某些第三方庫的代碼里面,我們會看到類似這樣的寫法:
from lxml.html import fromstringselector = fromstring(HTML)但是我們還可以寫為:
from lxml import htmlselector = html.fromstring(HTML)但是,下面這種寫法會導(dǎo)致報錯:
import lxml selector = lxml.html.fromstring(HTML)那么這里的lxml.html又是什么東西呢?
這種情況多常見于一些特別大型的第三方庫中,這種庫能處理多種類型的數(shù)據(jù)。例如lxml它既能處理xml的數(shù)據(jù),又能處理html的數(shù)據(jù),于是這種庫會劃分子模塊,lxml.html模塊專門負(fù)責(zé)html相關(guān)的數(shù)據(jù)。
自己來實現(xiàn)多種導(dǎo)入方法
我們現(xiàn)在自己來寫代碼,實現(xiàn)這多種導(dǎo)入方法。
我們創(chuàng)建一個文件夾DocParser,在里面分別創(chuàng)建兩個文件main.py和util.py,他們的內(nèi)容如下:
util.py文件:
def write():print('write 函數(shù)被調(diào)用!')main.py文件:
import utilutil.write()運行效果如下圖所示:
現(xiàn)在我們把main.py的導(dǎo)入方式修改一下:
from util import writewrite()依然正常運行,如下圖所示
當(dāng)兩個文件在同一個文件夾下面,并且該文件夾里面沒有__init__.py 文件時,兩種導(dǎo)入方式等價。
”現(xiàn)在,我們來創(chuàng)建一個文件夾microsoft,里面再添加一個文件parse.py:
def read():print('我是 microsoft 文件夾下面的 parse.py 中的 read函數(shù)')如下圖所示:
此時我們在?main.py中對它進行調(diào)用:
from microsoft import parseparse.read()運行效果如下圖所示:
我們也可以用另一種方法:
from microsoft.parse import readread()運行效果如下圖所示:
但是,你不能直接導(dǎo)入microsoft,如下圖所示:
?你只能導(dǎo)入一個模塊或者導(dǎo)入一個函數(shù)或者類,你不能導(dǎo)入一個文件夾
”無論你使用的是import xxx還是from xxx.yyy.zzz.www import qqq,你導(dǎo)入進來的東西,要不就是一個模塊(對應(yīng)到.py 文件的文件名),或者是某個.py 文件中的函數(shù)名、類名、變量名。
無論是import xxx還是from xxx import yyy,你導(dǎo)入進來的都不能是一個文件夾的名字。
可能有這樣一種情況,就是某個函數(shù)名與文件的名字相同,例如:
在?microsoft文件夾里面有一個microsoft.py文件,這個文件里面有一個函數(shù)叫做microsoft,那么你的代碼可以寫為:
from microsoft import microsoft` microsoft.microsoft()但請注意分辨,這里你導(dǎo)入的還是模塊,只不過microsoft.py文件名與它所在的文件夾名恰好相同而已。
總結(jié)
無論是使用import還是from import,第一個要求是代碼能夠正常運行,其次,根據(jù)代碼維護性,團隊編碼風(fēng)格來確定選擇哪一種方案。
如果我們只會使用到某個模塊下面的一個函數(shù)(或者常量、類)并且名字不會產(chǎn)生混淆,可識別性高,那么from 模塊名 import 函數(shù)名這沒有什么問題。
如果我們會用到一個模塊下面的多個函數(shù),或者是我們將要使用的函數(shù)名、常量名、類名可能會讓人產(chǎn)生混淆(例如 re.S、re.I),那么這種情況下,import 模塊名然后再?模塊名.xxx來調(diào)用會讓代碼更加清晰,更好維護。
但無論什么情況下,都禁止使用from xxx import *這種寫法,它會給你帶來無窮無盡的噩夢。
總結(jié)
以上是生活随笔為你收集整理的Python 中的 import 与 from import 区别的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 项目经理这些技能,是项目成功的关键保障
- 下一篇: 新人如何快速上手项目管理