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