4th Python常用模塊
4.1 模塊介紹
4.1.1 模塊及其好處
隨著我們代碼寫的越來越多,功能越來越復(fù)雜,我們發(fā)在一個文件里維護就比較麻煩。所以我們就把不同的代碼放在不同的py文件里,比如我們把連接數(shù)據(jù)庫和后端和Web界面代碼分開放。
一個py文件就可以當(dāng)做最小的模塊。模塊最大的好處就是提高代碼的利用率,而且避免了函數(shù)名、變量名的沖突(a.py
下的calc()
函數(shù)和b.py
下的calc()
函數(shù)不會有任何問題,導(dǎo)入使用的時候也不會產(chǎn)生沖突)
問題來了,就是我們應(yīng)該怎么導(dǎo)入,這個我們下面馬上來介紹。
4.1.2 模塊的種類
那在如何導(dǎo)入之前,我們介紹一下模塊的分類。
模塊分為三種:
內(nèi)置模塊、標(biāo)準(zhǔn)模塊:安裝好Python后,自帶的模塊,大約300多個
第三方模塊:全球用Python的大佬會將自己寫的模塊上傳到社區(qū)中,供全球使用,目前總共有18w多
自定義模塊:自己寫的,就是自己寫的py文件,我們開頭一開始說到的就是自定義模塊。
4.1.3 模塊的導(dǎo)入
?# 導(dǎo)入
?import os # 導(dǎo)入
?print(os.path) # 調(diào)用os中的變量和函數(shù)方法
?
?# 導(dǎo)入多個模塊
?import os, sys
?
?# 前面的導(dǎo)入是導(dǎo)入模塊中的所有東西,我們也可以導(dǎo)入一個模塊中的單個東西
?from os import rename # 導(dǎo)入os中的rename方法
?rename('', '') # 不用os.rename()了
?# 導(dǎo)入多個方法也是同理
?# from os import rename, replace, ...
?
?# 導(dǎo)入模塊的東西下的東西也可以
?from os.path import curdir # 導(dǎo)入os模塊path下的curdir
?
?# 另外,我們還可以給導(dǎo)入的東西重命名
?from asyncio.events import get_event_loop_policy as get_event
?get_event() ?# 這樣我們就可以用新的名字用了,一般是防止名字太長,才重命名
?
?# 導(dǎo)入模塊下所有東西(不推薦使用)
?from os import * # 和import os的不同的是,我們不用調(diào)用
?rename() # 不用os.rename()
?# 因為from os import *導(dǎo)入的所有東西不用調(diào)用,就會和其他導(dǎo)入的模塊或者你自己寫的東西沖突,致使你的代碼很亂
模塊的導(dǎo)入一般全寫在開頭,不要在代碼中間或其他地方亂寫,不方便維護
4.1.3 自定義模塊
放在同目錄下的兩個py文件的調(diào)用
?# file_1.py
?def say_hi(name):
? ? ?print('hi, ', name)
?# file_2.py
?import file_1 # pycharm可能會提示錯誤,不用管,我們下面解釋
?file_1.say_hi('zm') ?# 輸出hi, zm
但是,我們在其他地方就導(dǎo)入不了file_1.py
了,而且上面的代碼中自定義模塊的導(dǎo)入pycharm也會提示錯誤,這些問題到底是什么原因?
因為Python默認(rèn)的查找路徑是固定的,從開發(fā)社區(qū)下載的第三方庫都放在site-packages
中,標(biāo)準(zhǔn)庫放在第三方庫的上層目錄。我們在cmd中進入python,導(dǎo)入os
庫,打印os.path
,我們可以看到第一個元素是空,就代表當(dāng)前目錄,所以import
每次先找同目錄下的,然后接著找標(biāo)準(zhǔn)庫、第三方庫那里,都沒找到就報錯。
所以我們想讓所有程序在任何地方都可以調(diào)用到我們自己寫的模塊,我們就要把那個模塊的py文件放到site-packages
下
4.1.4 安裝第三方模塊
pip或者pip3
?pip install 模塊名
或者
?pip3 install 模塊名
這個方法的前提條件是必須要有python的環(huán)境變量。
不過python的pip默認(rèn)是去國外的python社區(qū)下載,可能會很慢或者鏈接不上,所以我們可以使用國內(nèi)的python鏡像網(wǎng)站,一般是豆瓣源或者是清華源,具體可以去CSDN找方案。
pip的卸載:
?pip uninstall
顯示安裝過的庫:
?pip list
或者
?pip freeze
4.2 常用模塊應(yīng)用
4.2.1 os & sys——系統(tǒng)調(diào)用
os
getcwd()
:獲取當(dāng)前py文件的目錄路徑;listdir()
:獲取指定目錄下的所有文件和目錄名;os.path.isfile()
:判斷指定路徑是否是文件;os.path.isdir()
:判斷是否是一個目錄;os.path.isabs()
:判斷是否為絕對路徑;os.path.exists()
:檢測地址是否真的存在;os.path.abspath()
:獲取絕對路徑;os.name
:顯示你正在使用的操作系統(tǒng)(Windows是nt,Linux/Uinux是posix);os.rename(old, new)
:文件重命名;os.replace(old, new)
:替換文件;os.makedirs()
:創(chuàng)建多級目錄,eg:os.makedirs(r'\python\test')
,在當(dāng)前目錄下創(chuàng)建python文件夾,其中包含子文件夾test;os.mkdir()
:創(chuàng)建單級目錄,eg:os.mkdir('python')
,在當(dāng)前目錄下創(chuàng)建python文件夾,但是創(chuàng)建多級目錄就不行,會報錯;os.stat(file)
:獲取文件屬性;os.path.getsize(filename)
:獲取文件大??;
sys
argv()
:命令行參數(shù),以list的形式返回,list中第一個參數(shù)是程序本身的路徑,前面用到過;exit()
:exit()
這個方法Python可以不導(dǎo)入就可以用,而且功能差不多,所以可以忽略;maxint()
:獲取最大的int值;path()
:返回python模塊的搜索路徑;platform()
:返回程序運行的操作系統(tǒng);getrecursionlimit()
:獲取最大遞歸層數(shù);getdefaultencoding()
:獲取Python解釋器的編碼;getfilesystemencoding()
:獲取內(nèi)存數(shù)據(jù)存到文件里的默認(rèn)編碼。
模塊調(diào)用需要注意
?import os
?# abspath(__file__)可以獲得當(dāng)前py文件的絕對路徑
?print(os.path.abspath(__file__))
?print(os.path.dirname(os.path.abspath(__file__)))
4.2.2 time等——時間處理
時間模塊的使用還是比較多的,我們寫程序?qū)r間的處理歸為以下三種:
時間的顯示:在屏幕顯示、或者日志記錄。
時間的轉(zhuǎn)換:吧字符串格式的日期轉(zhuǎn)換成Python中可以運算的日期類型
時間的運算:計算兩個日期間的差值。
時間通常的表示格式
時間戳:timestamp,表示的是從1970年1月1號0點按秒開始計算到現(xiàn)在的秒數(shù)。1970年是第一次Unix操作系統(tǒng)的誕生。python中用
time.time()
獲取當(dāng)前時間戳。格式化的字符串:比如
"2020-10-03 17:54"
元組(
struct_time
):一共九個元素。由于Python的time模塊的實現(xiàn)主要調(diào)用的是C語言的庫,所以各個操作系統(tǒng)可能會有所不同,Windows上:time.struct_time
為time.struct_time(tm_year=2020, tm_mon=11, tm_mday=22, tm_hour=15, tm_min=53, tm_sec=11, tm_wday=6, tm_yday=327, tm_isdst=0)
UTC時間:格林威治時間,世界標(biāo)準(zhǔn)時間,在中國為UTC+8,東8區(qū)。DST(
Daylight Saving Time
)即為夏令時。
time
time.localtime([secs])
:將一個時間戳轉(zhuǎn)換為當(dāng)前時區(qū)(中國全部都是東8區(qū))的struct_time
元組。不寫參數(shù)默認(rèn)是當(dāng)前時間;time.gmtime([secs])
:和localtime()
類似,和localtime
差八個小時,時區(qū)不一樣。同樣,不寫參數(shù)也默認(rèn)是當(dāng)前時間;time.mktime()
:將struct_time
元組轉(zhuǎn)換成時間戳,和上面相反;time.sleep(secs)
:程序停幾秒鐘,單位為秒;time.asctime([t])
:用的不多,將struct_time
元組傳入,返回英文格式的時間字符串;time.ctime()
:將時間戳傳入,返回英文格式的時間字符串;time.strftime(format, [t])
:格式化字符串,可以按我們想要的格式來輸出時間,eg:time.strftime("%Y.%m-%d %H:%M %p", time.localtime())
,輸出結(jié)果為2020.11-22 16:11 PM;time.strptime()
:和strftime()
相反,eg:time.strptime('2020/04/01 19:30', "%Y/%m/%d %H:%M")
,然后就可以獲得相應(yīng)的時間戳。
字符串轉(zhuǎn)時間格式對應(yīng)表:

