本節大綱
- 子產品介紹
- time &datetime子產品
- random
- os
- sys
- shutil
- json & picle
- shelve
- xml處理
- yaml處理
- configparser
- hashlib
- subprocess
- logging子產品
- re正規表達式
1:子產品介紹
子產品,用一砣代碼實作了某個功能的代碼集合。
類似于函數式程式設計和面向過程程式設計,函數式程式設計則完成一個功能,其他代碼用來調用即可,提供了代碼的重用性和代碼間的耦合。而對于一個複雜的功能來,可能需要多個函數才能完成(函數又可以在不同的.py檔案中),n個 .py 檔案組成的代碼集合就稱為子產品。
如:os 是系統相關的子產品;file是檔案操作相關的子產品
子產品分為三種:
- 自定義子產品
- 内置标準子產品(又稱标準庫)
- 開源子產品
子產品導入的三種方式:
方法一:
import modname
用import語句導入子產品,就在目前的名稱空間(namespace)建立了一個到該子產品的引用.這種引用必須使用全稱,也就是說,當使用在被導入子產品中定義的函數時,必須包含子產品的名字。是以不能隻使用 funcname,而應該使用 modname.funcname
方法二:
from modname import funcname
from modname import fa, fb, fc
from modname import *
與第1種方法的差別:funcname 被直接導入到本地名字空間去了,是以它可以直接使用,而不需要加上子產品名的限定* 表示,該子產品的所有公共對象(public objects)都被導入到 目前的名稱空間,也就是任何隻要不是以”_”開始的東西都會被導入。
modname沒有被定義,是以modname.funcname這種方式不起作用。并且,如果funcname如果已經被定義,它會被新版本(該導入子產品中的版本)所替代。如果funcname被改成指向其他對象,modname不能不會覺察到。
建議:
- 如果你要經常通路子產品的屬性和方法,且不想一遍又一遍地敲入子產品名,使用 from module import
- 如果你想要有選擇地導入某些屬性和方法,而不想要其它的,使用 from module import
- 如果子產品包含的屬性和方法與你的某個子產品同名,你必須使用import module來避免名字沖突
- 盡量少用 from module import * ,因為判定一個特殊的函數或屬性是從哪來的有些困難,并且會造成調試和重構都更困難。
2:time & datetime子產品
1 #_*_coding:utf-8_*_
2 __author__ = 'Alex Li'
3
4 import time
5
6
7 # print(time.clock()) #傳回處理器時間,3.3開始已廢棄 , 改成了time.process_time()測量處理器運算時間,不包括sleep時間,不穩定,mac上測不出來
8 # print(time.altzone) #傳回與utc時間的時間差,以秒計算\
9 # print(time.asctime()) #傳回時間格式"Fri Aug 19 11:14:16 2016",
10 # print(time.localtime()) #傳回本地時間 的struct time對象格式
11 # print(time.gmtime(time.time()-800000)) #傳回utc時間的struc時間對象格式
12
13 # print(time.asctime(time.localtime())) #傳回時間格式"Fri Aug 19 11:14:16 2016",
14 #print(time.ctime()) #傳回Fri Aug 19 12:38:29 2016 格式, 同上
15
16
17
18 # 日期字元串 轉成 時間戳
19 # string_2_struct = time.strptime("2016/05/22","%Y/%m/%d") #将 日期字元串 轉成 struct時間對象格式
20 # print(string_2_struct)
21 # #
22 # struct_2_stamp = time.mktime(string_2_struct) #将struct時間對象轉成時間戳
23 # print(struct_2_stamp)
24
25
26
27 #将時間戳轉為字元串格式
28 # print(time.gmtime(time.time()-86640)) #将utc時間戳轉換成struct_time格式
29 # print(time.strftime("%Y-%m-%d %H:%M:%S",time.gmtime()) ) #将utc struct_time格式轉成指定的字元串格式
30
31
32
33
34
35 #時間加減
36 import datetime
37
38 # print(datetime.datetime.now()) #傳回 2016-08-19 12:47:03.941925
39 #print(datetime.date.fromtimestamp(time.time()) ) # 時間戳直接轉成日期格式 2016-08-19
40 # print(datetime.datetime.now() )
41 # print(datetime.datetime.now() + datetime.timedelta(3)) #目前時間+3天
42 # print(datetime.datetime.now() + datetime.timedelta(-3)) #目前時間-3天
43 # print(datetime.datetime.now() + datetime.timedelta(hours=3)) #目前時間+3小時
44 # print(datetime.datetime.now() + datetime.timedelta(minutes=30)) #目前時間+30分
45
46
47 #
48 # c_time = datetime.datetime.now()
49 # print(c_time.replace(minute=3,hour=2)) #時間替換
3:random
import random
print(random.random())
print(random.randint(1, 2))
print(random.randrange(1, 10))
4:OS子產品
用于提供系統級别的操作:
os.getcwd() 擷取目前工作目錄,即目前python腳本工作的目錄路徑
os.chdir("dirname") 改變目前腳本工作目錄;相當于shell下cd
os.curdir 傳回目前目錄: ('.')
os.pardir 擷取目前目錄的父目錄字元串名:('..')
os.makedirs('dir1/dir2') 可生成多層遞歸目錄
os.removedirs('dirname1') 若目錄為空,則删除,并遞歸到上一級目錄,如若也為空,則删除,依此類推
os.mkdir('dirname') 生成單級目錄;相當于shell中mkdir dirname
os.rmdir('dirname') 删除單級空目錄,若目錄不為空則無法删除,報錯;相當于shell中rmdir dirname
os.listdir('dirname') 列出指定目錄下的所有檔案和子目錄,包括隐藏檔案,并以清單方式列印
os.remove() 删除一個檔案
os.rename("oldname","new") 重命名檔案/目錄
os.stat('path/filename') 擷取檔案/目錄資訊
os.sep 作業系統特定的路徑分隔符,win下為"\\",Linux下為"/"
os.linesep 目前平台使用的行終止符,win下為"\t\n",Linux下為"\n"
os.pathsep 用于分割檔案路徑的字元串
os.name 字元串訓示目前使用平台。win->'nt'; Linux->'posix'
os.system("bash command") 運作shell指令,直接顯示
os.environ 擷取系統環境變量
os.path.abspath(path) 傳回path規範化的絕對路徑
os.path.split(path) 将path分割成目錄和檔案名二進制組傳回
os.path.dirname(path) 傳回path的目錄。其實就是os.path.split(path)的第一個元素
os.path.basename(path) 傳回path最後的檔案名。如何path以/或\結尾,那麼就會傳回空值。即os.path.split(path)的第二個元素
os.path.exists(path) 如果path存在,傳回True;如果path不存在,傳回False
os.path.isabs(path) 如果path是絕對路徑,傳回True
os.path.isfile(path) 如果path是一個存在的檔案,傳回True。否則傳回False
os.path.isdir(path) 如果path是一個存在的目錄,則傳回True。否則傳回False
os.path.join(path1[, path2[, ...]]) 将多個路徑組合後傳回,第一個絕對路徑之前的參數将被忽略
os.path.getatime(path) 傳回path所指向的檔案或者目錄的最後存取時間
os.path.getmtime(path) 傳回path所指向的檔案或者目錄的最後修改時間
5:sys子產品
sys子產品用于提供對python解釋器相關的操作:
1 sys.argv 指令行參數List,第一個元素是程式本身路徑
2 sys.exit(n) 退出程式,正常退出時exit(0)
3 sys.version 擷取Python解釋程式的版本資訊
4 sys.maxint 最大的Int值
5 sys.path 傳回子產品的搜尋路徑,初始化時使用PYTHONPATH環境變量的值
6 sys.platform 傳回作業系統平台名稱
7 sys.stdout.write('please:')
8 val = sys.stdin.readline()[:-1]
練習題:
1:讀寫使用者的輸入,根據使用者輸入,建立一個相應的目錄
import sys,os
print(sys.argv)
os.mkdir(sys.argv[1])
在指令行下執行:
D:\Python\Python35-32>python e:/wwwroot/py
['e:/wwwroot/python/index.py', 'testdir']
執行完畢,在D:\Python\Python35-32目錄下就多了一個testdir的目錄
2:自己寫一個簡單的腳本,可以在任何路徑導入
3:進度條,帶百分比
1 import sys,time
2 for i in range(31):
3 sys.stdout.write('\r')
4 sys.stdout.write("%s%% |%s" % (int(i/30*100),int(i/30*100)*'*'))
5 sys.stdout.flush()
6 time.sleep(0.1)
如何添加sys.path路徑:
import sys
sys.path.append("D:")#這裡寫需要添加的路徑
for i in sys.path:
print(i)
6:shuntil
進階的 檔案、檔案夾、壓縮包 處理子產品
shutil.copyfileobj(fsrc, fdst[, length]):将檔案内容拷貝到另一個檔案中
1 import shutil
2
3 shutil.copyfileobj(open('old.xml','r'), open('new.xml', 'w'))
shutil.copyfile(src, dst):拷貝檔案
shutil.copyfile('f1.log', 'f2.log')
shutil.copymode(src, dst):僅拷貝權限。内容、組、使用者均不變
shutil.copymode('f1.log', 'f2.log')
shutil.copystat(src, dst):僅拷貝狀态的資訊,包括:mode bits, atime, mtime, flags
shutil.copystat('f1.log', 'f2.log')
shutil.copy(src, dst):拷貝檔案和權限
import shutil
shutil.copy('f1.log', 'f2.log')
shutil.copy2(src, dst):拷貝檔案和狀态資訊
import shutil
shutil.copy2('f1.log', 'f2.log')
shutil.ignore_patterns(*patterns)
shutil.copytree(src, dst, symlinks=False, ignore=None)
遞歸的去拷貝檔案夾
import shutil
shutil.copytree('folder1', 'folder2', ignore=shutil.ignore_patterns('*.pyc', 'tmp*'))
import shutil
shutil.copytree('f1', 'f2', symlinks=True, ignore=shutil.ignore_patterns('*.pyc', 'tmp*'))
shutil.rmtree(path[, ignore_errors[, onerror]])
遞歸的去删除檔案
import shutil
shutil.rmtree('folder1')
shutil.move(src, dst)
遞歸的去移動檔案,它類似mv指令,其實就是重命名。
import shutil
shutil.move('folder1', 'folder3')
shutil.make_archive(base_name, format,...)
建立壓縮包并傳回檔案路徑,例如:zip、tar
- base_name: 壓縮包的檔案名,也可以是壓縮包的路徑。隻是檔案名時,則儲存至目前目錄,否則儲存至指定路徑,
- 如:www =>儲存至目前路徑
- 如:/Users/wupeiqi/www =>儲存至/Users/wupeiqi/
- format: 壓縮包種類,“zip”, “tar”, “bztar”,“gztar”
- root_dir: 要壓縮的檔案夾路徑(預設目前目錄)
- owner: 使用者,預設目前使用者
- group: 組,預設目前組
- logger: 用于記錄日志,通常是logging.Logger對象
1 #将 /Users/wupeiqi/Downloads/test 下的檔案打包放置目前程式目錄
2 import shutil
3 ret = shutil.make_archive("wwwwwwwwww", 'gztar', root_dir='/Users/wupeiqi/Downloads/test')
4
5
6 #将 /Users/wupeiqi/Downloads/test 下的檔案打包放置 /Users/wupeiqi/目錄
7 import shutil
8 ret = shutil.make_archive("/Users/wupeiqi/wwwwwwwwww", 'gztar', root_dir='/Users/wupeiqi/Downloads/test')
shutil 對壓縮包的處理是調用 ZipFile 和 TarFile 兩個子產品來進行的,詳細:

