引用、遞歸函數(shù)统舀、匿名函數(shù)匆骗、列表推導(dǎo)式、文件的讀寫誉简、with open()as file文件的相關(guān)操作shutil模塊和os模塊
1.引用
什么是引用碉就?
python中 值傳遞的一種方式,引用就是 容器 -- 物品之間? -- 對應(yīng)關(guān)系(可以類比c的指針)
在python中闷串,值是靠引用來傳遞來的瓮钥。
python中變量保存的不是數(shù)值 而是引用
id 查看一個變量的地址 (唯一標(biāo)識 就好比門牌號一樣)
我們可以用id()來判斷兩個變量是否為同一個值的引用。 我們可以將id值理解為那塊內(nèi)存的地址標(biāo)示。
之前為了更好的理解變量碉熄,咱們可以把a=100理解為變量a中存放了100桨武,事實上變量a存儲是100的引用(可理解為在內(nèi)存中的一個編號)
引用當(dāng)做實參
? 可變類型與不可變類型的變量分別作為函數(shù)參數(shù)時,會有什么不同嗎锈津?
? Python有沒有類似C語言中的指針傳參呢呀酸?
def test1(b): # 變量b一定是一個局部變量,就看它指向的是誰琼梆?可變還是不可變
b += b # += 是直接對b指向的空間進(jìn)行修改,而不是讓b指向一個新的
b = b+b # xx = xx+yyy 先把=號右邊的結(jié)果計算出來,然后讓b指向這個新的地方,不管原來b指向
? # 誰性誉, 現(xiàn)在b一定指向這個新的地方
總結(jié):
? Python中函數(shù)參數(shù)是引用傳遞(注意不是值傳遞)
? 對于不可變類型,因變量不能修改茎杂,所以運算不會影響到變量自身
? ? ? ? ? ■ b = b + b 和 b += b 都是屬于重新賦值
? 而對于可變類型來說错览,函數(shù)體中的運算有可能會更改傳入的參數(shù)變量
? ? ? ? ? ■ 可變的數(shù)據(jù)類型 b = b + b 重新賦值? (b += b 對原來的數(shù)據(jù)進(jìn)行修改)
2.遞歸函數(shù)
遞歸函數(shù): 其函數(shù)內(nèi)部調(diào)用其自己本身
如果一個函數(shù)在內(nèi)部調(diào)用的函數(shù)是自己本身的話,這個函數(shù)就是遞歸函數(shù)煌往。
在python中遞歸函數(shù)必須有一個停止遞歸調(diào)用的條件(因為調(diào)用函數(shù)的時候也需要消耗資源)? ? 如果遞歸函數(shù)不能停止 就會把計算機資源耗盡
為了理解: 在遞歸函數(shù)中 自己調(diào)用自己本身 (只是函數(shù)名相同 但是存在于不同的空間)
import sys
獲取遞歸次數(shù)
sys.getrecursionlimit()
設(shè)置遞歸次數(shù)n次
sys.setrecursionlimit(n)
3.匿名函數(shù)
用lambda關(guān)鍵詞能創(chuàng)建小型匿名函數(shù)倾哺。這種函數(shù)得名于省略了用def聲明函數(shù)的標(biāo)準(zhǔn)步驟。
Lambda函數(shù)能接收任何數(shù)量的參數(shù)但只能返回一個表達(dá)式的值
匿名函數(shù)不能直接調(diào)用print刽脖,因為lambda需要一個表達(dá)式
匿名函數(shù)(藏匿名字的函數(shù)):
? 01: 對函數(shù)的另一種表現(xiàn)形式
? ? ? ? ? ■ 無參數(shù)無返回值的函數(shù)
f = lambda :print("你好世界")
? ? ? ? ? ■ 無參數(shù)有返回值的函數(shù)
f = lambda :3.14
? ? ? ? ? ■ 有參數(shù)無返回值的函數(shù)
f = lambda name:print("你好%s" % name)
? ? ? ? ? ■ 有參數(shù)有返回值的函數(shù)
f = lambda a, b: a + b
? 02: 可以作為函數(shù)的參數(shù)使用
f = lambda a, b, c : a + b + c
def average3num(num1, num2, num3, my_func):
? ? # 求和
? ? ret = my_func(num1, num2, num3)
? ? # 返回
? ? return ret / 3
# 變量
aa = 10
bb = 20
cc = 30
result = average3num(aa, bb, cc, f)
print(result)
? 03: 自定義排序 list.sort
列表.sort(key=lambda 臨時變量名:臨時變量名[key])
4.列表推導(dǎo)式
所謂的列表推導(dǎo)式羞海,就是指的輕量級循環(huán)創(chuàng)建列表
? 01: 需求: 定義一個列表 保存1~100元素
list = [i for i in range(1, 101)]
? 02: 定義一個列表 保存10個元素 每個元素都為 "哈哈"
list = ["哈哈" for _ in range(10)]
? 03:定義一個列表 保存1~100直接的偶數(shù)
list = [i for i in range(1, 101) if i % 2 == 0]
? 04: [(0, 1), (0, 2), (0, 3), (1, 1), (1, 2), (1, 3)]
list = [(i, j) for i in range(2) for j in range(1, 4)]
? 05:寫出一段 Python 代碼實現(xiàn)分組一個 list 里面的元素,比如 [1,2,3,...100]變成 [[1,2,3],[4,5,6]....]? ? 切片技術(shù): 字符串 列表
a = [x for x in range(1,101)]
b = [a[x:x+3] for x in range(0,len(a),3)]
5.文件的讀寫
不同的文件 有不同的后綴名(代表是不同類型的文件)
文件存在的意義? 為了保存數(shù)據(jù)(持久化) -> 硬盤
變量存在的意義? 保存數(shù)據(jù) 臨時保存(程序運行中) -> 內(nèi)存
就是把一些存儲存放起來,可以讓程序下一次執(zhí)行的時候直接使用曲管,而不必重新制作一份扣猫,省時省力
open(file, mode='r', buffering=None, encoding=None, errors=None, newline=None, closefd=True):
file: 文件名 encoding: 編碼格式 errors: 表示如果按照utf-8的編碼格式進(jìn)行解碼時,可以在解碼不出來時用errors='ignore'忽略特殊字符翘地,保證程序不報錯
<1>打開文件
在python申尤,使用open函數(shù),可以打開一個已經(jīng)存在的文件衙耕,或者創(chuàng)建一個新文件
open(文件名昧穿,訪問模式)
訪問權(quán)限:r 只讀、w 只寫橙喘、a 追加
文件的打開
? 默認(rèn)情況下 使用r
如果文件存在 直接打開
如果文件不存在 將報錯
open("hm.txt", "r")
? 使用w
如果文件存在 直接打開
如果文件不存在 先創(chuàng)建 然后再打開
open("hm.txt", "w")
? 使用a
如果文件存在 直接打開
如果文件不存在 先創(chuàng)建 然后再打開
open("hm1.txt", "a")
訪問模式 說明
r 以只讀方式打開文件时鸵。文件的指針將會放在文件的開頭。這是默認(rèn)模式厅瞎。
w 打開一個文件只用于寫入饰潜。如果該文件已存在則將其覆蓋。如果該文件不存在和簸,創(chuàng)建新文件彭雾。
a 打開一個文件用于追加。如果該文件已存在锁保,文件指針將會放在文件的結(jié)尾薯酝。也就是說半沽,新的內(nèi)容將會被寫入到已有內(nèi)容之后。如果該文件不存在吴菠,創(chuàng)建新文件進(jìn)行寫入者填。
rb 以二進(jìn)制格式打開一個文件用于只讀。文件指針將會放在文件的開頭做葵。這是默認(rèn)模式占哟。
wb 以二進(jìn)制格式打開一個文件只用于寫入。如果該文件已存在則將其覆蓋酿矢。如果該文件不存在重挑,創(chuàng)建新文件。
ab 以二進(jìn)制格式打開一個文件用于追加棠涮。如果該文件已存在,文件指針將會放在文件的結(jié)尾刺覆。也就是說严肪,新的內(nèi)容將會被寫入到已有內(nèi)容之后。如果該文件不存在谦屑,創(chuàng)建新文件進(jìn)行寫入驳糯。
r+ 打開一個文件用于讀寫。文件指針將會放在文件的開頭氢橙。
w+ 打開一個文件用于讀寫酝枢。如果該文件已存在則將其覆蓋。如果該文件不存在悍手,創(chuàng)建新文件帘睦。
a+ 打開一個文件用于讀寫。如果該文件已存在坦康,文件指針將會放在文件的結(jié)尾竣付。文件打開時會是追加模式。如果該文件不存在滞欠,創(chuàng)建新文件用于讀寫古胆。
rb+ 以二進(jìn)制格式打開一個文件用于讀寫。文件指針將會放在文件的開頭筛璧。
wb+ 以二進(jìn)制格式打開一個文件用于讀寫逸绎。如果該文件已存在則將其覆蓋。如果該文件不存在夭谤,創(chuàng)建新文件棺牧。
ab+ 以二進(jìn)制格式打開一個文件用于追加。如果該文件已存在朗儒,文件指針將會放在文件的結(jié)尾陨帆。如果該文件不存在曲秉,創(chuàng)建新文件用于讀寫。
r+? 等同于 r+w疲牵,可不清空原內(nèi)容
w+ 等同于 = w+r
a+ 等同于 = a+r
<2>關(guān)閉文件
close( )
示例:f.close()
如果程序員沒有關(guān)閉文件 待程序退出后 系統(tǒng)會幫我們關(guān)閉
<3>寫數(shù)據(jù)(write)
使用write()可以完成向文件寫入數(shù)據(jù)
? 使用w默認(rèn)打開文件 每次打開先進(jìn)行清空數(shù)據(jù)
f = open("hm.txt", "w")
f.write("helloworld")
f.close()
? 使用a默認(rèn)打開文件承二,在原有的數(shù)據(jù)后面 進(jìn)行追加數(shù)據(jù)
f = open("hm.txt", "a")
f.write("haha")
f.close()
當(dāng)我們寫文件時,操作系統(tǒng)往往不會立刻把數(shù)據(jù)寫入磁盤纲爸,而是在緩沖區(qū)(buffer)亥鸠,空閑的時候再慢慢寫入。只有調(diào)用close()方法時识啦,操作系統(tǒng)才保證把沒有寫入的數(shù)據(jù)全部寫入磁盤负蚊。忘記調(diào)用close()的后果是數(shù)據(jù)可能只寫了一部分到磁盤,剩下的丟失了颓哮。所以家妆,還是用with語句來得保險:
with open('test.txt', 'w', encoding='utf-8') as f:
? ? f.write('Hello, world!')
<4>讀數(shù)據(jù)(read)
? ? ? ? ? ■ f.read([size]) #size為讀取的長度,以byte為單位冕茅,在rb(二進(jìn)制)模式下伤极,使用utf-8的編碼格式時,一個漢字占用三個字節(jié)姨伤,一個字母占用一個字節(jié)
? ? ? ? ? ■ f.readline([size]) #讀一行哨坪,如果定義了size,有可能返回的只是一行的一部分
? ? ? ? ? ■ f.readlines([size]) #把文件每一行作為一個list的一個成員乍楚,并返回這個list当编。其實它的內(nèi)部是通過循環(huán)調(diào)用readline()來實現(xiàn)的。如果提供size參數(shù)徒溪,size是表示讀取內(nèi)容的總長忿偷,也就是說可能只讀到文件的一部分。
? ? ? ? ? ■ f.write(str) #把str寫到文件中臊泌,write()并不會在str后加上一個換行符
? ? ? ? ? ■ f.writelines(seq) #把seq的內(nèi)容(元素是字符串的列表)全部寫到文件中(多行一次性寫入)牵舱。這個函數(shù)也只是忠實地寫入,不會在每行后面加上任何東西缺虐。
? ? ? ? ? ■ f.close() #關(guān)閉文件芜壁。python會在一個文件不用后自動關(guān)閉文件,不過這一功能沒有保證高氮,最好還是養(yǎng)成自己關(guān)閉的習(xí)慣慧妄。? 如果一個文件在關(guān)閉后還對其進(jìn)行操作會產(chǎn)生ValueError
? ? ? ? ? ■ f.seek(offset[,whence]) #將文件打操作標(biāo)記移到offset的位置。這個offset一般是相對于文件的開頭來計算的剪芍,一般為正數(shù)塞淹。但如果提供了whence參數(shù)就不一定了,whence可以為0表示從頭開始計算罪裹,1表示以當(dāng)前位置為原點計算饱普。2表示以文件末尾為原點進(jìn)行計算运挫。需要注意,如果文件以a或a+的模式打開套耕,每次進(jìn)行寫操作時谁帕,文件操作標(biāo)記會自動返回到文件末尾。
? ? ? ? ? ■ f.flush() #把緩沖區(qū)的內(nèi)容寫入硬盤
? ? ? ? ? ■ f.fileno() #返回一個長整型的"文件標(biāo)簽"
? ? ? ? ? ■ f.isatty() #文件是否是一個終端設(shè)備文件(unix系統(tǒng)中的)
? ? ? ? ? ■ f.tell() #返回文件操作標(biāo)記的當(dāng)前位置冯袍,以文件的開頭為原點
? ? ? ? ? ■ f.next() #返回下一行匈挖,并將文件操作標(biāo)記位移到下一行。把一個file用于for … in file這樣的語句時康愤,就是調(diào)用next()函數(shù)來實現(xiàn)遍歷的儡循。
? ? ? ? ? ■ f.truncate([size]) #把文件裁成規(guī)定的大小,默認(rèn)的是裁到當(dāng)前文件操作標(biāo)記的位置征冷。如果size比文件的大小還要大择膝,依據(jù)系統(tǒng)的不同可能是不改變文件,也可能是用0把文件補到相應(yīng)的大小检激,也可能是以一些隨機的內(nèi)容加上去肴捉。
print(f.encoding) #查看編碼格式
默認(rèn)情況下 windows 編碼格式為cp936 也就是GBK? ascii
在mac和烏班圖上編碼格式默認(rèn)就是utf-8格式
保存中文的時候 需要程序員指定編碼格式為utf-8
f = open("hm.txt", "w", encoding="utf-8")
f.write("中國")
f.close()
<5>二進(jìn)制讀寫數(shù)據(jù)(b)
rb 以二進(jìn)制方式讀取數(shù)據(jù)時:
文件訪問模式里面如果帶有b(binary二進(jìn)制)模式,不需要指定編碼格式呵扛,因為數(shù)據(jù)讀取出來或者寫入都需要進(jìn)行解碼和編碼
content = result.decode('utf-8', errors='ignore')
errors: 表示如果按照utf-8的編碼格式進(jìn)行解碼時,可以在解碼不出來時用errors='ignore'忽略特殊字符筐带,保證程序不報錯
讀取二進(jìn)制數(shù)據(jù)進(jìn)行解碼(以utf-8的格式進(jìn)行解碼)操作:
result = f.read()
content = result.decode('utf-8')
print(content)
wb 以二進(jìn)制方式寫入數(shù)據(jù)時:
把字符(以utf-8的格式進(jìn)行編碼)轉(zhuǎn)成二進(jìn)制再寫入
content = '你好'
content_data = content.encode('utf-8')
f.write(content_data)
或者:
f.write('a.txt', encode('utf-8'))
<6>在指定位置創(chuàng)建新文件
\:表示轉(zhuǎn)義字符今穿,兩個反斜杠表示一個真正的反斜杠字符
file_path = 'C:\\Users\\Administrator\\Desktop\\' + newFileName
# 打開新文件
newFile = open(file_path, 'wb')
6.文件的相關(guān)操作shutil模塊和os模塊
<1>導(dǎo)入os模塊
import os
? 文件、文件名重命名
os模塊中的rename()可以完成對文件或文件名的重命名操作
os.rename(需要修改的文件名, 新的文件名)
os.rename("畢業(yè)論文.txt", "畢業(yè)論文-最終版.txt")
? 刪除文件
os模塊中的remove()可以完成對文件的刪除操作
os.remove(待刪除的文件名)
os.remove("畢業(yè)論文.txt")
? 創(chuàng)建文件夾
os模塊中的mkdir()可以完成創(chuàng)建文件夾
os.mkdir(待創(chuàng)建的文件夾名)
os.mkdir("張三")
? 獲取當(dāng)前目錄
os模塊中的getcwd()可以獲取當(dāng)前目錄伦籍,返回一個字符串類型的路徑地址
os.getcwd()
path = os.getcwd()
print(path)
? 改變默認(rèn)目錄
os模塊中的chdir()可以改變默認(rèn)目錄
./ 相對路徑 == C:\北京黑馬金32期代碼\第九天的代碼 (當(dāng)前路徑)
./黑馬 == 黑馬 當(dāng)前路徑下的黑馬文件夾
../ 相對路徑 == C:\北京黑馬金32期代碼 (上一級)
C:\北京黑馬金32期代碼 絕對路徑(可以看到盤符)
os.chdir("../") 切換到上一級目錄
os.chdir("黑馬")或者os.chdir("./黑馬") 切換到當(dāng)前路徑下的黑馬文件夾
? 獲取目錄列表
os模塊中的listdir()可以獲取目錄列表蓝晒,返回一個目錄列表
os.listdir("./")
list = os.listdir("./")
print(list)
? 刪除文件夾
os模塊中的rmdir()可以刪除空文件夾
os.rmdir("文件夾名")
os.rmdir("黑馬")
? 擴展
判斷文件在當(dāng)前地址是否存在
isExists = os.path.exists(sourceFileName)
獲取文件的絕對路徑
my_path = os.path.abspath('文件名')
獲取絕對路徑的文件名
file_name = os.path.basename('絕對路徑')
獲取文件名及文件后綴
file_name, extension_name = os.path.splitext('文件名')
既改文件夾名又改文件名
os.renames('原文件夾名/原文件名', '新文件夾名/新文件名')
<2>導(dǎo)入shutil模塊
import shutil
刪除文件夾及里面的所有文件
shutil.rmtree('文件夾名')