time中時間格式的轉(zhuǎn)換圖:

datetime
datetime
比time
更加直觀、更加容易調(diào)用。time
一般用來格式化時間輸出或者獲取時間戳;datetime
更多用來計算時間。
datetime
模塊分為五種數(shù)據(jù)類型,分別是date
、datetime
、time
、timedelta
、tzinfo
。
date
:
datetime.date.today()
:獲取當(dāng)前時間,輸出一般為datetime.date(2020, 11, 22)
datetime.date.timetuple(date)
:將上面的date
格式轉(zhuǎn)化成struct_time
元組,eg:datetime.date.timetuple(datetime.date.today())
,輸出:time.struct_time(tm_year=2020, tm_mon=11, tm_mday=22, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=6, tm_yday=327, tm_isdst=-1)
datetime.date.ctime()
:和time.ctime()
一樣,輸出英文的時間格式datetime.date.fromtimestamp()
:把時間戳轉(zhuǎn)換成date
類型
time
:date
輸出年月日,time
輸出的是小時分鐘秒等時間信息。
datetime
:
datetime.datetime.now()
:獲取當(dāng)前時間,類型為datetime
類型,eg:datetime.datetime(2020, 11, 23, 10, 57, 48, 525775)
datetime.datetime.fromtimestamp()
:將時間戳轉(zhuǎn)換成datetime
類型
timedelta
:
datetime.timedelta()
:參數(shù)格式為默認(rèn)參數(shù),可以傳入的參數(shù)有天數(shù)、毫秒和秒。eg:?import datetime
?now_time = datetime.datetime.now() # 獲取當(dāng)前時間
?the_time = now_time - datetime.timedelta(days=3, hours=4, minutes=5) ?# 將當(dāng)前時間減去3天4小時5分鐘 # 參數(shù)寫負(fù)數(shù)也可以
時間替換:
time1.replace(year=2000, month=1, day=1)
,上面的date
、time
、datetime
類型都可以用這個來進行時間的替換。
tzinfo
:與時區(qū)有關(guān)的,在金融行業(yè)的工作和時區(qū)比較常使用
pytz
這個模塊就是與時區(qū)相關(guān)的模塊,pytz.all_timezones()
輸出所有時區(qū),pytz.all_timezone(地區(qū))
就可以獲取時區(qū),t1 = pytz.all_timezone('Asia/Shanghai')
獲取之后,然后datetime.datetime.now(tz=t1)
,就可以生成指定時區(qū)的時間。
4.2.3 random——隨機
py文件的命名
py文件的命名別和內(nèi)置模塊名重復(fù),不然會沖突。
random的方法
random.randint(1, 10)
:返回1到10(包括10)的一個隨機數(shù);random.randrange(1, 10)
:返回1到10(不包括10)的一個隨機數(shù);random.random()
:返回一個0到1之間的隨機浮點數(shù);random.choice(the_str)
:返回給定字符串中的一個隨機字符,列表、元組也可以,但set
和dict
不可以;random.sample(the_str, num)
:返回num個字符串中的隨機字符(列表、集合、元組都可以,字典不行),以列表形式返回;?# 隨機驗證碼
?import string
?import random
? print(''.join(random.sample(string.digits+string.ascii_lowercase, 5)))random.shuffle(the_list)
:將列表數(shù)據(jù)打亂,會默認(rèn)修改原來的列表數(shù)據(jù),修改成打亂的列表數(shù)據(jù),數(shù)據(jù)就只能是列表。
4.2.4 pickle——序列化
pickle
我們知道,字符串是可以寫入文件的,因為Python自動幫我們將字符串通過編碼轉(zhuǎn)換寫入硬盤,但是像字典、列表、集合、元組這些數(shù)據(jù)怎么存進硬盤呢?這是就涉及到序列化的知識點。
序列化即是:將字典、列表這些數(shù)據(jù)序列化轉(zhuǎn)成硬盤能認(rèn)識的數(shù)據(jù)類型,比如說16進制的字節(jié)。
?d = {
? ? ?"name": "alex",
? ? ?"role": "police",
? ? ?"blood": 76,
? ? ?"weapon": "AK47",
?}
?
?d_dump = pickle.dumps(d) # 序列化,返回16進制的字節(jié)
?print(d_dump)
?print(pickle.loads(d_dump)) ?# 反序列化
?
?f = open("game.pkl", "wb")
?# f.write(d_dump)
?pickle.dump(d, f) # 和write一樣,將
?f.close()
?
?f = open("game.pkl", "rb")
?# f.read()
?pickle.load(f) # 先取先dump進去的
?pickle.load(f) # 取第二次dump進去的
?# pickle.load(f) # 沒數(shù)據(jù)時就報錯
?
?# dump寫入文件,load讀出文件;
?# dumps是生成序列化的字符串,loads將序列化的字符串反序列化解析
當(dāng)然,上面的演示代碼我們dump
和load
了好幾次,在實際開發(fā)中我們建議dump
一次,load
一次,不然程序很大的話,你也記不住程序到底dump
了幾次。我們可以將需要寫入文件的序列化數(shù)據(jù)存在一個列表(或其他)里,然后dump
這個列表,即可實現(xiàn)一次dump
多個需要序列化的數(shù)據(jù)了。
我們將序列化的數(shù)據(jù)寫入文件,文件肯定會產(chǎn)生亂碼,因為這是通過pickle
的規(guī)則轉(zhuǎn)化的bytes
數(shù)據(jù),和編碼的格式肯定不同,只要我們讀出來不是亂碼就說明數(shù)據(jù)沒有被破壞,這點需要注意一下。
json vs pickle
除了pickle
,json
也是用來序列化的模塊。他們最大的區(qū)別就是:json各種語言都能用,但是只支持str
、int
、dict
、set
、list
、tuple
這些基本的數(shù)據(jù)類型,以后寫東西需要跨語言,就會用到json
;pickle
是Python專屬的,支持Python所有的數(shù)據(jù)類型,比如function
、datetime
、class/object
全都可以。
?# json
?d = {
? ? ?"name": "alex",
? ? ?"role": "police",
? ? ?"blood": 76,
? ? ?"weapon": "AK47",
?}
?
?print(json.dumps(d)) # dict變成了字符串
?print(type(json.dumps(d))) # <class 'str'>
?
?with open("test.json", "w") as f:
? ? ?json.dump(d, f)
?with open("test.json", 'r') as f:
? ? ?json.load(f)
注意:json
如果dump
多次,load
就會報錯,因為json
不支持多次dump
。
而且我們可以注意到json
和pickle
的另一個區(qū)別:
json
是將字典、列表這些數(shù)據(jù)先轉(zhuǎn)化成字符串,然后再通過編碼存入硬盤,所以我們可以看到我們json轉(zhuǎn)化的時候點開文件我們看不到亂碼。另外,json
這樣的方式耗費的空間比pickle
小。
以后我們盡量使用json
,因為json
用的比較多,pickle
基本不怎么用,知道就好。
4.2.6 hashlib——加密
hash,也就是散列或者哈希,不同的值映射出來的可以是相同的(數(shù)據(jù)量極大的情況下會出現(xiàn),又稱哈希碰撞)
MD5
我們每次進Python時,對相同數(shù)據(jù)的hash
值都會不一樣,從而hash不能直接用來加密,所以我們需要確保hash
輸出的值是穩(wěn)定的,所以MD5(訊息摘要演算法)誕生了。
功能:
任意長度 -> 固定的長度;
不同數(shù)據(jù)會得出不同MD5值(極小可能會重復(fù))
特點:
壓縮性;
容易計算;
抗修改性;
強抗碰撞(極小可能會重復(fù))。
MD5算法和hash一樣,是不可逆的。
用途:
防止被篡改。
防止直接看到明文。
數(shù)字簽名。
用法:
?import hashlib
?m = hashlib.md5() # 開啟md5加密(創(chuàng)建md5的一個對象)
?m.update("Hello world".encode('utf-8')) ?# 傳入加密數(shù)據(jù)
?m.update("asd".encode('utf-8'))
?# print(m.digest()) ?# 加密,返回byte,不常用
?print(m.hexdigest()) # 加密,返回16進制(常用)
?
?# 多個update是放一塊加密的,直接拼一起
?m2.hashlib.md5()
?m2.update("Hello worldasd".encode('utf-8'))
?print(m2.hexdigest()) # 和上面的m.hexdigest()輸出一樣的值
注意,如果密碼是純數(shù)字或純小寫字符組成的密碼,及有可能被撞庫撞出來,就是一個一個試md5密文,已達(dá)到破解md5算法的目的。
一般網(wǎng)站通過在md5密文后再加上一些字節(jié)(俗稱加鹽),這樣數(shù)據(jù)庫被黑客攻擊,黑客拿到的md5密文也不可能反推出原來對應(yīng)的明文密碼。
SHA
SHA對于2^64以內(nèi)的數(shù)據(jù)會產(chǎn)生160位的消息摘要,比md5的128多了幾十位,所以安全性比md5高一些。SHA是美國國家安全局設(shè)計的,目前最流行的是SHA-256。HTTPS就是基于SHA-256的,網(wǎng)站的加密是SSL2(以前是SSL1)也是基于SHA-256的。SHA-256是生成256位的消息摘要,更加難以破解。
用法和md5一樣
?s2 = hashlib.sha256()
?s2.update('zm'.encode('utf-8'))
?print(s2.hexdigest())
當(dāng)然,SHA產(chǎn)生的消息摘要位數(shù)越多,加密耗費的時間也越多,所以md5一般用于文件校驗,因為比較快;SHA-256一般就用在網(wǎng)站的安全維護上。
4.2.7 shutil——文件操作
shutil
shutil.copyfileobj(f1, f2)
:傳入的參數(shù)必須是打開的文件就是說必須傳進兩個文件的對象(f = open('filename', 'w', encoding='utf-8')
,f
就是一個文件對象),將f1中的內(nèi)容copy到f2中,不常用;copyfile(old_filename, new_filename)
:傳入兩個文件名,新的文件如果和已有的文件重名就會被覆蓋;copymode()
:copy文件的權(quán)限,兩個文件必須存在。將第一個文件的文件權(quán)限copy到第二個文件的文件權(quán)限,兩個文件的權(quán)限改變,內(nèi)容什么的都不變,不常用;copystat()
:copy文件的狀態(tài),第二個文件必須存在,覆蓋掉第二個文件的創(chuàng)建時間啥的文件狀態(tài),用的也不多;copy()
:創(chuàng)建一個文件,然后copy權(quán)限和文件內(nèi)容copyfile()
和copymode()
的結(jié)合;copy2()
:copy文件內(nèi)容和狀態(tài),copyfile()
和copystat()
的結(jié)合;copytree()
:copy目錄,新目錄必須不存在,另外還可以設(shè)置ignore
參數(shù),可以設(shè)置不想要的文件。?import shutil
?shutil.copytree("", "", ignore=shutil.ignore_patterns("", ""))
?move(src, dst)
:如果第二個文件夾存在,移動文件src
文件夾下的所有文件到dst
文件夾下,如果第二個文件夾不存在,那move()
本質(zhì)上就是重命名;rmtree(src)
:刪除文件src
文件夾下的所有文件;make_archive(base_name, format, root_dir)
:base_name
是壓縮包的文件名,format
是壓縮的格式(zip
、tar
等),root_dir
是需要壓縮的文件夾;
zipfile&tarfile
shutil.make_archive()
是基于zipfile
和tarfile
寫出來的,這里我們就順便來看看這兩個模塊。
?import zipfile
?import tarfile
?
?# zip文件壓縮
?with zipfile.ZipFile('test.zip', 'w') as z:
? ? ?z.write('test.txt')
? ? ?z.write('web.log')
?
?# zip文件解壓
?with zipfile.ZipFile('test.zip', 'r') as z:
? ? ?z.extractall('new/zip/')
?
?# tar文件壓縮
?with tarfile.TarFile('test.tar', 'w') as t:
? ? ?t.add('test.txt')
? ? ?t.add('web.log')
?
?# tar文件解壓
?with tarfile.TarFile('test.tar', 'r') as t:
? ? ?t.extractall('new/tar/')
4.2.8 re——正則表達(dá)式
入門
正則表達(dá)式是一個很重要的一個知識點,在我們后面的web開發(fā)(Python的Django)中大量用到。
首先我們有一個需求,就是讀取文件中的所有手機號
?# test.txt
?朱明 12345611233
?王芝偉 13265411344
?# test.py
?with open('test.txt', 'r') as f:
? ? ?phone_list = []
? ? ?for line in f:
? ? ? ? ?name, phone = line.split(' ')
? ? ? ? ?if phone[0] == '1':
? ? ? ? ? ? ?phone_list.append(phone)
現(xiàn)在我們有一個更加簡便的方法。
?import re
?with open('test.txt', 'r') as f:
? ? ?phone_list = re.findall('[0-9]{11}]', f.read())
?print(phone_list)
這就是正則表達(dá)式,你幾行的代碼瞬間可以寫成一行代碼。
匹配語法
那學(xué)習(xí)正則表達(dá)式的語法之前呢,我們先來學(xué)習(xí)re
的匹配語法,分為以下幾種:
re.match(pattern, string, flags=0)
:從起始位置開始根據(jù)模型去字符串中匹配指定內(nèi)容,匹配開頭的字符是否符合指定內(nèi)容,不常用;re.search(pattern, string, flags=0)
:根據(jù)模型去字符串中匹配指定內(nèi)容,匹配到一個符合就返回,不往下找了;re.findall(pattern, string, flags=0)
:match()
和search()
均用于匹配單值,即:只能匹配字符串中的一個,如果想要匹配到字符串中所有符合條件的元素,則需要使用findall()
;re.split(pattern, string, maxsplit=0, flags=0)
:用匹配到的值做為分割點,把值分割成列表,eg:split("[0-9]", "asd1asd2asd3zxc")
,輸出的是['asd', 'asd', 'asd', 'zxc']
;re.sub(pattern, string, flags=0)
:用于替換匹配的字符串,比str.replace()
功能更加強大,eg:sub("abc", "ABC", "abcdef", count=2)
,輸出ABCdef
,count
是指最多尋找?guī)状危?/p>re.fullmatch(pattern, string, flags=0)
:全部匹配,和findall()
類似,不過返回的是match類型的數(shù)據(jù)需要group()
來處理輸出。
表達(dá)式規(guī)則
.
:匹配任意一個字符(除了\n
,其他符號都可以匹配),比如print(search('.', 'zm123'))
返回的是<re.Match object; span=(0, 1), match='z'>
,要輸出的話必須加一個group()
,print(search('.', 'zm123').group())
輸出的就是z
;^
:匹配字符的開頭,比如``$
:匹配字符的結(jié)尾*
:從開頭匹配一個字符0次或多次,0次返回的不是None,返回<re.Match object; span=(0, 1), match=''>
+
:匹配多次?
:匹配一個字符0次或1次;{m}
:匹配m次;{m, n}
:匹配m到n次包括m和n;|
:或,匹配左邊的字符或者右邊的字符;(...)
:分組匹配;[]
:比如[a-z]
匹配所有小寫字符,[A-Z]
匹配所有大寫,[a-zA-Z0-9]
匹配所有小寫大寫和數(shù)字;\A
:只從字符開頭匹配,像search('\Aabc', 'zmabc')
返回的就是None,相當(dāng)于match()
;\Z
:匹配字符結(jié)尾;\d
:匹配數(shù)字0-9;\D
:匹配非數(shù)字;\w
;匹配a-z,A-Z和0-9的字符;\W
;匹配非[a-zA-Z0-9]
s
:匹配空白字符、\t、\n、\r;(?P<name>...)
:分組匹配,比如分組讀取身份證號:re.search(([0-9]{3})([0-9]){3}(0-9){4}, '身份證號')
,然后groups()
輸出分組的數(shù)據(jù);我們還可以起名字:re.search((?P<province>[0-9]{3})(?P<city>[0-9]{3})(?P<year>(0-9){4}), '身份證號')
然后用groupdict()
輸出字典。
當(dāng)需要篩選的字符串中包含-
、+
、*
等語法字符時,我們可以在其前面加\
來表示非語法字符。
那這些match
、search
、findall
等等幾個匹配語法,都有解析正則表達(dá)式的需要,re
模塊的設(shè)計者也將這部分的功能獨立編寫了函數(shù)compile()
,我們可以在需要大量解析正則表達(dá)式的時候,統(tǒng)一compile()
,然后再用match
、search
這些方法,傳入?yún)?shù)只需要所分析的數(shù)據(jù)就好了。
flags
在上面match、search等匹配語法中,都有一個叫flags的參數(shù),F(xiàn)lags被稱作標(biāo)志符,有幾個固定的值
re.I
:忽略大小寫re.M
:多行模式,改變^
和$
。eg:re.search('^zm', 'mack\nzmghd')
返回None
,但是我們加上多行模式,就可以匹配到數(shù)據(jù)了,re.search('^zm', 'mack\nzmghd', re.M)
就會輸出找到的zm
。re.M
用的不多,知道即可;re.S
:改變.
的行為,原本.
不能匹配出\n
,但是加上這個就可以匹配了;re.X
:加注釋,注釋語法和Python是一樣的,一般寫的太復(fù)雜時會用。
練習(xí)
驗證手機號是否合法;
?import re
?
?phone = input('請輸入字符:').strip()
?# 用fullmatch是為了字符總長度需為11,用findall就不會有總長11的限制
?if re.fullmatch('[0-9]{11}', phone) and re.search('^1', phone):
? ? ?print('手機號碼符合標(biāo)準(zhǔn)')
?else:
? ? ?print('輸入字符不合法')驗證郵箱是否合法;
?import re
?
?mail = input('請輸入字符:').strip()
?
?if re.fullmatch('\d+@(qq|chzu)\.(com|edu|cn)', mail):
? ? ?print('合法')
?else:
? ? ?print('不合法')開發(fā)一個簡單的python計算器,實現(xiàn)加減乘除及括號優(yōu)先級解析,比如
1-2*((60-30+(-40/5)*(9-2*5/3+7/3*99/4*2998 +10*568/14))-(-4*3)/(16-3*2))
。這部分暫且擱置一下(其實是暫時沒思路),自己之后寫寫看= =
4.3 軟件項目設(shè)計規(guī)范
4.3.1 項目目錄設(shè)計規(guī)范
目錄設(shè)計規(guī)范的好處
我們設(shè)計一個層次清晰的目錄結(jié)構(gòu),就是為了達(dá)到以下兩點:
可讀性高
可維護性高
這里看個大概就好了,我們后面寫比較大的程序時,自己親手寫幾遍就會了。
好的目錄組織方式
假設(shè)現(xiàn)在我們寫一個Foo的大項目,推薦的文件結(jié)構(gòu)如下:
?Foo/
?|-- bin/
?| ? |-- foo
?|
?|-- foo/
?| ? |-- tests/
?| ? | ? |-- __init__.py
?| ? | ? |-- test_main.py
?| ? |-- core/
?| ? |-- __init__.py
?| ? |-- main.py
?|
?|-- docs/
?| ? |-- conf.py
?| ? |-- abc.csv
?|
?|-- setup.py
?|-- requirements.txt
?|-- README
bin/
:放一些可執(zhí)行的文件,當(dāng)然你也可以起名script/
之類的也可;foo/
:存放項目的所有源代碼;源代碼中所有模塊、包都應(yīng)該放這里;
子目錄
test/
存放單元測試代碼;程序的入口最好命名為
main.py
。doc/
:存放一些文檔;setup.py
:安裝、部署、打包的腳本;requirements.txt
:存放軟件依賴的外部Python包列表,有一個pip命令可以快速生成電腦的python環(huán)境信息:?pip freeze > requirements.txt
README.md
:項目說明文件。
當(dāng)然,還有更多的規(guī)范內(nèi)容,比如LICENSE.txt
、ChangeLog.txt
等,他們是項目開源時需要用到的,開源軟件的目錄組織可以參考 。
關(guān)于README
這個文件主要目的是讓讀者快速熟悉代碼的主要功能和一些重要信息,需要說明以下幾點:
軟件定位:軟件的基本功能。
運行代碼的方法。安裝環(huán)境、啟動命令等。
簡要的使用說明。
代碼目錄結(jié)構(gòu)說明,更詳細(xì)可惡意說明軟件的基本原理。
常見問題說明。
關(guān)于requirements.txt
這里就寫一些調(diào)用的庫,包括庫名和版本。
關(guān)于setup.py
setup.py是來管理代碼的打包、安裝、部署問題。業(yè)界標(biāo)準(zhǔn)的寫法是用Python流行的打包工具
來管理這些事情。不過,我們初學(xué)的時候不是讓我們養(yǎng)成用標(biāo)準(zhǔn)化的工具來解決這些問題,而是一個項目一定要有一個安裝部署的工具,能讓自己的代碼在一臺新機器上迅速將環(huán)境裝好、代碼部署好,最后可以使程序正常運行起來。配置文件
即是settings.py
末
有什么Python代碼或者其他問題可以私信問我或者在下面留言,Python課程設(shè)計我也偶爾可以有償幫做,祝大家變得更強[狗頭]
剩下的就是和上一篇文章末尾一樣要說的,我就當(dāng)成套話了。
套話:因為小破站上的文本格式對演示代碼極其不友好,而且自己平時的筆記是通過Markdown語法來記錄的,在格式上和美觀程度上不是很好看,如果你看的不習(xí)慣,就去下載一個Typora(或者支持markdown語法的應(yīng)用),我這里給出md文件的迅雷網(wǎng)盤鏈接(百度網(wǎng)盤上傳不了),然后用Typora打開文件看就好了。
鏈接:https://pan.xunlei.com/s/VMVzuPFHFx9Z9EkrEKyKbTgmA1
提取碼:nnfs
咳咳,emmm,這里再加幾句話吧。
到這里呢,Python基礎(chǔ)的系列就快要結(jié)束了,接下來就是Python面向?qū)ο?/span>和網(wǎng)絡(luò)編程,比較的難,如果你之前完全沒有接觸過面向?qū)ο蟮母拍?,可能會有些不適應(yīng),希望大家可以耐住性子學(xué)下去(如果真的想學(xué)的話);
網(wǎng)絡(luò)編程會先從網(wǎng)絡(luò)這個話題引入,然后再涉及計算機組成原理,最后再到應(yīng)用層程序的邏輯解釋。概念....怎么減都還是很多,不過網(wǎng)絡(luò)編程這一章就是Python基礎(chǔ)的最終章了。
感謝給我鼓勵的大家,如果你喜歡這個系列,就給每篇文章點一個贊(收藏和投幣我也不會拒絕的,不過會睡不著覺,哈哈哈),也希望大家多多評論,問問題什么的都可以噠。