-
閉包的特點(diǎn)是返回的函數(shù)還引用了外層函數(shù)的局部變量,所以,要正確使用閉包,就要確保引用的局部變量在函數(shù)返回后不能變。舉例如下:
#?希望一次返回3個函數(shù),分別計算1x1,2x2,3x3: def?count(): ????fs?=?[] ????for?i?in?range(1,?4): ????????def?f(): ?????????????return?i*i ????????fs.append(f) ????return?fs f1,?f2,?f3?=?count()
你可能認(rèn)為調(diào)用f1(),f2()和f3()結(jié)果應(yīng)該是1,4,9,但實(shí)際結(jié)果全部都是 9(請自己動手驗證)。
原因就是當(dāng)count()函數(shù)返回了3個函數(shù)時,這3個函數(shù)所引用的變量 i 的值已經(jīng)變成了3。由于f1、f2、f3并沒有被調(diào)用,所以,此時他們并未計算 i*i,當(dāng) f1 被調(diào)用時:
>>>?f1() 9?????#?因為f1現(xiàn)在才計算i*i,但現(xiàn)在i的值已經(jīng)變?yōu)?
因此,返回函數(shù)不要引用任何循環(huán)變量,或者后續(xù)會發(fā)生變化的變量。
查看全部 -
Python內(nèi)置的 sorted()函數(shù)可對list進(jìn)行排序:
>>>?sorted([36,?5,?12,?9,?21]) [5,?9,?12,?21,?36]
可以看到,sorted()函數(shù),默認(rèn)是由小到大排序列表的元素。
>>>?score?=?[('Alice',?72),?('Candy',?90),?('Bob',?62)] >>>?sorted(score) [('Alice',?72),?('Bob',?62),?('Candy',?90)]
當(dāng)list的每一個元素又是一個容器時,則會以第一個元素來排序,比如在score中,每個元素都是包含名字和成績的一個tuple,sorted()函數(shù)則按名字首字母進(jìn)行了排序并返回。
如果需要按照成績高低進(jìn)行排序,需要指定排序的字段是成績,sorted接受key參數(shù),用來指定排序的字段,key的值是一個函數(shù),接受待排序列表的元素作為參數(shù),并返回對應(yīng)需要排序的字段。因此,sorted()函數(shù)也是高階函數(shù)。
def?k(item): ????return?item[1]?#?==>?按成績排序,成績是第二個字段 sorted(score,?key=k)
得到結(jié)果:[('Bob', 62), ('Alice', 72), ('Candy', 90)] 。
如果需要倒序,指定reverse參數(shù)即可。sorted(score,?key=k,?reverse=True)
得到結(jié)果:[('Candy', 90), ('Alice', 72), ('Bob', 62)] 。
查看全部 -
filter()函數(shù)接收一個函數(shù) f 和一個list,這個函數(shù) f 的作用是對每個元素進(jìn)行判斷,返回 True或 False,filter()根據(jù)判斷結(jié)果自動過濾掉不符合條件的元素,并返回一個迭代器,可以迭代出所有符合條件的元素。
例如,要從一個list [1, 4, 6, 7, 9, 12, 17]中刪除偶數(shù),保留奇數(shù),首先,要編寫一個判斷奇數(shù)的函數(shù):def?is_odd(x): ????return?x?%?2?==?1
然后,利用filter()過濾掉偶數(shù):
for?item?in?filter(is_odd,?[1,?4,?6,?7,?9,?12,?17]): ????print(item)
結(jié)果:1,7,9,17。
查看全部 -
reduce()函數(shù)也是Python內(nèi)置的一個高階函數(shù)。reduce()函數(shù)接收的參數(shù)和 map() 類似,一個函數(shù) f,一個list,但行為和 map()不同,reduce()傳入的函數(shù) f 必須接收兩個參數(shù),reduce()對list的每個元素反復(fù)調(diào)用函數(shù)f,并返回最終結(jié)果值。
在python2中,reduce()函數(shù)和map()函數(shù)一樣,可以直接使用,但是在python3中,reduce()函數(shù)被收錄到functools包內(nèi),需要引入functools才可以使用。
def?f(x,?y): ????return?x?+?y
調(diào)用 reduce(f, [1, 3, 5, 7, 9]):
from?functools?import?reduce def?f(x,?y): ????return?x?+?y print(reduce(f,?[1,3,5,7,9]))?#?==>?25
reduce()還可以接收第3個可選參數(shù),作為計算的初始值。如果把初始值設(shè)為100,計算:
print(reduce(f,?[1,?3,?5,?7,?9],?100))?#?==>?125
結(jié)果將變?yōu)?25,因為第一輪計算是:
計算初始值和第一個元素:f(100, 1),結(jié)果為101。
查看全部 -
map()是 Python 內(nèi)置的高階函數(shù),它接收一個函數(shù) f?和一個 list,并通過把函數(shù) f依次作用在list的每個元素上,map()函數(shù)會返回一個迭代器,可以依次迭代得到原來list的元素被函數(shù)f處理后的結(jié)果。
>>>?map(f,?list)
例如,對于list [1, 2, 3, 4, 5, 6, 7, 8, 9]。
如果希望把list的每個元素都作平方,就可以利用map()函數(shù)。
我們定義需要傳入函數(shù)f(x)=x*x,就可以利用map()函數(shù)完成這個計算:def?f(x): ????return?x*x for?item?in?map(f,?[1,?2,?3,?4,?5,?6,?7,?8,?9]): ????print(item)
得到結(jié)果:
[1,?4,?9,?10,?25,?36,?49,?64,?81]
由于list包含的元素可以是任何類型,因此,map() 不僅僅可以處理只包含數(shù)值的 list,事實(shí)上它可以處理包含任意類型的 list,只要傳入的函數(shù)f可以處理這種數(shù)據(jù)類型。
查看全部 -
服務(wù)端建立需要四個步驟:新建socket、綁定IP和端口(bind)、監(jiān)聽連接(listen)、接受連接(accept)。
客戶端建立則簡單一些,僅需兩個步驟:新建socket、連接服務(wù)端(connect)。
當(dāng)網(wǎng)絡(luò)連接上以后,客戶端和服務(wù)端就可以進(jìn)行數(shù)據(jù)通信了,套接字通過send()函數(shù)發(fā)送數(shù)據(jù),通過recv()函數(shù)接收數(shù)據(jù)。
先看服務(wù)端的過程,新建一個server.py的文件:import?socket server?=?socket.socket()?#?1.?新建socket server.bind(('127.0.0.1',?8999))?#?2.?綁定IP和端口(其中127.0.0.1為本機(jī)回環(huán)IP) server.listen(5)?#?3.?監(jiān)聽連接 s,?addr?=?server.accept()?#?4.?接受連接 print('connect?addr:{}'.format(addr)) content?=s.recv(1024) print(str(content,?encoding='utf-8'))??#?接受來自客戶端的消息,并編碼打印出來 s.close()
如上,服務(wù)端就編寫完畢,接下來是編寫客戶端,新建一個client.py的文件:
import?socket client?=?socket.socket()?#?1.?新建socket client.connect(('127.0.0.1',?8999))?#?2.?連接服務(wù)端(注意,IP和端口要和服務(wù)端一致) client.send(bytes('Hello?World.?Hello?Socket',?encoding='utf-8'))?#?發(fā)送內(nèi)容,注意發(fā)送的是字節(jié)字符串。 client.close()
接著在一個終端先運(yùn)行服務(wù)端:
python?server.py
然后再在另外一個終端運(yùn)行客戶端:
python?client.py
在服務(wù)端的終端,將會輸出以下信息:
connect?addr:('127.0.0.1',?50382) b'Hello?World.?Hello?Socket'
查看全部 -
為了正確關(guān)閉文件,需要考慮各種異常情況,這是非常麻煩的一件事,Python提供with關(guān)鍵字,可以免除這類后顧之憂。
with關(guān)鍵字對資源進(jìn)行訪問的場合,會確保不管在使用過程中是否發(fā)生異常,都會執(zhí)行必要的“清理”的操作,釋放資源,比如文件使用后自動關(guān)閉等等。
with的使用方法如下:with?open('test.txt',?'r')?as?f: ????content?=?f.readlines() ????for?line?in?content: ????????print(line)
當(dāng)文件使用結(jié)束后,不需要顯式的調(diào)用f.close()關(guān)閉文件。
查看全部 -
Python提供文件追加內(nèi)容的打開模式,可以往文件尾部添加內(nèi)容,又不清空文件原有的內(nèi)容。
模式
描述
a
打開一個文件并追加內(nèi)容,會往文件尾部添加內(nèi)容
ab
以二進(jìn)制格式打開一個文件并追加內(nèi)容,會往文件尾部添加內(nèi)容
a+
打開一個文件并使用追加進(jìn)行讀寫
?
f?=?open('test.txt',?'a') f.write('Hello?Everyone\n') f.close()
使用a的打開方式打開文件,文件游標(biāo)默認(rèn)是在文件的尾部,因此,可以便捷的往文件尾部添加內(nèi)容,除此以外,文件對象還提供seek()方法,可以移動文件的游標(biāo)位置,它接受一個參數(shù),表示文件的位置,0:文件首部,1:當(dāng)前位置,2:文件尾部,通過seek()可以把文件游標(biāo)移動到文件首部但不刪除文件的內(nèi)容。
f?=?open('test.txt',?'a+') content?=?f.readlines() print(content)?#?==>?[] f.seek(0) content?=?f.readlines() print(content)?#?==>?['Hello?World\n',?'Hello?Python\n',?'Hello?Imooc\n']
第一次print(content)的時候,由于文件游標(biāo)在文件的尾部,所以readlines()讀取不到任何數(shù)據(jù),打印了空的結(jié)果,第二次print(content)的時候,由于通過seek(0),文件游標(biāo)移動到了文件的首部,因此readlines()就返回了文件所有的內(nèi)容。
查看全部 -
?字符串反轉(zhuǎn)可以使用切片實(shí)現(xiàn): reverse = str_[::-1]
3. 換行符是'\n',字符串反轉(zhuǎn)的時候,換行符也會翻轉(zhuǎn)
查看全部 -
f?=?open('test.txt',?'w')
寫入若干字符
文件對象提供write方法向文件內(nèi)寫入若干字符,它接受一個字符串參數(shù),表示需要寫入的字符串。
f?=?open('test.txt',?'w') f.write('Hello?World\n') f.close()
寫入若干行
文件對象提供writelines()方法向文件內(nèi)容寫入多行數(shù)據(jù),它接受一個列表,表示需要寫入的字符串列表。
lines?=?['Hello?World\n',?'Hello?Python\n',?'Hello?Imooc\n'] f?=?open('test.txt',?'w') f.writelines(lines) f.close()
查看全部 -
讀取若干字符
文件對象提供read()方法,可以讀取文件中的若干個字符,它提供一個參數(shù)size,可以指定讀取字符的數(shù)量。
s?=?f.read(5) print(s)?#?==>?Hello
當(dāng)read()之后,訪問文件的游標(biāo)就會移動到第六個字符前面,此時,繼續(xù)read,將得到Hello后面的結(jié)果。
s?=?f.read(6) print(s)?#?==>?'?World'
讀取一行
文件對象提供readline()方法,和read()方法類似,可以讀取文件中的若干個字符,它也提供一個參數(shù)size,可以指定讀取字符的數(shù)量,不過和read()方法不同的是,readline()方法遇到一行結(jié)束的時候,就會返回。
f.close() f?=?open('test.txt',?'r')?#?重新打開文件 s?=?f.readline(20) print(s)??#?==>?'Hello?World.\n'
可以看到,打印的內(nèi)容并沒有20個字符,readline最多返回一行的所有字符。
讀取多行
文件對象提供readlines()方法,可以讀取多行字符,返回一個列表。它提供一個hint參數(shù),表示指定讀取的行數(shù),沒有指定則默認(rèn)以列表的形式返回文件所有的字符串。
f.close() f.open('test.txt',?'r') s?=?f.readlines() print(s)?#?==>?['Hello?World.\n',?'Hello?Python.\n',?'Hello?Imooc.\n']
查看全部 -
除了文本以外,還有大量的非文本文件,比如圖片、壓縮文件、視頻文件、音樂文件等等,這種文件統(tǒng)稱為二進(jìn)制文件,在Python中打開二進(jìn)制文件,需要不同的打開模式。
b
二進(jìn)制模式,打開二進(jìn)制文件
wb
以二進(jìn)制格式只寫模式打開一個文件,會清除原有的內(nèi)容
ab
以二進(jìn)制格式打開一個文件并追加內(nèi)容,會往文件尾部添加內(nèi)容
rb
以二進(jìn)制格式只讀模式打開一個文件
f?=?open('test.jpg',?'rb') f.close()
查看全部 -
常用的打開模式如下:
模式
描述
t
文本模式(默認(rèn))
x
寫模式,新建一個文件
b
二進(jìn)制模式,打開二進(jìn)制文件
+
更新一個文件(可讀可寫)
r
以只讀模式打開一個文件
rb
以二進(jìn)制格式只讀模式打開一個文件
w
打開一個文件進(jìn)行寫入,如果文件內(nèi)容已存在,會清除原有的內(nèi)容
wb
以二進(jìn)制格式只寫模式打開一個文件,會清除原有的內(nèi)容
a
打開一個文件并追加內(nèi)容,會往文件尾部添加內(nèi)容
ab
以二進(jìn)制格式打開一個文件并追加內(nèi)容,會往文件尾部添加內(nèi)容
w+
打開一個文件進(jìn)行讀寫,如果文件內(nèi)容已存在,會清除原有的內(nèi)容
a+
打開一個文件并使用追加進(jìn)行讀寫
注意,為了安全操作文件,文件使用完畢后,需要使用close()函數(shù)正確關(guān)閉。
在當(dāng)前目錄下新建一個test.txt文件,并新建一個main.py,此時文件目錄如下:|--?test.txt +--?main.py
?
f?=?open('test.txt',?'r')?#?打開test.txt文件 type(f)?#?打印f的類型(<class?'_io.TextIOWrapper'>) f.close()?#?關(guān)閉文件
查看全部 -
縮進(jìn)錯了就完蛋了
查看全部 -
如果需要導(dǎo)入自定義模塊,則需要了解Python導(dǎo)入模塊搜索的路徑。
通過sys模塊,可以知道導(dǎo)入模塊的路徑。>>>?import?sys >>>?sys.path ['',?'/data/miniconda3/lib/python3.8',?'/data/miniconda3/lib/python3.8/site-packages']
它返回的是一個列表,表示的是在搜索Python模塊時,會搜索的路徑,在示例中,返回了四個路徑。我們分析一些關(guān)鍵路徑:
第一個路徑是'',它是一個空字符串,表達(dá)的是當(dāng)前路徑的意思。
第二個路徑是/data/miniconda3/lib/python3.8,它是Python默認(rèn)模塊的存放的路徑,在這個路徑下,可以發(fā)現(xiàn)有os、sys等模塊的代碼。
第三個路徑是/data/miniconda3/lib/python3.8/site-packages,它是第三方模塊代碼的存放路徑,在這個路徑下,存放的是需要安裝的第三方模塊。那如何使用我們前面定義的tools.py模塊呢?
我們在tools.py同級目錄,創(chuàng)建main.py文件:#?main.py import?tools?#?導(dǎo)入模塊 tools.say_hello()?#?調(diào)用模塊里面的say_hello()函數(shù) tools.say_goodbye()?#?調(diào)用模塊里面的say_goodbye()函數(shù)
就可以運(yùn)行了。
查看全部
舉報