python3常用標準庫
趁著有時間,把一些我用過的常用標準庫進行整理和復習,
time
| 用法 | 說明 |
|---|---|
time.time() |
回傳時間戳(從1970年1月1日00:00:00開始計算) |
time.localtime() |
回傳當前時間的結構化時間(struct_time)物件,可以用.tm_year等獲取年等資料 |
time.gmtime() |
回傳世界標準時間的結構化時間(struct_time)物件 |
time.mktime(struct_time) |
結構化時間轉化為時間戳 |
time.strftime("時間格式", struct_time) |
結構化時間轉化為字串時間 |
time.strptime("字串時間", "時間格式") |
字串時間轉化為結構化時間 |
time.asctime([tuple]) |
時間元組轉換為字串,如果時間元組不存在,則使用localtime()回傳的當前時間 |
time.ctime(seconds) |
將時間秒數轉換為時間字串,相當于time.asctime(localtime(seconds)),second不存在,則使用localtime()回傳的當前時間, |
常用時間占位符
- 年 %Y
- 月 %m
- 日 %d
- 時 %H (24小時制)
- 分 %M
- 秒 %S
- 時分秒 %X ,相當于
%H:%M:%S

time庫各方法關系
datetime
雖然python庫中已經有了time庫,但time庫不支持對時間的加減等操作,因此就有了datetime庫,
| 用法 | 說明 |
|---|---|
datetime.datetime.now() |
獲取當前時間,回傳datetime.datetime物件,有year, month, day, hour, minute, second, microsecond等屬性, |
datetime.timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0 |
這是一個類,表示兩個 date 或者 time 的時間間隔, |
datetime.datetime.fromtimestamp(seconds) |
將秒數轉換為datetime.datetime物件,datetime.datetime.fromtimestamp(time.time())<==>datetime.datetime.now() |
datetime.timetuple() |
這是datetime.datetime物件的方法,回傳結構化時間,time.localtime() 的回傳型別相同 |
datetime.replace(year=self.year, month=.., day=.., hour=.., minute=.., second=.., ...) |
一樣是datetime.datetime物件的方法,可以替換當前物件的year等屬性,詳見檔案 |
有了以上幾個方法,我們就可以對時間進行加減操作,并可以在time和datetime之間進行轉換,
- datetime.datetime之間可以相減,結果為datetime.timedelta物件,有days和seconds屬性
- datetime.datetime與datetime.timedelta之間可以加減,結果為datetime.datetime物件
- datetime.timedelta本身可以乘以一個數,以表示不同的時間間隔
import time
import datetime
def main():
date1_string = "2017/6/8 15:0:0"
# date1_string轉換為時間戳
# strptime -> mktime -> fromtimestamp ==> datetime.datetime
date1 = datetime.datetime.fromtimestamp(time.mktime(
time.strptime(date1_string, '%Y/%m/%d %H:%M:%S')))
date2 = datetime.datetime.now() # 獲取當前時間
# 使用datetime.datetime物件之間 進行操作,結果為datetime.timedelta物件
result1 = date2 - date1 # 兩個時間過了多久了
print(result1.days, result1.seconds)
# datetime.datetime與datetime.timedelta之間的操作, 結果是datetime.datetime物件
year = datetime.timedelta(days=365) # 一年時間
result2 = date2 + 2 * year # 當前時間的兩年后
print(result2.year, result2.month, result2.day)
if __name__ == '__main__':
main()
random
使用random可以生成偽亂數,
| 用法 | 說明 |
|---|---|
random.seek(time.time()) |
初始化亂數生成器 |
random.random() |
生成[0.0, 1.0) 范圍內的一個隨機浮點數 |
random.uniform(num1, num2) |
回傳[num1, num2] [1] 中一個隨機浮點數 |
random.randint(num1, num2) |
生成[num1, num2] 范圍內的一個整數,num1, num2均為int |
random.randrange(num1, num2) |
生成[num1, num2) 范圍內的一個整數,num1, num2均為int |
random.choice(iterable_obj) |
從可迭代物件中隨機取一個元素 |
random.sample(iterable_obj, n) |
從可迭代物件中隨機取n個元素組成一個串列回傳 |
random.shuffle(x) |
將序列 x 隨機打亂位置,不可變的可以用random.sample(x, k=len(x)) |
生成驗證碼例子:
import random
def make_code(n):
res = ''
for i in range(n):
letter = chr(random.randint(65, 90)) # 生成A-Z的任意一個字母
number = str(random.randint(0, 9)) # 生成0-9的任意一個數
res += random.choice([letter, number])
return res
print(make_code(9))
sys
sys模塊提供了一些與解釋器相關的變數和函式,
| 用法 | 說明 |
|---|---|
sys.argv |
回傳一個串列,第一個元素是程式本身路徑,其他元素是命令列輸入引數 |
sys.exit(n) |
退出程式,實作方式是拋出一個SystemExit例外,正常時n為0,非零值視為“例外終止”,大多數系統要求該值的范圍是 0~127, |
sys.path |
回傳模塊的搜索路徑,其本質上是串列,可以使用append方法添加路徑,匯入特定模塊, |
sys.platform |
回傳平臺名稱(Linux:'linux',Windows:'win32',Mac OS X:darwin') |
sys.stdout.write(" ") |
不換行列印 |
sys.stdout.flush() |
重繪 |
os
一般用于對檔案和目錄進性操作的模塊,
路徑相關
os.getcwd() 獲取當前作業目錄
os.chdir(path) 改變當前作業目錄
檔案/目錄操作
| 用法 | 說明 |
|---|---|
os.mkdir(path) |
創建目錄 |
os.makedirs(path) |
遞回創建目錄 |
os.redir(path) |
洗掉空目錄 |
os.removedirs(path) |
遞回洗掉空目錄 |
os.remove(path) |
洗掉檔案 |
os.rename(old_name, new_name) |
更改檔案或目錄名 |
os.stat(path) |
查看檔案詳情( 'st_atime', 'st_ctime', 'st_mtime', 'st_size'等) |
輸出符號
| 用法 | 說明 |
|---|---|
os.sep |
輸出系統分隔符(如:\或/) |
os.linesep |
輸出行終止符(win:\r\n,linux:\n) |
os.pathsep |
輸出路徑分割符(win:;,linux::) |
path
path是os庫中的一個模塊,里面有很多實用的函式,
| 用法 | 說明 |
|---|---|
os.path.split(path) |
把路徑分割為(目錄, 檔案名) |
os.path.abspath(path) |
回傳path規范化的絕對路徑 |
os.path.normpath(path) |
回傳path規范化后的結果 |
os.path.dirname(path) |
split結果的個第一元素 |
os.path.basername(path) |
split結果的個第二元素 |
os.path.join(path1, path2, path3 ...) |
把多個路徑拼接成一個,并回傳 |
os.path.exists(path) |
判斷路徑是否存在 |
os.path.isabs(path) |
判斷路徑是否為絕對路徑 |
os.path.isfile(path) |
判斷路徑是否為檔案 |
os.path.isdir(path) |
判斷路徑是否為目錄 |
os.path.getatime(path) |
回傳檔案/目錄的最后訪問時間,回傳值是一個浮點數,為紀元秒數 |
os.path.getctime(path) |
回傳檔案/目錄的最后修改時間,回傳值是一個浮點數,為紀元秒數 |
os.path.getmtime(path) |
Unix:回傳元資料的最后修改時間,Win:回傳創建時間,回傳值是一個數,為紀元秒數 |
os.path.size(path) |
回傳檔案/目錄的大小,以位元組為單位 |
shutil
shutil模塊提供了一系列對檔案和檔案集合的高階操作, 特別是提供了一些支持檔案拷貝和洗掉的函式,
拷貝操作
-
shutil.copyfileobj(fsrc, fdst[, length])
將檔案類物件 fsrc 的內容拷貝到檔案類物件 fdst,length表示緩沖區大小,且默認情況為:1024 * 1024 if WINDOWS else 64 * 1024,import shutil shutil.copyfileobj(open("./t1/a.txt", "r"), open("t1/b.txt", "w"))注意有個fsrc是讀,而fdst是寫
-
shutil.copyfile(src, dst)
將src檔案拷貝到dst檔案,dst可以不存在import shutil shutil.copyfile("./t1/a.txt", "./t1/b.txt") -
shutil.copymode(src, dst)
僅拷貝權限,內容、組、用戶均不變,此功能并不是在所有平臺上均可用(查看檔案,了解更多)import shutil shutil.copymode("./t1/a.txt", "./t1/b.txt") -
shutil.copystat(src, dst)
從 src 拷貝權限位、最近訪問時間、最近修改時間以及旗標到 dst. -
shutil.copy(src, dst)
拷貝檔案和權限 -
shutil.copy2(src, dst)
拷貝檔案和狀態資訊 -
shutil.copytree(src, dst)
遞回拷貝,引數很多,沒有詳細列出import shutil shutil.copytree('folder1', 'folder2', ignore=shutil.ignore_patterns('*.pyc', 'tmp*')) # 目標目錄不能存在,注意對folder2目錄父級目錄要有可寫權限,ignore的意思是排除
洗掉操作
shutil.rmtree(path, ignore_errors=False, one rror=None)
遞回洗掉檔案夾,前面說過:空檔案夾用os.redir(path),單個檔案用os.remove(path);onerror引數可以指定處理程式來處理例外(ignore_errors為False時)
移動操作
shutil.move(src, dst)
遞回地將一個檔案或目錄 (src) 移至另一位置 (dst) 并回傳目標位置,同一目錄時為重命名,類似于mv命令,
json
json模塊可以把python基本資料型別與json資料進行轉換,
-
json.dumps(data)
將基本資料型別格式轉換為json資料import json data = https://www.cnblogs.com/lczmx/p/{ "name": "lczmx", "age": 20, } s = json.dumps(data) print(repr(s)) # '{"name": "lczmx", "age": 20}' -
json.dump(data, file_obj)
將基本資料型別轉換為json資料并寫入到檔案中import json data = https://www.cnblogs.com/lczmx/p/{ "name": "lczmx", "age": 20, } f = open("./res.json", "w", encoding="utf-8") json.dump(data, f) f.close() -
json.loads(s)
把json字串轉化為python資料型別import json s = '{"name": "lczmx", "age": 20}' res = json.loads(s) print(res, type(res)) # {'name': 'lczmx', 'age': 20} <class 'dict'> -
json.load(file_obj)
轉換檔案物件的json內容,import json with open("./res.json", "r", encoding="utf-8") as f: res = json.load(f) print(res, type(res))
擴展json
json模塊只支持python基本資料型別,但我們可以自定義JSON編碼器,重寫default方法,這樣我們自己寫的類就可以使用
json.dumps了
import json
class Foo:
def __init__(self, name, age):
self.name = name
self.age = age
def data_dict(self):
# 回傳的是基本資料型別
return {"name": self.name, "age": self.age}
class JsonCustomEncoder(json.JSONEncoder):
# 重寫default方法
def default(self, field):
if isinstance(field, Foo):
return field.data_dict() # 呼叫自定義的方法
else:
return json.JSONEncoder.default(self, field)
f = Foo("lczmx", 21)
# 使用時要指定自定義的編碼器
res = json.dumps(f, cls=JsonCustomEncoder)
print(res)
# {"name": "lczmx", "age": 21}
pickle
模塊 pickle 實作了對一個 Python 物件結構的二進制序列化和反序列化,它只能用于Python,并且可能不同版本的Python彼此都不兼容,因此,只能用Pickle保存那些不重要的資料,不能成功地反序列化也沒關系,
注意:pickle 模塊并不安全,你只應該對你信任的資料進行unpickle操作.
import pickle
dic = {'name': 'alvin', 'age': 23, 'sex': 'male'}
print(type(dic)) # <class 'dict'>
j = pickle.dumps(dic)
print(type(j)) # <class 'bytes'>
f = open('序列化物件_pickle', 'wb') # 注意是w是寫入str,wb是寫入bytes,j是'bytes'
f.write(j) # -------------------等價于pickle.dump(dic,f)
f.close()
# -------------------------反序列化
f = open('序列化物件_pickle', 'rb')
data = https://www.cnblogs.com/lczmx/p/pickle.loads(f.read()) # 等價于data=https://www.cnblogs.com/lczmx/p/pickle.load(f)
print(data['age'])
shelve
shelve" 是一種持久化的類似字典的物件,只有open方法,比pickle簡單,
由于 shelve 模塊需要 pickle 的支持,所以shelve模塊也不安全,需要注意是否為信任資料才能使用,
import shelve
d = shelve.open("持久化檔案.txt")
# 以 d[key] = data 的形式存盤
d["name"] = "lczmx"
d["age"] = 22
d["addr"] = "guangzhou"
d["data"] = [1, 2, 3]
# 使用中括號取值
name = d["name"]
print(name) # lczmx
# 使用del洗掉某個鍵對應的值
del d["age"]
# 可以使用 in 判斷某個鍵是否存在
flag = "age" in d
print(flag) # False
# .keys()方法 可以列出所有的鍵 (速度較慢!)
klist = list(d.keys())
print(klist) # ['name', 'addr', 'data']
# 值即使是參考物件,假如要保存修改后的值,要重新賦值
temp = d['data']
temp.append(4)
print(d["data"]) # [1, 2, 3]
d['data'] = temp
print(d["data"]) # [1, 2, 3, 4]
# close掉,可以使用背景關系管理協議
d.close()
xml
xml也是一個可以跨語言的資料交換協議,但使用起來沒有json簡單,由于xml誕生的時間比json早,所以至今還有一些公司正在使用,
生成xml
步驟:
- 創建根節點
- 為根節點添加子節點
- 為位元組點添加內容和屬性
- 生成檔案物件樹
- 保存到檔案等
import xml.etree.ElementTree as ET
# 創建根節點
new_xml = ET.Element("namelist")
# 為跟節點創建位元組點
name1 = ET.SubElement(new_xml, "name", attrib={"enrolled": "yes"})
age1 = ET.SubElement(name1, "age", attrib={"checked": "no"})
# 添加內容
name1.text = '老王'
age1.text = "30"
# 同上
name2 = ET.SubElement(new_xml, "name", attrib={"enrolled": "no"})
age2 = ET.SubElement(name2, "age")
name2.text = "隔壁"
age2.text = '33'
# 生成檔案物件
et = ET.ElementTree(new_xml)
# 寫入檔案中
et.write("test.xml", encoding="utf-8", xml_declaration=True)
# 列印生成的格式
ET.dump(new_xml)
結果:
<?xml version='1.0' encoding='utf-8'?>
<namelist>
<name enrolled="yes">老王<age checked="no">30</age></name>
<name enrolled="no">隔壁<age>33</age></name>
</namelist>
讀取xml
對xml檔案進行操作,用的是parse方法和getroot方法
import xml.etree.ElementTree as ET
tree = ET.parse("./test.xml")
root = tree.getroot()
以下都以root即根節點這個物件進行操作
root可以換成任意子節點
查看
root.tag獲取標簽名root.attrib獲取屬性root.text獲取內容
遍歷/查找
root.iter(tag)查找子孫節點中的tag標簽,以迭代器方式回傳root.find(tag)查找子節點的第一個tag標簽root.findall(tag)找子節點的所有tag標簽
修改
root.text="xx"修改內容root.set("屬性名", "屬性值")設定屬性值
洗掉
root.remove(node)洗掉子節點
struct
此模塊可以執行 Python 值和以 Python bytes 物件表示的 C 結構之間的轉換, 這可以被用來處理存盤在檔案中或是從網路連接等其他來源獲取的二進制資料,
一般使用它的兩個函式:
struct.pack("格式", data)struct.unpack("格式", byte_data)
import struct
# 資料 -> bytes
pi = 3.14159265358
res = struct.pack("f", pi)
print(res, type(res)) # b'\xdb\x0fI@' <class 'bytes'> # 已經轉化為位元組型別
# bytes -> 原資料
data = https://www.cnblogs.com/lczmx/p/struct.unpack("f", res)
print(data, type(data)) # (3.1415927410125732,) <class 'tuple'>
| 格式 | C 型別 | Python 型別 | 標準大小 | 注釋 |
|---|---|---|---|---|
| x | 填充位元組 | 無 | ||
| c | char | 長度為 1 的位元組串 | 1 | |
| b | signed char | 整數 | 1 | (1), (2) |
| B | unsigned char | 整數 | 1 | (2) |
| ? | _Bool | bool | 1 | (1) |
| h | short | 整數 | 2 | (2) |
| H | unsigned short | 整數 | 2 | (2) |
| i | int | 整數 | 4 | (2) |
| I | unsigned int | 整數 | 4 | (2) |
| l | long | 整數 | 4 | (2) |
| L | unsigned long | 整數 | 4 | (2) |
| q | long long | 整數 | 8 | (2) |
| Q | unsigned long long | 整數 | 8 | (2) |
| n | ssize_t | 整數 | (3) | |
| N | size_t | 整數 | (3) | |
| e | (6) | 浮點數 | 2 | (4) |
| f | float | 浮點數 | 4 | (4) |
| d | double | 浮點數 | 8 | (4) |
| s | char[] | 位元組串 | ||
| p | char[] | 位元組串 | ||
| P | void * | 整數 | (5) |
re
正則運算式是用來描述字符或字串的特殊符號,在python中用re模塊實作,正則運算式模式被編譯成一系列的位元組碼,用 C 撰寫的匹配引擎執行,
元字符
正則運算式語言由兩種基本字符型別組成:原義(正常)文本字符和元字符,元字符實質上就是有特殊含義的字符,
下面列舉一些常用的元字符,參考檔案給出的元字符
| 字符 | 描述 | 列子 |
|---|---|---|
\\ |
匹配\ | |
\w |
匹配字母、數字、下劃線 | |
\W |
匹配非字母數字下劃線 | |
\s |
匹配空白字符 | |
\S |
匹配非空白字符 | |
\d |
匹配數字 | |
\D |
匹配非數字 | |
\n |
匹配換行符 | |
\t |
匹配制表符 | |
^ |
匹配字串的開頭 | |
$ |
匹配字串的結尾 | |
. |
匹配除換行符外的所有字符,當re.DOTALL標記被指定時,可以匹配換行符 | |
[] |
匹配括號中的每一個字符,如[abc]表示a、b、c |
|
[^] |
匹配不在括號中的字符,如[^abc]表示不是a或b |
|
* |
對它前面的正則式匹配0到任意次重復,如\w*表示0到任意個數字 |
|
+ |
對它前面的正則式匹配1到任意次重復 | |
? |
對它前面的正則式匹配0到1次重復 | |
{n} |
對其之前的正則式指定匹配 m 個重復;少于 m 的話就會導致匹配失敗,如\w{6}表示6個數字 |
|
{n,m} |
對正則式進行 n 到 m 次匹配,在 n 和 m 之間取盡量多, | |
a|b |
匹配a或b | |
() |
組合,匹配括號內的運算式 |
更多可以看這篇文章 linux shell 正則運算式(BREs,EREs,PREs)差異比較
關于(?…)個擴展標記法,可以看官方檔案,
方法
查找
| 使用 | 說明 |
|---|---|
re.findall(pattern, string) |
匹配所有結果,回傳一個串列,空匹配也會包含在結果里 |
re.finditer(pattern, string) |
匹配所有結果,回傳由匹配物件(re.Match)構成的迭代器 , string 從左到右掃描,匹配按順序排列,空匹配也包含在結果里, |
re.search(pattern, string) |
匹配第一個結果,回傳匹配物件(re.Match),未匹配到時為None |
re.match(pattern, string) |
字串開頭相當于re.search("^ ...", string)是否匹配pattern,是則回傳匹配物件(re.Match),未匹配到時為None |
分割
re.split(pattern, string, maxsplit=0, flags=0)
以pattern規則分割string,結果以串列形式回傳,maxsplit非零時,表示分割多少次,flags=re.IGNORECASE可以忽略大小寫import re s = "12a21v13xsa15" res = re.split("[a-z]+", s) print(res) # ['12', '21', '13', '15']
替換
- re.sub(pattern, repl, string, count=0, flags=0)
回傳通過使用 repl 替換在 string 最左邊非重疊出現的 pattern 而獲得的字串,
可選引數 count 是要替換的最大次數;count 必須是非負整數,如果省略這個引數或設為 0,所有的匹配都會被替換,
假如repl引數是一個函式,那么可以極大擴展替換功能,import re s = "12a21v13xsa15" res = re.sub("[a-z]+", ", ", s) print(res) # 12, 21, 13, 15import re s = "name=lczmx, age=22" def repl_func(matchobj): age = int(matchobj.group("age")) return str(age + 1) res = re.sub(r"(?P<age>\d+)", repl_func, s) print(res) # name=lczmx, age=23
匹配物件(re.Match)操作
Match.group([group1, ...])
回傳一個或者多個匹配的子組,如果只有一個引數,結果就是一個字串,如果有多個引數,結果就是一個元組,使用正則運算式使用了(?P<name>…)語法,可以用Match.group("name")的方式取值,Match.groups(default=None)
回傳一個元組,包含所有匹配的子組- Match.groupdict(default=None)?
回傳一個字典,包含了所有的命名子組,key就是組名import re s = "[email protected],user" res = re.match(r"([a-zA-Z]+)@(\w+\.com)", s) print(res.groups()) # ('abc', 'example.com') print(res.group(0)) # [email protected] print(res.group(1)) # abc print(res.group(2)) # example.com res = re.match(r"(?P<prefix>\w+)@(?P<suffix>\w+\.com)", s) print(res.groups()) # ('abc', 'example.com') print(res.group(0)) # [email protected] print(res.group(1)) # abc print(res.group("prefix")) # abc print(res.group(2)) # example.com print(res.group("suffix")) # example.com print(res.groupdict()) # {'prefix': 'abc', 'suffix': 'example.com'}
去括號優先級
假如這樣的例子:
import re
res = re.findall(r"(abc)+", "abcabcabc")
print(res) # ['abc']
其匹配結果是["abc"],而非["abcabcabc"],這是因為括號的優先級高,假如要括號與后面的元字符相結合的化可以使用以下方法:
import re
res = re.findall(r"(?:abc)+", "abcabcabc")
print(res) # ['abcabcabc']
匹配原理
關于正則匹配原理,看此文,
logging
關于日志管理的基本教程,請點擊這里
關于使用日志的流程,大約有以下步驟:
- 呼叫
logging.basicConfig()設定logging,確定日記級別、是否輸入到檔案、資訊格式等引數 - 根據需求,呼叫
logging的debug、info、warning、error、critical方法
注意
由于logging.basicConfig()只需要定義一次,所以debug等方法應該在其被設定后呼叫
列印到終端
列印到終端是開發程序中的一個實用的方法,
import logging
logging.basicConfig()
logging.debug("debug messages")
logging.info("info messages")
logging.warning("warning messages")
logging.error("error messages")
logging.critical("critical messages")
由于默認日志級別為WARNING,所以只在終端顯示了后三行資訊
寫入檔案
為basicConfig()增加filename引數即可
import logging
logging.basicConfig(filename="test.log")
logging.debug("debug messages")
logging.info("info messages")
logging.warning("warning messages")
logging.error("error messages")
logging.critical("critical messages")
python 3.9版本的logging.basicConfig() 可以指定
encoding引數,之前的以系統默認的編碼方式打開,
多模塊使用
在多個模塊中import logging即可,其操作的是同一個logging物件
import logging
import mylib
def main():
logging.basicConfig()
logging.warning("start function")
mylib.my_func()
logging.warning("end function")
print(id(logging)) # 2248755624272
if __name__ == '__main__':
main()
./mylib.py
# ./mylib.py
import logging
def my_func():
logging.error("error massage")
print(id(logging)) # 2248755624272
修改日志級別
日志級別從低到高:
| 級別 | 何時使用 |
|---|---|
| DEBUG | 細節資訊,僅當診斷問題時適用, |
| INFO | 確認程式按預期運行 |
| WARNING | 表明有已經或即將發生的意外(例如:磁盤空間不足),程式仍按預期進行 |
| ERROR | 由于嚴重的問題,程式的某些功能已經不能正常執行 |
| CRITICAL | 嚴重的錯誤,表明程式已不能繼續執行 |
默認級別為WARNING
修改日志級別要用到logging.basicConfig()的level引數,其傳入的值是一個在logging模塊中已經被定義好的數:
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
例子:
import logging
logging.basicConfig(level=logging.INFO)
logging.warning("start function")
從命令列中接收日志級別
使用argparse庫接收命令列引數,再使用getattr()方法從logging模塊中把對應的日志級別取出來:
import logging
import argparse
# log選項的值只能是level_list的元素
level_list = ["debug", "info", "warning", "warn", "error", "fatal", "critical"]
level_list.extend(list(map(lambda x: x.upper(), level_list))) # 全大寫再加入
parser = argparse.ArgumentParser(description="test file")
parser.add_argument("--log", default="debug", choices=level_list)
args = parser.parse_args()
# 拿到級別字串后要大寫
level = getattr(logging, args.log.upper())
logging.basicConfig(level=level)
logging.debug("debug messages")
logging.info("info messages")
logging.warning("warning messages")
logging.error("error messages")
logging.critical("critical messages")
$ python test.py --log error
ERROR:root:error messages
CRITICAL:root:critical messages
$ python test.py --log info
INFO:root:info messages
WARNING:root:warning messages
ERROR:root:error messages
CRITICAL:root:critical messages
configparser
configparser庫是python的組態檔管理模塊,其所用結構與 INI 檔案的類似,
注意:小節(section)中的鍵(key)大小寫不敏感并且會存盤為小寫形式
寫
步驟:
- 創建物件
configparser.ConfigParser() - 在字典中添加資料,用中括號操作,類似字典
- 寫入檔案
import configparser
# 1 創建parser物件
config = configparser.ConfigParser()
# 2 添加資料
# 方法一
config["DEFAULT"] = {"HOST": "localhost", "PORT": "3306"}
# 方法二
config["CUSTOM"] = {}
config["CUSTOM"]["HOST"] = "192.168.0.1"
# 或
custom_config = config["CUSTOM"]
custom_config["PORT"] = "3333"
# 3 寫入檔案
with open("config.ini", "w") as f:
config.write(f)
最外層就是一個字典
config.ini檔案:
[DEFAULT]
host = localhost
port = 3306
[CUSTOM]
host = 192.168.0.1
port = 3333
讀
注意:DEFAULT不在sections()中,可以直接用["DEFAULT"].get(key)或.get("DEFAULT", key)取值
根據不同的需求可以用以下幾個方法:
-
config.read(path) 讀取組態檔
-
config.sections() 回傳可用節的串列,即
[xxx]中的xxx -
config.options(Section) 回傳鍵構成的元組
-
config.items(Section) 回傳串列,元素為鍵值對組成的元組
-
config.get(Section, key) 等價于 Section.get(key)
-
Section.get(key, default) 類似字典一樣取值
config 還可以通過使用for回圈,有.keys(), .values(), .items()
import configparser config = configparser.ConfigParser() config.read("./config.ini") print(config["DEFAULT"].get("host")) # localhost print(config.options("CUSTOM")) # ['host', 'port'] print(config.items("CUSTOM")) # [('host', '192.168.0.1'), ('port', '3333')]
刪操作
-
config.remove_section(section) 洗掉塊即整個
[xxx] -
config.remove_option(section, key) 洗掉塊下面的鍵(包括值)
import configparser config = configparser.ConfigParser() config.read("./config.ini") config.remove_section("CUSTOM") config.remove_option("DEFAULT", "host") config.write(open("./config.ini", "w"))
argparse
argparse是python推薦的命令列引數決議模塊,argparse基于optparse(3.2版中已經被棄用),所以兩者用法類似,
其一般的使用步驟是:
- 創建決議器
- 添加引數
- 決議引數
創建決議器
parser = argparse.ArgumentParser(description="計算兩個數的和", prog="SUM")
description引數可以指定幫助檔案之前顯示的描述資訊prog指定程式名,默認sys.argv[0]
添加引數
使用parser.add_argument(name or flags)方法,該方法可以指定位置引數或者是選項,而且它可以接收很多引數,下面列舉幾個常用的引數:
- action - 當引數在命令列中出現時使用的動作基本型別,
它的值列出這幾個更多可以看檔案:action值 說明 store存盤引數的值(默認) store_trueandstore_false分別用作存盤 True 和 False 值的特殊用例 version期望有一個 version= 命名引數,version引數可以用 %(prog)s的形式使用prog引數 - default - 設定默認值,
- type - 命令列引數應當被轉換成的型別,即把str轉成其他形式,
- choices - 可用的引數的容器(一般為串列),即引數值只能是里面的元素,
- required - 此命令列選項是否必需,默認
False
(一般來說選項是可以被省略的,不然換為位置引數更好), - help - 為此選項作用的簡單描述,使用-h或--help可以看到,
parser.add_argument("x", type=float, help="一個數x") # 添加位置引數x
parser.add_argument("y", type=float, help="一個數y") # 添加位置引數y
# 添加選項-a, 把值存盤為True
parser.add_argument("-a", action="store_true", help="顯示詳細程序")
# 添加選項-f,它的值知道能是[1, 2, 3]中的元素
parser.add_argument("-f", default=1, choices=[1, 2, 3],
type=int, help="保留小數點位數")
# 添加選項-v 或 --version
# 使用來自argparse.ArgumentParser的prog引數
parser.add_argument("-v", "--version", action="version",
version="%(prog)s 0.1", help="顯示版本")
決議引數
通過parser.parse_args()決議,然后通過.的方式取值(無論位置引數還是選項)
# 決議
args = parser.parse_args()
print(args.x)
print(args.a)
print(args.f)
完整例子
一個計算兩個數和的程式
import argparse
parser = argparse.ArgumentParser(description="計算兩個數的和", prog="SUM")
parser.add_argument("x", type=float, help="一個數x") # 添加位置引數x
parser.add_argument("y", type=float, help="一個數y") # 添加位置引數y
# 添加選項-a, 把值存盤為True
parser.add_argument("-a", action="store_true", help="顯示詳細程序")
# 添加選項-f,它的值知道能是[1, 2, 3]中的元素
parser.add_argument("-f", default=1, choices=[1, 2, 3],
type=int, help="保留小數點位數")
# 添加選項-v 或 --version
# 使用來自argparse.ArgumentParser的prog引數
parser.add_argument("-v", "--version", action="version",
version="%(prog)s 0.1", help="顯示版本")
# 決議
args = parser.parse_args()
# 計算并保留小數
res = round(args.x + args.y, args.f)
if args.a:
print("{x} + {y} = {res}".format(x=args.x, y=args.y, res=res))
else:
print(res)
在命令列中使用:
$ python get_sum.py -h
usage: SUM [-h] [-a] [-f {1,2,3}] [-v] x y
計算兩個數的和
positional arguments:
x 一個數x
y 一個數y
optional arguments:
-h, --help show this help message and exit
-a 顯示詳細程序
-f {1,2,3} 保留小數點位數
-v, --version 顯示版本
$ python get_sum.py -v
SUM 0.1
$ python get_sum.py 3.14 5.96
9.1
$ python get_sum.py 3.14 5.96 -a
3.14 + 5.96 = 9.1
$ python get_sum.py 3.14159 3.335 -f 3 -a
3.14159 + 3.335 = 6.477
$ python get_sum.py
usage: SUM [-h] [-a] [-f {1,2,3}] [-v] x y
SUM: error: the following arguments are required: x, y
hashlib
hashlib是針對不同的安全哈希和訊息摘要演算法實作了一個通用的介面,
生成md5
import hashlib
md5 = hashlib.md5()
# 輸入的是位元組串
md5.update("test message".encode("utf-8"))
res = md5.hexdigest()
print(res)
# c72b9698fa1927e1dd12d3cf26ed84b2
為md5加鹽
所謂加鹽就是update其他內容,改變md5的值,防止撞庫,
import hashlib
md5 = hashlib.md5()
# 輸入的是位元組
md5.update("加鹽".encode("utf-8"))
md5.update("test message".encode("utf-8"))
res = md5.hexdigest()
print(res)
# 3f5a030db81d9e5e83d2c8e7eba1965c
uuid
生成uuid4
import uuid
print(uuid.uuid4())
# f1d50cdd-2f36-4db2-b788-ec4f2f08ce52
subprocess
subprocess 模塊允許你生成新的行程,連接它們的輸入、輸出、錯誤管道,并且獲取它們的回傳碼,
對于subprocess模塊,我們只需要關注底層的Popen介面的使用方法即可,
常用引數:
args
一般來說是命令,推薦使用串列的方式傳入(有順序)shell
True或False
在 POSIX,當 shell=True, shell 默認為/bin/sh
在 Windows,當 shell=True,環境變數 COMSPEC 指定了默認 shell,執行命令時可以為True,但執行批處理檔案或可執行檔案時,不需要shell=Truestdin,stdout和stderr
分別指定了執行的程式的標準輸入、輸出和標準錯誤檔案句柄
它們的合法值一般有:- 其他Popen物件的stdin/stdout/stderr
subprocess.PIPE表示打開標準流的管道None- 檔案物件
更加詳細內容,請看官方檔案
獲取回傳資訊
- 使用
subprocess.PIPE接收 - popen_obj.stdout.read().decode("xx") 的方式
當然也可以在stdout中傳入檔案物件,直接寫入檔案中
使用例子
import subprocess
# 執行沒有引數的
subprocess.Popen(["dir"], shell=True, stdout=open("dir_res.txt", "w"))
# 有引數
# get_sum.py為argparse模塊最后的例子
command = "python get_sum.py 3.47 2.48 -a -f 2"
res2 = subprocess.Popen(command.split(" "), shell=True, stdout=subprocess.PIPE)
print(res2.stdout.read().decode("gbk")) # 3.47 + 2.48 = 5.95
# stdout作為stdin
res3 = subprocess.Popen(["echo", "www.baidu.com"],
shell=True, stdout=subprocess.PIPE)
res4 = subprocess.Popen(["nslookup"], shell=True,
stdin=res3.stdout, stdout=subprocess.PIPE)
print(res4.stdout.read().decode("gbk"))
"""
默認服務器: UnKnown
Address: 192.168.0.1
> 服務器: UnKnown
Address: 192.168.0.1
名稱: www.baidu.com
Address: 182.61.200.7
>
"""
我的github
我的博客
我的筆記
num1 > num2時為[num2, num1] ?
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/251951.html
標籤:Python