1 import zipfile
2
3 # 壓縮
4 z = zipfile.ZipFile('laxi.zip', 'w')
5 z.write('a.log')
6 z.write('data.data')
7 z.close()
8
9 # 解壓
10 z = zipfile.ZipFile('laxi.zip', 'r')
11 z.extractall()
12 z.close()
13
14 zipfile解壓縮
ZIPfile解壓縮

1 import tarfile
2
3 # 壓縮
4 tar = tarfile.open('your.tar','w')
5 tar.add('/Users/wupeiqi/PycharmProjects/bbs2.log', arcname='bbs2.log')
6 tar.add('/Users/wupeiqi/PycharmProjects/cmdb.log', arcname='cmdb.log')
7 tar.close()
8
9 # 解壓
10 tar = tarfile.open('your.tar','r')
11 tar.extractall() # 可設定解壓位址
12 tar.close()
13
14 tarfile解壓縮
tarfile解壓縮
7:json & pickle 子產品
用于序列化的兩個子產品
- json,用于字元串 和 python資料類型間進行轉換
- pickle,用于python特有的類型 和 python的資料類型間進行轉換
Json子產品提供了四個功能:dumps、dump、loads、load
pickle子產品提供了四個功能:dumps、dump、loads、load
pickle子產品的dumps,loads示範:
假如現在有一個字典弄的資料,内容如下:
accounts = {
1000:{
'name':'poe',
'password':'123456',
'email':'[email protected]',
'balance':15000,
'phone':13888888888,
'back_acc':{'ICBC':62202,'CBC':52202,'ABC':42202}
},
1001:{
'name':'jet',
'password':'654321',
'email':'[email protected]',
'balance':150,
'phone':13888888888,
'back_acc':{'ICBC':62202}
}
}
那麼如何将這個字典型的資料持久化儲存到硬碟裡呢?由于檔案的寫入隻允許儲存字元串,是以一般的方法無法将該字典型資料儲存到硬碟裡,這裡就需要用到pickle子產品的dumps與loads功能

