您好,登錄后才能下訂單哦!
一個(gè) .py文件 就是一個(gè)模塊(Module)。
在開(kāi)發(fā)過(guò)程中我們不會(huì)把所有的代碼都寫(xiě)在一個(gè) .py文件 中。隨著代碼量的增大,可以按照功能將函數(shù)或者類(lèi)分開(kāi)存放到不同的 .py文件 中。
?
這樣代碼更方便管理,以及后期的維護(hù),也便于其他程序來(lái)調(diào)用當(dāng)前已經(jīng)實(shí)現(xiàn)的功能~
?
在開(kāi)發(fā)過(guò)程中,我們也經(jīng)常引用其他模塊,例如:time,os,configparser,re 等等
在Python中模塊一般有如下3種:
1)Python內(nèi)置模塊
2)第三方模塊
3)自定義模塊
導(dǎo)入模塊的語(yǔ)句如下:
import module1[, module2[,... moduleN]
或
import module1
import module2
...
import moduleN
具體使用哪一種方式根據(jù)個(gè)人習(xí)慣而定,導(dǎo)入模塊后,模塊中的方法或者類(lèi)可以通過(guò) 模塊名.方法() 直接調(diào)用~
>>> import time
>>> time.time() # time() 為 time模塊中的方法
1545832129.4365451
>>> import datetime
>>> datetime.datetime.now() # datetime 為datetime模塊中的類(lèi)
datetime.datetime(2018, 12, 26, 21, 49, 2, 805953)
當(dāng)我們使用 import 語(yǔ)句導(dǎo)入模塊時(shí),Python解釋器首先會(huì)去內(nèi)置名稱(chēng)空間中尋找,即判斷導(dǎo)入的模塊是不是內(nèi)置模塊(例如time模塊就是Python內(nèi)置模塊),然后再去 sys.path 列表中定義的路徑從前往后尋找 .py文件
如下是在個(gè)人筆記本上輸出的 sys.path列表:
# pycharm中進(jìn)行輸出:
['/Users/baby/PycharmProjects/untitled/module',
'/Users/baby/PycharmProjects/untitled',
'/usr/local/Cellar/python/3.7.1/Frameworks/Python.framework/Versions/3.7/lib/python37.zip',
'/usr/local/Cellar/python/3.7.1/Frameworks/Python.framework/Versions/3.7/lib/python3.7',
'/usr/local/Cellar/python/3.7.1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/lib-dynload', '/usr/local/lib/python3.7/site-packages',
'/Applications/PyCharm.app/Contents/helpers/pycharm_matplotlib_backend']
# 在終端進(jìn)行輸出:
>>> sys.path
['', '/usr/local/Cellar/python/3.7.1/Frameworks/Python.framework/Versions/3.7/lib/python37.zip',
'/usr/local/Cellar/python/3.7.1/Frameworks/Python.framework/Versions/3.7/lib/python3.7',
'/usr/local/Cellar/python/3.7.1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/lib-dynload',
'/usr/local/lib/python3.7/site-packages']
? ~ ls /usr/local/Cellar/python/3.7.1/Frameworks/Python.framework/Versions/3.7/lib/python3.7
LICENSE.txt fileinput.py re.py
__future__.py fnmatch.py reprlib.py
__phello__.foo.py formatter.py rlcompleter.py
...
...
現(xiàn)在我自己編輯了一個(gè)模塊 sftp,內(nèi)容如下:
server_ip = '192.168.0.30'
def get_file():
print('ddownload file ...')
然后在 main.py文件(與sftp.py在同一個(gè)路徑下) 中進(jìn)行導(dǎo)入:
import sftp
?
在 import sftp 時(shí),Python解釋器會(huì)首先創(chuàng)建一個(gè)新的名稱(chēng)空間,這個(gè)名稱(chēng)空間用于存放 sftp 模塊中定義的名字,然后在該名稱(chēng)空間中執(zhí)行 sftp.py 文件。
例如現(xiàn)在在 sftp 模塊中添加 print 語(yǔ)句,然后執(zhí)行 main.py文件:
# sftp.py
server_ip = '192.168.0.30'
def get_file():
print('ddownload file ...')
print('hello ....')
# main.py
import sftp
# 執(zhí)行 main.py 后會(huì)有如下輸出:
hello ....
import語(yǔ)句 可以理解為定義了一個(gè)變量,而該變量就指向?qū)?yīng)的名稱(chēng)空間,通過(guò)使用這個(gè)變量來(lái)引用該名稱(chēng)空間中的方法及變量~
?
import sftp 之后,注意區(qū)分新創(chuàng)建的名稱(chēng)空間和當(dāng)前的名稱(chēng)空間,示例如下:
# sftp.py
server_ip = '192.168.0.30'
def get_file():
print('ddownload file ...')
# main.py
import sftp
server_ip = '1.2.3.4'
print(server_ip)
print(sftp.server_ip)
# 執(zhí)行 main.py 后會(huì)有如下輸出:
1.2.3.4
192.168.0.30
在導(dǎo)入模塊的時(shí)候還可以對(duì)模塊進(jìn)行重命名,以方便使用;若是當(dāng)前文件中存在同名的方法或變量,也可以通過(guò)這種方式避免沖突~
import datetime as date
date.datetime.now()
from import 語(yǔ)法如下:
from modname import name1[, name2[, ... nameN]]
import語(yǔ)句的導(dǎo)入會(huì)新建一個(gè)名稱(chēng)空間,將模塊中的名稱(chēng)存放在該名稱(chēng)空間中,而 'from modname import name1, name2' 則會(huì)將name1 和 name2 單個(gè)導(dǎo)入到當(dāng)前的名稱(chēng)空間中。既然是導(dǎo)入到當(dāng)前的名稱(chēng)空間中,那就可以直接拿來(lái)使用,前面不需要再添加模塊名稱(chēng)。
from datetime import datetime
print(datetime.now()) # 不需要寫(xiě)成 datetime.datetime.now()
?
若是 from … import 導(dǎo)致了名稱(chēng)重讀,則哪一個(gè)后定義,就使用哪一個(gè)
def foo():
pass
from demo import foo
# 這里引用 foo 函數(shù),會(huì)使用 demo 模塊中的 foo函數(shù)
#############
from demo import foo
def foo():
pass
# 這里引用 foo 函數(shù),會(huì)使用 當(dāng)前文件中的 foo函數(shù)
簡(jiǎn)單而言,Python中的包(Package)就是一個(gè)目錄,里面存放了 .py文件,外加一個(gè) __init__.py。通過(guò)目錄的方式來(lái)組織眾多的模塊,包就是用來(lái)管理和分類(lèi)模塊的。引入包之后,還有一個(gè)好處就是 同名的模塊可以放在不同的包下,以避免名稱(chēng)沖突~
?
例如現(xiàn)在有如下3個(gè)包,ROOT,pk_1,pk_2:
模塊m1的全名是:ROOT.pk_1.m1;模塊m2的全名則是:ROOT.pk_2.m2 ~
在每一個(gè)包目錄下,都應(yīng)該有一個(gè) __init__.py 文件,若這個(gè)文件不存在,那么這個(gè)目錄只是一個(gè)目錄而不是一個(gè)包。__init__.py 文件可以是空文件,也可以有 Python 代碼,原則是盡量保持 __init__.py 文件的精簡(jiǎn)~
?
導(dǎo)入包的語(yǔ)句如下:
import package
# 或引入包下的某一個(gè)模塊
from package import module
import package 或者 from package import module 都會(huì)執(zhí)行package 包下的 __init__ 文件
?
現(xiàn)在有如下目錄結(jié)構(gòu):
├─ROOT
│ ├─pk_1
│ │ ├─__init__.py
│ │ ├─m1.py
│ ├─pk_2
│ │ ├─__init__.py
│ │ └─m2.py
│ ├─__init__.py
│ ├─test.py
pk_1 和 pk_2 包中的 __init__.py 文件都為空,ROOT包下的 test.py 想要使用 pk_1 包下 m1模塊中的方法,可以使用如下語(yǔ)句:
from pk_1 import m1
m1.fun_1() # fun_1() 為m1模塊中的方法
但是使用如下語(yǔ)句,就會(huì)拋出異常:
from pk_1 import *
m1.fun_1()
# 異常信息:
NameError: name 'm1' is not defined
##############################
import pk_1
pk_1.m1.fun_1()
# 異常信息:
AttributeError: module 'pk_1' has no attribute 'm1'
這時(shí)候可以在 pk_1 包中的__init__.py 中 進(jìn)行 包提升(在包中提升導(dǎo)入權(quán)限),pk_1 包的 __init__.py 文件內(nèi)容如下:
from pk_1.m1 import fun_1
然后在 test.py 文件中可以直接通過(guò)包名引入方法:
# 1)
from pk_1 import fun_1 # 或 from pk_1 import *
fun_1()
# 2)
import pk_1
pk_1.fun_1()
?
這個(gè)就是 包中 __init__.py 文件存在的意義,可以將相關(guān)的導(dǎo)入語(yǔ)句 或 提升導(dǎo)入權(quán)限的語(yǔ)句 寫(xiě)在 __init__.py文件中,這樣使用者就不需要了解包中的內(nèi)部結(jié)構(gòu),可以直接通過(guò)包名 調(diào)用該包(package)中某個(gè)模塊的方法~
?
還可以在 包中 __init__.py 文件中使用 __all__ 列出需要導(dǎo)入的模塊,例如在 pk_1 包中的 __init__.py文件中添加 __all__ 變量:
__all__ = ['m2']
然后在 test.py 文件中就可以使用 from pk_2 import * 一次性導(dǎo)入 __all__變量中列出的模塊:
from pk_2 import *
m2.fun_2()
若是 pk_2 包的 __init__.py 文件已經(jīng)對(duì) fun_2 方法做了提升:
# pk_2 包的 \_\_init\_\_.py 內(nèi)容
from pk_2.m2 import fun_2
這樣在 test.py 中 import * 后可直接使用該方法:
from pk_2 import *
fun_2()
注意:當(dāng) __init__.py 中定義了 __all__ 變量時(shí),import * 只會(huì)導(dǎo)入 __all__中列出的模塊
現(xiàn)在有如下目錄結(jié)構(gòu):
├─log
│ ├─util
│ │ ├─__init__.py
│ │ ├─a.py
│ │ ├─b.py
│ ├─__init__.py
│ ├─test.py
在test中引入 a模塊:
from util import a
在 a 模塊中又引入了 b 模塊:
import b
這樣的話(huà)在執(zhí)行 test 文件時(shí)就會(huì)報(bào)錯(cuò),ModuleNotFoundError: No module named 'b',說(shuō)無(wú)法找到b模塊。
?
這是因?yàn)?在執(zhí)行 test 時(shí),sys.path 中的路徑不包含 util 下的路徑,所以在 a.py 文件中 import b 模塊時(shí)就會(huì)報(bào)錯(cuò)(若是直接執(zhí)行的是 a.py 文件就不會(huì)有問(wèn)題)。在 a模塊 中引入 b 模塊的正確的寫(xiě)法是:
from util import b
當(dāng)然這個(gè)時(shí)候 a.py 文件就不能再單獨(dú)運(yùn)行了,運(yùn)行時(shí)就會(huì)報(bào)錯(cuò)
?
Tip:在 a.py 文件中 使用 "from util import b" 導(dǎo)入模塊 b,這個(gè)時(shí)候若是直接執(zhí)行 a.py 文件就會(huì)報(bào)錯(cuò),因?yàn)?a.py 文件本身就位于util路徑下,sys.path(執(zhí)行 a.py 時(shí)的sys.path)中有util路徑,但是 'from util' 是找不到util的,util 位于 sys.path 的某個(gè)路徑下時(shí),'from util' 才能找到util ~
?
若是現(xiàn)在 主執(zhí)行文件 本身就位于項(xiàng)目目錄下的某個(gè)包中,要引入其他包中的模塊,就需要通過(guò)在 os.path 中添加路徑來(lái)實(shí)現(xiàn):
?
現(xiàn)在執(zhí)行文件是 bin 目錄下的 bin.py,在 bin.py 中要導(dǎo)入 util包 中的 a模塊 和 b模塊,為了保證通用性,可以使用如下方式獲取 log 路徑,并且添加到os.path中:
import sys, os
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from util import a
__name__ 與 __file__一樣,是一個(gè)內(nèi)置變量,這個(gè)變量記錄了當(dāng)前文件(使用 __name__ 變量的文件)是作為模塊運(yùn)行還是主執(zhí)行文件~
示例:
a.py 文件內(nèi)容
print(__name__)
# 直接執(zhí)行 a.py 文件,輸出:
# __main__
?
現(xiàn)在 在b.py文件中 import a。b.py 文件內(nèi)容如下:
import a
# 現(xiàn)在運(yùn)行 b.py 文件(這個(gè)過(guò)程會(huì)運(yùn)行 a.py 文件),輸出內(nèi)容:
# a ## 即 a 的模塊名稱(chēng)
這個(gè)功能經(jīng)常被用于代碼的調(diào)試:
if __name__=='__main__':
pass
可以將調(diào)試的代碼寫(xiě)在 if 語(yǔ)句中,用于調(diào)試當(dāng)前py文件中的代碼,因?yàn)橹苯舆\(yùn)行當(dāng)前文件, __name__ 變量的值就是 __main__。當(dāng)外部模塊調(diào)用的時(shí)候,就不會(huì)執(zhí)行 if 語(yǔ)句中的內(nèi)容,因?yàn)?外部模塊調(diào)用 __name__ 變量的值 為模塊名稱(chēng)~
.................^_^
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。