恍恍惚惚,九月第一篇。
操作文件和目錄
Python中內(nèi)置的os模塊可以用來直接調(diào)用操作系統(tǒng)提供的接口函數(shù)钓猬。
importos
os.name
'nt'
說明:結(jié)果如果是nt, 說明系統(tǒng)是windows系統(tǒng)誊锭;如果是posix,說明系統(tǒng)是Linux校读、Unix或Mac OS X沼侣。
要獲取詳細(xì)的系統(tǒng)信息,可以調(diào)用unname()函數(shù):
os.uname()
unmae()函數(shù)在Windows上不提供歉秫,也就是說蛾洛,os模塊的某些函數(shù)是跟操作系統(tǒng)相關(guān)的。
環(huán)境變量
操作系統(tǒng)中定義的環(huán)境變量雁芙,全部保存在os.environ這個(gè)變量中雅潭,可以直接查看:
os.environ
要獲取某個(gè)環(huán)境變量的值,可以調(diào)用os.environ.get('key')
os.environ.get('PATH')
os.environ.get('x','default')
'default'
操作文件和目錄
操作文件和目錄的函數(shù)一部分放在os模塊中却特,一部分是放在os.path模塊中扶供,這一點(diǎn)要注意下。查看裂明、創(chuàng)建和刪除目錄可以這樣調(diào)用:
看當(dāng)前目錄的絕對路徑:
importos
os.path.abspath('.')
'C:\\Users\\Gaofuhai'
在某個(gè)目錄下創(chuàng)建一個(gè)新目錄椿浓,首先把新目錄的完整路徑表示出來
os.path.join('C:\\Users\\Gaofuhai','testdir')
'C:\\Users\\Gaofuhai\\testdir'
創(chuàng)建一個(gè)目錄
os.mkdir('C:\\Users\\Gaofuhai\\testdir')
刪除目錄
os.rmdir('C:\\Users\\Gaofuhai\\testdir')
注意:把兩個(gè)字符串合成一個(gè)時(shí),不要直接拼字符串闽晦,而要通過os.path.join()函數(shù)扳碍,這樣可以正確處理不同操作系統(tǒng)的路徑分隔符。
在Linux/Unix/Mac下仙蛉,os.path.join()返回這樣的字符串:
part-1/part-2
而在Windoes下回返回這樣的字符串:
part-1\part-2
同樣的道理笋敞,要拆分路徑時(shí),也不要直接去拆字符串荠瘪。而要通過os.path.split()函數(shù)夯巷,這樣可以把一個(gè)路徑分為兩個(gè)部分,后一部分總是最后級別的目錄名或文件名:
os.path.split('C:\\Users\\Gaofuhai\\testdir')
('C:\\Users\\Gaofuhai', 'testdir')
os.path.splittext()可以直接讓你得到文件擴(kuò)展名哀墓,很多時(shí)候非常方便:
os.path.splitext('C:\\Users\\Gaofuhai\\testdir\\file.text')
('C:\\Users\\Gaofuhai\\testdir\\file', '.text')
這些合并趁餐、拆分路徑的函數(shù)并不要求目錄和文件要真實(shí)存在,它們只對字符串進(jìn)行操作篮绰。
文件操作使用下面的函數(shù)后雷,假定當(dāng)前目錄下有一個(gè)test.txt文件:
對文件重命名
os.rename('text.txt','text.py')
刪除文件
os.remove('test.py')
注意:復(fù)制文件的函數(shù)不在os模塊中,原因是復(fù)制文件并非由操作系統(tǒng)提供的系統(tǒng)調(diào)用。理論上講臀突,我們通過上一節(jié)的讀寫文件可以完成文件復(fù)制勉抓,只是要多寫很多代碼。
幸運(yùn)的是shutil模塊提供了copyfile()的函數(shù)候学,你還可以在shutil模塊中找到很多實(shí)用的函數(shù)琳状,是os模塊的一種補(bǔ)充。
最后來看看如何用Python的特性來過濾文件:
比如:我們列出了當(dāng)前目錄下的所有目錄盒齿,只需要一行代碼:
[x for x in os.listdir('.') if os.path.isdir(x)]
'.anaconda', '.android', '.conda', '.ipynb_checkpoints', '.ipython', '.jupyter', '.matplotlib', '.PyCharmCE2018.2', '.vscode', '3D Objects', 'AppData', 'Application Data', 'Contacts', 'Cookies', 'Desktop', 'Documents', 'Downloads', 'Favorites', 'IntelGraphicsProfiles', 'Links', 'Local Settings', 'MicrosoftEdgeBackups', 'Music', 'My Documents', 'NetHood', 'OneDrive', 'Pictures', 'PrintHood', 'Recent', 'Saved Games', 'Searches', 'SendTo', 'Templates', 'Untitled Folder', 'Videos', 'wc', '「開始」菜單']
要列出所有的.py文件念逞,也只需要一行代碼:
[x for xin os.listdir('.') if os.path.isfile(x) and os.path.splitext(x)[1] =='.py']
注意:Python中os模塊封裝了操作系統(tǒng)的目錄和文件操作,但這些函數(shù)有的在os模塊中边翁,有些在os.path模塊中翎承。
序列化
在程序運(yùn)行過程中,所有的變量都是在內(nèi)存中符匾,可以隨時(shí)修改變量叨咖,但一旦程序結(jié)束,變量所占用的內(nèi)存就被操作系統(tǒng)全部回收啊胶。
序列化:把變量從內(nèi)存中變成可存儲(chǔ)或傳輸?shù)倪^程甸各,在Python中叫pickling,在其他語言中也被稱為serialization,marshalling,flattening等等焰坪。
序列化后就可以把序列化后的內(nèi)容寫入磁盤趣倾,或者通過網(wǎng)絡(luò)傳輸?shù)絼e的別的機(jī)器上。
反序列化:把變量內(nèi)容從序列化的對象重新讀到內(nèi)存里某饰,即unpicking.
python提供了pickle模塊來實(shí)現(xiàn)序列化儒恋。
首先,我們嘗試把一個(gè)對象序列化并寫入文件
import pickle
d = dict(name = 'Bob',age = 20,score = 88)
pickle.dumps(d)
pickle.dumps()方法把任意對象序列化成一個(gè)bytes黔漂,然后诫尽,就可以把這個(gè)bytes寫入文件,或者用另一個(gè)方法pickle.dump()直接把對象序列化后寫入一個(gè)file-like Object:
f =open('dump.text','wb')
pickle.dump(d,f)
f.close()
寫入的dump.txt文件炬守,是一堆亂七八糟的內(nèi)容牧嫉,這些都是Python保存的對象內(nèi)部信息。
當(dāng)我們要把對象從磁盤讀到內(nèi)存時(shí)减途,可以把內(nèi)容讀到一個(gè)bytes酣藻,然后用pickle.loads()方法反序列化出對象,也可以直接用pickle.loads()方法從一個(gè)file-like Object:
f =open('dump.text','rb')
pickle.load(f)
f.close()
d
{'name': 'Bob', 'age': 20, 'score': 88}
注意:這個(gè)變量和原來的變量是完全不相干的對象观蜗,它們只是內(nèi)容相同臊恋。
Pickle的問題和所有其他的編程特有的序列化問題一樣,就是它只能用于Python,并且可能不同版本的Python彼此都不兼容墓捻,因此,只能用Pickle保存那些不重要的數(shù)據(jù),不能成功地反序列化也沒關(guān)系砖第。
JSON
如果我們要在不同的編程語言之間傳遞對象撤卢,就必須把對象序列化為標(biāo)準(zhǔn)格式,比如XML梧兼,但更好的方法是序列化為JSON放吩,因?yàn)镴SON表示出來就是一個(gè)字符串,可以被所有語言讀取羽杰,也可以方便地存儲(chǔ)到磁盤或者通過網(wǎng)絡(luò)傳輸渡紫。JSON不僅是標(biāo)準(zhǔn)格式,并且比XML更快考赛,而且可以直接在Web頁面讀取惕澎,非常方便。
JSON表示的對象就是標(biāo)準(zhǔn)的JavaScript語言的對象颜骤,JSON和Python內(nèi)置的數(shù)據(jù)類型對應(yīng)如下:
Python內(nèi)置的json模塊提供了非常完善的Python對象到JSON格式的轉(zhuǎn)換唧喉。我們先看看如何把Python對象變成一個(gè)JSON:
import json
d = dict(name ='Bob',age = 20,score = 88)
json.dumps(d)
'{"name": "Bob", "age": 20, "score": 88}'
dump()方法返回一個(gè)str,內(nèi)容就是標(biāo)準(zhǔn)的JSON忍抽。類似的八孝,dump()方法可以直接把JSON寫入一個(gè)file-like Object。
要把JSON反序列化為Python對象鸠项,用loads()或者對應(yīng)的load()方法干跛,前者把JSON的字符串反序列化。后者從file-like Object中讀取字符串并反序列化:
json_str = '{"name":"Bob","age":20,"score":88}'
json.loads(json_str)
{'name': 'Bob', 'age': 20, 'score': 88}
由于JSON標(biāo)準(zhǔn)規(guī)定編碼是UTF-8,所以我們總能正確地在Python的str與JSON的字符串之間轉(zhuǎn)換祟绊。
JSON進(jìn)階
Python的dict對象可以直接序列化為JSON的{}驯鳖,不過,很多時(shí)候久免,我們更喜歡用class表示對象浅辙,比如定義Student類,然后序列化:
import json
classStudent(object):
????def__init__(self,name,age,score):
????????self.name = name
????????self.age = age
????????self.score = score
s =Student('Bob',20,88)
print(json.dump(s))
當(dāng)運(yùn)行上述代碼時(shí)阎姥,會(huì)出現(xiàn)錯(cuò)誤记舆,原因是Student對象不是一個(gè)可序列化為JSON的對象。
但dump()方法還提供了其他一大推的可選參數(shù)呼巴。https://docs.python.org/3/library/json.html#json.dumps
這些可選參數(shù)就是讓我們來定制JSON序列化泽腮。
前面的代碼之所以無法把Student類實(shí)例化為JSON,是因?yàn)槟J(rèn)情況下衣赶,dump()方法不知道如何將Student實(shí)例變?yōu)橐粋€(gè)JSON的{}對象诊赊。
可選參數(shù)default就是把任意一個(gè)對象變成一個(gè)可序列化為JSON的對象,我們只需要為Student專門寫一個(gè)轉(zhuǎn)換函數(shù)府瞄,再把函數(shù)傳進(jìn)去即可:
def student2dict(std):
????return{
????????'name'; std.name,
????????'age'; std.age,
????????'score'; std.score
????}
這樣碧磅,Student實(shí)例首先被student2dict()函數(shù)轉(zhuǎn)換成dict,然后再被順利序列化為JSON:
print(json.dump(s,default= student2dict))
不過,下次再遇到一個(gè)Teacher類的實(shí)例鲸郊,照樣無法序列化為JSON丰榴。我們可以偷個(gè)懶,把任意class的實(shí)例變?yōu)閐ict:
print(json.dump(s,default= lambda obj:obj._dict_))
因?yàn)橥ǔlass的實(shí)例都有一個(gè)__dict__屬性秆撮,它就是一個(gè)dict四濒,用來儲(chǔ)存實(shí)例變量。也有少數(shù)例外职辨,比如定義了__slots__的class盗蟆。
同樣的道理,如果我們要把JSON反序列化為一個(gè)Student對象實(shí)例舒裤,loads()方法首先轉(zhuǎn)換出一個(gè)dict對象喳资,然后,我們傳入的object_hook函數(shù)負(fù)責(zé)把dict轉(zhuǎn)換為Student實(shí)例惭每。
def dict2student(d):
????return Student(d['name'],d['age'],d['score'])
運(yùn)行結(jié)果:
json_str = '{"age":20,"score":88,"name":"Bob"}'
print(json.loads(json_str,object_hook = dict2student))
打印出的結(jié)果就是反序列化的Student實(shí)力對象骨饿。