1 import pickle
2 accounts = {
3 1000:{
4 'name':'poe',
5 'password':'123456',
6 'email':'[email protected]',
7 'balance':15000,
8 'phone':13888888888,
9 'back_acc':{'ICBC':62202,'CBC':52202,'ABC':42202}
10 },
11 1001:{
12 'name':'jet',
13 'password':'654321',
14 'email':'[email protected]',
15 'balance':150,
16 'phone':13888888888,
17 'back_acc':{'ICBC':62202}
18 }
19 }
20 f = open('account.db','wb')
21 f.write(pickle.dumps(accounts))
22 f.close()
account.py
資料儲存後,那麼如果需要重寫,該怎麼辦呢?

1 import pickle
2 acc_file_name = "account.db"
3 account_file = open(acc_file_name,'rb')
4 # print(pickle.loads(account_file.read()))
5 account_dic = pickle.loads(account_file.read())
6 account_file.close()
7 account_dic[1000]['balance'] -= 500
8 f = open(acc_file_name,'wb')
9 f.write(pickle.dumps(account_dic))
10 f.close()
11 print(account_dic)
shopping.py
驗證資料是否寫入成功:

import pickle
f = open("account.db",'rb')
account_db = pickle.loads(f.read())
print(account_db)
check.py
1 import json
2 s = '{"key1":"value1","key2":"value2"}' # ==> 用json子產品将字元串轉化成其他資料類型,字元串裡出現引号必須用雙引号
3 ret = json.loads(s) # ==> loads 由字元串轉其他資料類型
4 print(ret,type(ret))
5
6 ret = json.load(open('ethan.txt','r')) # ==> 将文檔(内部是字元串格式)轉換成python的其他資料類型
7 print(ret,type(ret)) # ==> 文檔裡是字典樣式的字元串
8
9 l = '[11,22,3,56,75]'
10 result =json.loads(l)
11 print(result,type(result))
12 # 總結:
13 # json.loads()用于将形似字典、清單、元組的字元串,轉換成字典、清單、元組
14 # json.load() 用于将文檔(内容是形似字典、清單、元組的字元串)轉換成字典、清單、元組
15
16 di = {"key1":"value1","key2":"value2"}
17 ret = json.dumps(di) # ==> 将字典、清單、元組 轉換成字元串格式
18 print(ret,type(ret))
19
20 json.dump(di,open('ethan.txt','a+')) # ==> 将字典、元組、清單轉換成字元串格式并寫入文檔
21
22 import pickle
23
24 d = {'name':'ethan','age':28}
25 ret = pickle.dumps(d) # ==> pickle将字典、元組、清單轉換成二進制
26 print(ret,type(ret))
27
28 l = [11,22,3,45,54]
29 res = pickle.dumps(l)
30 print(res)
31
32 pickle.dump(d,open('ethan.txt','ab')) # ==> 将字典、元組、清單轉換成二進制寫入文檔
33
34 # 注意 dump load 不要一起運作,會報錯,一步一步來
35
36 f = open('ethan.txt','rb')
37 r = pickle.loads(f.read()) # ==> 将二進制轉換成字典、清單、元組
38 print(r)
11:configpaser子產品
configparser用于處理特定格式的檔案,其本質上是利用open來操作檔案。

1 # 注釋1
2 ; 注釋2
3
4 [section1] # 節點
5 k1 = v1 # 值
6 k2:v2 # 值
7
8 [section2] # 節點
9 k1 = v1 # 值
10
11 指定格式
指定格式
舉例:假如現在有一個ini的檔案,内容如下:
1 [poe]
2 age = 12
3 gender = 'female'
4 edu = 'daxue'
5 [jet]
6 age = 19
7 gender = 'male'
1:利用configparser子產品提供的功能,擷取所有節點
import configparser
con = configparser.ConfigParser()#建立對象
#con對象的read功能,打開檔案讀取檔案,放進記憶體
con.read("ini",encoding="utf-8")
#con對象的sections,内在中尋找所有的[xxx]節點
result = con.sections()
print(result)
#con對象的options功能,擷取指定[xxx]節點下的内容
ret = con.options("poe")
print(ret)
##########################################
['poe', 'jet']
['age', 'gender', 'edu']
2:擷取指定節點下所有的鍵值對
import configparser
con = configparser.ConfigParser()
con.read("ini",encoding="utf-8")
ret = con.items('poe')
print(ret)
##########################################
[('age', '12'), ('gender', "'female'"), ('edu', "'daxue'")]
3:擷取指定節點下指定key的值
import configparser
con = configparser.ConfigParser()
con.read("ini",encoding="utf-8")
ret = con.get("poe","age")
print(ret)
##########################################
12
4:檢查、删除、添加節點
1 import configparser
2 con = configparser.ConfigParser()
3 con.read("ini",encoding="utf-8")
4
5 # 檢查節點是否存在,存在傳回True,否則傳回False
6 has_sec = con.has_section("poe")
7 print(has_sec)
8
9 # 添加節點
10 con.add_section("andy")
11 con.write(open("ini","w"))
12
13 # 删除節點
14 con.remove_section("trim")
15 con.write(open("ini","w"))
5:檢查、删除、設定指定組内的鍵值對
1 import configparser
2 con = configparser.ConfigParser()
3 con.read("ini",encoding="utf-8")
4
5 # 檢查andy節點下是否存在hobby鍵
6 has_sec = con.has_option("andy","hobby")
7 print(has_sec)
8
9 # 删除
10 con.remove_option("andy","hobby")
11 con.write(open("ini","w"))
12
13 # 設定
14 con.set("andy","from","beijing")
15 con.write(open("ini","w"))
總結:
增:
- obj.add_section(塊節點名稱) 增加一個塊節點
- obj.set(塊節點名稱,鍵,值) 在指定的塊節點下增加鍵值
删:
- obj.remove_section(塊節點名稱) 删除指定塊節點(連同該塊節點下的所有鍵值都删除)
- obj.remove_option(塊節點名稱,該塊節點下的鍵名) 删除指定塊節點下指定鍵的鍵值對
改:
- obj.set(塊節點名稱,鍵,值)
查:
- obj.sections() 查詢所有的塊節點(且稱之為塊節點,如:上面檔案中的[poe],[jet]),傳回一個清單
- obj.options(塊節點名稱) 查詢指定塊節點下的所有鍵,傳回一個清單
- obj.items(塊節點名稱) 查詢指定塊節點下的所有鍵及值,傳回一個清單(每個鍵值對儲存為一個元組)
- obj.get(塊節點名稱,塊節點下的鍵) 查詢指定塊節點下,鍵所對就的值
- obj.has_section(塊節點名稱) 查詢塊節點是否存在
- obj.has_option(塊節點名稱,塊節點下的鍵) 查詢指定塊節點下的鍵是否存在
12:hashlib
用于加密相關的操作,代替了md5子產品和sha子產品,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法
import hashlib
# ######## md5 ########
hash = hashlib.md5()
# help(hash.update)
hash.update(bytes('admin', encoding='utf-8'))
print(hash.hexdigest())
print(hash.digest())
######## sha1 ########
hash = hashlib.sha1()
hash.update(bytes('admin', encoding='utf-8'))
print(hash.hexdigest())
# ######## sha256 ########
hash = hashlib.sha256()
hash.update(bytes('admin', encoding='utf-8'))
print(hash.hexdigest())
# ######## sha384 ########
hash = hashlib.sha384()
hash.update(bytes('admin', encoding='utf-8'))
print(hash.hexdigest())
# ######## sha512 ########
hash = hashlib.sha512()
hash.update(bytes('admin', encoding='utf-8'))
print(hash.hexdigest())
以上加密算法雖然依然非常厲害,但時候存在缺陷,即:通過撞庫可以反解。是以,有必要對加密算法中添加自定義key再來做加密。(推薦使用此方法)
import hashlib
# ######## md5 ########
hash = hashlib.md5(bytes('898oaFs09f',encoding="utf-8"))
hash.update(bytes('admin',encoding="utf-8"))
print(hash.hexdigest())
python内置還有一個 hmac 子產品,它内部對我們建立 key 和 内容 進行進一步的處理然後再加密
import hmac
h = hmac.new(bytes('898oaFs09f',encoding="utf-8"))
h.update(bytes('admin',encoding="utf-8"))
print(h.hexdigest())
基于加密的登入程式:

import hashlib
def md5(arg) :
p = hashlib.md5(bytes('admin',encoding='utf-8'))
p.update(bytes(arg,encoding='utf-8'))
return p.hexdigest()
def register(user,pwd) :
with open("db","a",encoding="utf-8") as f :
temp = user + "|" + md5(pwd)
f.write(temp)
def login(user,pwd):
with open('db','r',encoding="utf-8") as f :
for line in f:
u,p = line.strip().split("|")
if u == user and p == md5(pwd):
return True
return False
i = input("1:login 2:register")
if i == '2':
user = input('username : ')
pwd = input('password : ')
register(user,pwd)
elif i == '1':
user = input('username :')
pwd = input('password :')
if login(user,pwd) :
print('login success')
else:
print('login failed')
使用者登入
13:subprocess子產品
執行shell指令
call
執行指令,傳回狀态碼
ret = subprocess.call(["ls", "-l"], shell=False)
ret = subprocess.call("ls -l", shell=True)
check_call
執行指令,如果執行狀态碼是 0 ,則傳回0,否則抛異常
subprocess.check_call(["ls", "-l"])
subprocess.check_call("exit 1", shell=True)
check_output
執行指令,如果狀态碼是 0 ,則傳回執行結果,否則抛異常
subprocess.check_output(["echo", "Hello World!"])
subprocess.check_output("exit 1", shell=True)
subprocess.Popen(...)
用于執行複雜的系統指令
參數:
- args:shell指令,可以是字元串或者序列類型(如:list,元組)
- bufsize:指定緩沖。0 無緩沖,1 行緩沖,其他 緩沖區大小,負值 系統緩沖
- stdin, stdout, stderr:分别表示程式的标準輸入、輸出、錯誤句柄
- preexec_fn:隻在Unix平台下有效,用于指定一個可執行對象(callable object),它将在子程序運作之前被調用
- close_sfs:在windows平台下,如果close_fds被設定為True,則新建立的子程序将不會繼承父程序的輸入、輸出、錯誤管道。
- 是以不能将close_fds設定為True同時重定向子程序的标準輸入、輸出與錯誤(stdin, stdout, stderr)。
- shell:同上
- cwd:用于設定子程序的目前目錄
- env:用于指定子程序的環境變量。如果env = None,子程序的環境變量将從父程序中繼承。
- universal_newlines:不同系統的換行符不同,True -> 同意使用 \n
- startupinfo與createionflags隻在windows下有效
- 将被傳遞給底層的CreateProcess()函數,用于設定子程序的一些屬性,如:主視窗的外觀,程序的優先級等等
import subprocess
ret1 = subprocess.Popen(["mkdir","t1"])
ret2 = subprocess.Popen("mkdir t2", shell=True)
終端輸入的指令分為兩種:
- 輸入即可得到輸出,如:ifconfig
- 輸入進行某環境,依賴再輸入,如:python
import subprocess
obj = subprocess.Popen("mkdir t3", shell=True, cwd='/home/dev',)
import subprocess
obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
obj.stdin.write("print(1)\n")
obj.stdin.write("print(2)")
obj.stdin.close()
cmd_out = obj.stdout.read()
obj.stdout.close()
cmd_error = obj.stderr.read()
obj.stderr.close()
print(cmd_out)
print(cmd_error)
import subprocess
obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
obj.stdin.write("print(1)\n")
obj.stdin.write("print(2)")
out_error_list = obj.communicate()
print(out_error_list)
import subprocess
obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
out_error_list = obj.communicate('print("hello")')
print(out_error_list)
14:login子產品
用于便捷記錄日志且線程安全的子產品
1、單檔案日志
import logging
logging.basicConfig(filename='log.log',
format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S %p',
level=10)
logging.debug('debug')
logging.info('info')
logging.warning('warning')
logging.error('error')
logging.critical('critical')
logging.log(10,'log')
日志等級:
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
注:隻有【目前寫等級】大于【日志等級】時,日志檔案才被記錄。
日志記錄格式:
2、多檔案日志
對于上述記錄日志的功能,隻能将日志記錄在單檔案中,如果想要設定多個日志檔案,logging.basicConfig将無法完成,需要自定義檔案和日志操作對象。
# 定義檔案
file_1_1 = logging.FileHandler('l1_1.log', 'a', encoding='utf-8')
fmt = logging.Formatter(fmt="%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s")
file_1_1.setFormatter(fmt)
file_1_2 = logging.FileHandler('l1_2.log', 'a', encoding='utf-8')
fmt = logging.Formatter()
file_1_2.setFormatter(fmt)
# 定義日志
logger1 = logging.Logger('s1', level=logging.ERROR)
logger1.addHandler(file_1_1)
logger1.addHandler(file_1_2)
# 寫日志
logger1.critical('1111')
# 定義檔案
file_2_1 = logging.FileHandler('l2_1.log', 'a')
fmt = logging.Formatter()
file_2_1.setFormatter(fmt)
# 定義日志
logger2 = logging.Logger('s2', level=logging.INFO)
logger2.addHandler(file_2_1)
如上述建立的兩個日志對象
- 當使用【logger1】寫日志時,會将相應的内容寫入 l1_1.log 和 l1_2.log 檔案中
- 當使用【logger2】寫日志時,會将相應的内容寫入 l2_1.log 檔案中