本文為TesterHome社區(qū)同學(xué)耿曉分享的Python基礎(chǔ)系列文章:作者的話:
再梳理一遍Python系列知識(shí)點(diǎn),夯實(shí)基礎(chǔ),,無他,,唯手熟爾!
Python系列總結(jié)都是我自己平時(shí)的學(xué)習(xí)筆記,,如果有不正確的地方,,希望各位佬兒哥指正糾偏~
測試基礎(chǔ)-Python篇 基礎(chǔ)①
變量名命名規(guī)則 - 遵循PEP8原則
普通變量:max_value
全局變量:MAX_VALUE
內(nèi)部變量:_local_var
和關(guān)鍵字重名:class_
函數(shù)名:bar_function
類名:FooClass
布爾類型的變量名用 is,has 這類詞語前綴
is_superuser
has_errors
allow_empty
釋義為數(shù)字的單詞
port
age
radius
以_id 為結(jié)尾的單詞
user_id
port_id
以 length/count 開頭或結(jié)尾的詞
length_of_username
max_length
users_count
注:不要用名詞的復(fù)數(shù)形式來作為 int 類型的變量名,因?yàn)槊~的負(fù)數(shù)形式更像是一個(gè)容器,。建議使用 number_of_apples 或 trips_count,;
超短命名
數(shù)組索引三劍客 i,、j、k
某個(gè)整數(shù) n
某個(gè)字符串 s
某個(gè)異常 e
文件對(duì)象 fp
變量注解
在Python3.5之后,,可以使用類型注解功能來注明變量類型,,在變量后添加類型,并用冒號(hào)隔開,;
def repeat_message(message: str, count: int) -> str:
return message * count
算術(shù)運(yùn)算符
不同類型變量之間的計(jì)算
獲取輸入的信息-input
input 輸入的數(shù)據(jù)類型都是字符串類型
格式化輸出
%s --字符串
%d --有符號(hào)十進(jìn)制整數(shù),,%06d 表示輸出的整數(shù)顯示位數(shù),不足的地方使用 0 補(bǔ)全
%f --浮點(diǎn)數(shù),,%.2f 表示小數(shù)點(diǎn)后只顯示兩位,,會(huì)四舍五入
%% --輸出%
vb1 = 'Tom'print('hello %s' % vb1)vb2 = 5print('有符號(hào)十進(jìn)制整數(shù):%d' % vb2)print('輸出顯示位數(shù)的整數(shù):%06d' % vb2)vb3 = 3.1415926print('保留兩位小數(shù):%.2f' % vb3)print('保留三位小數(shù):%.3f' % vb3)vb4 = 80print('正確率為:%d%%' % vb4)--------------------------------------------------------------------hello Tom有符號(hào)十進(jìn)制整數(shù):5輸出顯示位數(shù)的整數(shù):000005保留兩位小數(shù):3.14保留三位小數(shù):3.142正確率為:80%
邏輯運(yùn)算
and:
條件1 and 條件2
or:
條件1 or 條件2
not:(取反)
not 條件
a = 10b = 20c = 10if c == a and c == b:print('right')else:print('error')-------------------------------error
a = 10b = 20c = 10if c == a or c == b:print('right')else:print('error')-------------------------------right
循環(huán)-while
初始條件設(shè)置 -- 通常是重復(fù)執(zhí)行的 計(jì)數(shù)器
while 條件 1:
條件滿足時(shí),做的事情 1
條件滿足時(shí),,做的事情 2
條件滿足時(shí),,做的事情 3
……
while 條件 2:
條件滿足時(shí),做的事情 1
條件滿足時(shí),,做的事情 2
條件滿足時(shí),,做的事情 3
……
處理?xiàng)l件 2
處理?xiàng)l件 1
print 函數(shù)增強(qiáng)
在默認(rèn)情況下,print 函數(shù)輸出內(nèi)容之后,,會(huì)自動(dòng)在內(nèi)容末尾增加換行,;
如果不希望末尾增加換行,可以在 peint 函數(shù)輸出內(nèi)容的后面增加,end=''
其中''中間可以指定 print 函數(shù)輸出內(nèi)容之后,,繼續(xù)希望現(xiàn)實(shí)的內(nèi)容,;
語法格式如下:
print('*',end='')
轉(zhuǎn)義字符
列表
列表通過索引取值,列表索引從0開始,,且不能超過范圍,;
len(列表)--獲取列表的長度
列表.count(數(shù)據(jù))--數(shù)據(jù)在列表中出現(xiàn)的次數(shù)
列表.index(數(shù)據(jù))--獲取數(shù)據(jù)第一次出現(xiàn)的索引
del 列表 [索引]--刪除指定索引的數(shù)據(jù)
列表.remove[數(shù)據(jù)]--刪除第一個(gè)出現(xiàn)的指定數(shù)據(jù)
列表.pop--刪除末尾數(shù)據(jù)
列表.pop(索引)--刪除指定索引的數(shù)據(jù)
列表.insert(索引,數(shù)據(jù))--在指定位置插入數(shù)據(jù)
列表.append(數(shù)據(jù))--在末尾追加數(shù)據(jù)
列表.extend(列表 2)--將列表2的數(shù)據(jù)追加到列表1
列表.sort()--升序排序
列表.sort(reverse=True)--降序排序
列表.reverse() 反轉(zhuǎn)/逆序
元祖
Tuple(元組)與列表類似,不同之處在于元組的 元素不能修改,;
創(chuàng)建空元組:info_tuple = ()
元組中只包含一個(gè)元素時(shí),,需要在元素后面添加逗號(hào):info_tuple = (50, )
len(元組)--獲取元組的長度 n+1;
元組.count(數(shù)據(jù))--數(shù)據(jù)在元組中出現(xiàn)的次數(shù),;
元組 [索引]--從元祖中取值,;
元組.index(數(shù)據(jù))--獲取數(shù)據(jù)第一次出現(xiàn)的索引,。
元組和列表之間的轉(zhuǎn)換
字典
Python3.6 之后的字典是有序的,如果解釋器版本沒有那么新,,也可以使用 collections 模塊里的 OrderedDict 方法保證字典的有序性,。
OrderedDict 與新版字典在比較上面的區(qū)別:在對(duì)比兩個(gè)內(nèi)容相同但順序不同的字典時(shí),新版字典會(huì)返回 True,,OrderedDict 則會(huì)返回 False,。
from collections import OrderedDict
d = OrderedDict()
d['one'] = 1
d['two'] = 2
print(d)————————————————————
OrderedDict([('one', 1), ('two', 2)])
鍵必須是唯一的;
值可以取任何數(shù)據(jù)類型,,但鍵只能使用字符串,、數(shù)字或元組;
字典.keys()--所有 key 列表,;
字典.values()--所有 value 列表,;
字典.items()--所有(key,value)元組列表,;
字典 [key]--可以從字典中取值,,key 不存在會(huì)報(bào)錯(cuò);
1.返回的數(shù)據(jù)類型類似列表,,但不是真正意義的列表,,沒有 append() 方法;
2.但是可以用于 for 循環(huán);
3.可以用 list() 方轉(zhuǎn)換成真正的列表;
字典.get(key)--可以從字典中取值,key 不存在不會(huì)報(bào)錯(cuò),;
del 字典 [key]--刪除指定鍵值對(duì),,key 不存在會(huì)報(bào)錯(cuò),;
字典.pop(key)--刪除指定鍵值對(duì),,并且返回刪除鍵對(duì)應(yīng)的值,key 不存在會(huì)報(bào)錯(cuò),;
字典.pop(key, default=msg)--刪除指定鍵值對(duì),,并且返回刪除鍵對(duì)應(yīng)的值,key 不存在不會(huì)報(bào)錯(cuò),,會(huì)返回 msg,;
字典 popitem() 方法返回并刪除字典中的最后一對(duì)鍵和值。
字典.clear()--清空字典,;
字典 [key] = value
如果 key 存在,,修改數(shù)據(jù)
如果 key 不存在,新建鍵值對(duì)
字典.setdefault(key,value)
如果 key 存在,,不會(huì)修改數(shù)據(jù)
如果 key 不存在,,新建鍵值對(duì)
字典.update(字典2)--將字典2的數(shù)據(jù)合并到字典1,如果字典2中有和字典 1 重復(fù)的鍵值對(duì),,則替換字典 1 中的鍵值對(duì),;
生成字典的方法:d = dict.fromkeys(['name','age','code'],0) #0 為默認(rèn)值
字符串
拼接多個(gè)字符串,,使用 str.join 和 +=同樣好用;
len(字符串)--獲取字符串的長度,;
字符串.count(字符串)--小字符串在大字符串中出現(xiàn)的次數(shù),;
字符串 [索引]--從字符串中取出單個(gè)字符;
字符串.index(字符串)--獲得小字符串第一次出現(xiàn)的索引,;
string.istitle() | 如果 string 是標(biāo)題化的 (每個(gè)單詞的首字母大寫) 則返回 True,;
string.startswith(str) | 檢查字符串是否是以 str 開頭,是則返回 True,;
string.endswith(str) | 檢查字符串是否是以 str 結(jié)束,,是則返回 True;
string.find(str, start=0, end=len(string)) | 檢測 str 是否包含在 string 中,,如果 start 和 end 指定范圍,,則檢查是否包含在指定范圍內(nèi),如果是返回開始的索引值,,否則返回 -1
,;
string.index(str, start=0, end=len(string)) | 跟 find() 方法類似,不過如果 str 不在 string 會(huì)報(bào)錯(cuò),;
string.replace(old_str, new_str, num=string.count(old)) | 把 string 中的 old_str 替換成 new_str,,如果 num 指定,則替換不超過 num 次,;
string.capitalize() | 把字符串的第一個(gè)字符大寫,;
string.title() | 把字符串的每個(gè)單詞首字母大寫;
string.lower() | 轉(zhuǎn)換 string 中所有大寫字符為小寫,;
string.upper() | 轉(zhuǎn)換 string 中的小寫字母為大寫,;
string.swapcase() | 翻轉(zhuǎn) string 中的大小寫;
字符串 - 切片
切片方法適用于字符串,、列表,、元組;
字符串 [開始索引:結(jié)束索引:步長],;
切片:正反向索引(正:從 0 開始,,反:從-1 開始)
切片索引:[startstep]
start:開始截取的位置,包含在截取內(nèi)容內(nèi)
end:結(jié)束截取的位置,,結(jié)束截取的位置并不包含
step:截取的步長,,默認(rèn)值為 1
step:為正,表示從左到右進(jìn)行截取,,start 必須在 end 之前(從左開始算前,,下標(biāo)必須從左到右)
step:為負(fù),表示從右到左進(jìn)行截取,,start 必須在 end 之前(從右開始算前,,下標(biāo)必須從右到左)
s = 'hello,world'
print(s[:]) # 取全部
print(s[1:]) # 從第 2 位取到最后
print(s[:-1]) # 從開始取到倒數(shù)第二位
print(s[::2]) # 步長為 2
print(s[::-1]) # 反序
指定的區(qū)間屬于左閉右開型 [開始索引, 結(jié)束索引) => 開始索引 >= 范圍 < 結(jié)束索引
從 起始位開始,,到 結(jié)束位的前一位 結(jié)束(不包含結(jié)束位本身)
從頭開始,開始索引 數(shù)字可以省略,,冒號(hào)不能省略
到末尾結(jié)束,,結(jié)束索引 數(shù)字可以省略,冒號(hào)不能省略
步長默認(rèn)為 1,,如果連續(xù)切片,,數(shù)字和冒號(hào)都可以省略
索引的順序和倒序:
在 Python 中不僅支持 順序索引,同時(shí)還支持 倒序索引
所謂倒序索引就是 從右向左 計(jì)算索引
最右邊的索引值是 -1,,依次遞減
字符串格式化
# 將username靠右對(duì)齊,,左側(cè)補(bǔ)空格一共到20位username = 'Lili'print(f'{username:>20}')-------------------------------------
Lili
username = 'Lily'sore = 10print('{0}:{0}的成績是{1}'.format(username, sore))
集合
集合是一個(gè)無序的可變?nèi)萜黝愋停畲蟮奶攸c(diǎn)就是成員不能重復(fù)
要初始化一個(gè)空集合只能調(diào)用 set() 方法,,因?yàn)閧}表示的是一個(gè)空字典,,而不是一個(gè)空集合
集合也有自己的推導(dǎo)式-nums = {n for n in range(10) if n % 2 == 0}
集合是可變類型,可以通過.add() 追加元素
可以使用 update 方法可以將一個(gè)可迭代元素更新到集合中
s1 = set([1,2,3])s2 = set([2,3,4])s1.update(s2)s1.update('hello')print(s1)------------------------{1, 2, 3, 4, 'o', 'h', 'e', 'l'}
使用.remove() 可以刪除集合中的元素,,但元素不存在會(huì)報(bào)錯(cuò)-KeyError:
使用.discard() 可以刪除集合中的元素,,元素不存在也不會(huì)報(bào)錯(cuò)
集合的元素不可以修改,只能先刪再加
我們可以使用 in 判斷某個(gè)元素是否在某個(gè)集合中,,不能在集合中取值,,只能使用 for 循環(huán)遍歷集合中的元素
集合只能存放可哈希對(duì)象
s1 = set([1,2,3])s1.add([1])-----------------------TypeError: unhashable type: 'list'
集合的運(yùn)算
集合支持集合運(yùn)算,比如交集,、并集,、差集。所有的操作都可以用兩種方式:方法和運(yùn)算符,;
fruits_1 = {'apple','orange','pineapple'}fruits_2 = {'tomato','orange','grapes','mango'}print(fruits_1 & fruits_2)-----------------------------{'orange'}
fruits_1 = {'apple','orange','pineapple'}fruits_2 = {'tomato','orange','grapes','mango'}print(fruits_1 | fruits_2)----------------------------------------------------------{'tomato', 'pineapple', 'orange', 'apple', 'grapes', 'mango'}
fruits_1 = {'apple','orange','pineapple'}fruits_2 = {'tomato','orange','grapes','mango'}print(fruits_1 - fruits_2)------------------------------------{'apple', 'pineapple'}
fruits_1 = {'apple','orange','pineapple'}fruits_2 = {'tomato','orange','grapes','mango'}print(fruits_1.symmetric_difference(fruits_2)){'apple', 'mango', 'tomato', 'pineapple', 'grapes'}
fruits_1 = {'apple','orange','pineapple'}fruits_2 = {'apple','orange','pineapple','water'}print(fruits_1.issubset(fruits_2))print(fruits_2.issubset(fruits_1))--------------------------------------------------TrueFalse
Python 循環(huán)結(jié)構(gòu)
什么時(shí)候用 for:當(dāng)循環(huán)次數(shù)是一定的,,或者是循環(huán)對(duì)象是一定的,比如說在一個(gè)固定的字符串或列表中進(jìn)行循環(huán),,那么最好使用 for
什么時(shí)候用 while:當(dāng)循環(huán)次數(shù)不是一定的,,只是滿足某個(gè)條件時(shí)才進(jìn)行循環(huán),,那么最好使用 while
沒有 do…while…循環(huán)
循環(huán)里面加 else:當(dāng)循環(huán)執(zhí)行完畢時(shí),,else 才會(huì)執(zhí)行;如果循環(huán)在中間退出,,則 else 不會(huì)運(yùn)行
break&continue:不管是 break 還是 continue 都只作用于當(dāng)前循環(huán)
匿名函數(shù)-lambda
lambda 關(guān)鍵字能夠幫我們創(chuàng)建小型的匿名函數(shù):
lambda x:express
lambda 返回的是該匿名函數(shù)的指針
func = lambda x,y:x*y
print(func(2,3))
類
類定義
類方法
實(shí)例方法
1,、只能通過對(duì)象 (實(shí)例) 調(diào)用的方法
2,、實(shí)例方法在定義時(shí)總是以 self 作為第一個(gè)參數(shù)
3、實(shí)例方法在調(diào)用時(shí)不需要傳入 self,,這個(gè)實(shí)例本身會(huì)自動(dòng)傳到方法中作為 self
初始化方法 (init())
1.不需要顯式調(diào)用,,在初始化對(duì)象時(shí)會(huì)有 python 自動(dòng)調(diào)用
2.初始化方法一般只在定義對(duì)象屬性的時(shí)候才會(huì)定義
類方法
1,、可以直接通過類名調(diào)用的方法,也可以通過實(shí)例調(diào)用
2,、類方法必須通過@classmethod裝飾器進(jìn)行裝飾
3,、所有的類方法第一個(gè)參數(shù)必須是 cls
4、類方法不能訪問實(shí)例屬性,,只能訪問類屬性
屬性方法
使用場景:屬性方法對(duì)應(yīng)的屬性的值無法直接確定,,要通過一系列的操作才能得到這個(gè)值,而且用戶不關(guān)心這個(gè)操作過程,,只想得到這個(gè)值,。
定義:當(dāng)成屬性使用的方法,調(diào)用屬性方法時(shí)不需要加 ()
靜態(tài)方法
1,、通過@staticmethod裝飾器來進(jìn)行裝飾的方法
2,、靜態(tài)方法既不能訪問實(shí)例屬性,也不能訪問類屬性
3,、可以通過類名直接調(diào)用,,也可以通過對(duì)象調(diào)用
類的三大特征
封裝
暴露接口,隱藏細(xì)節(jié)
繼承
1.子類通過繼承直接獲得父類的全部屬性和方法,,實(shí)現(xiàn)代碼復(fù)用
2.初始化的幾種情況:
2.1 當(dāng)子類中沒有定義init() 方法,,則初始化子類時(shí)將默認(rèn)使用父類的初始化方法,并傳入對(duì)應(yīng)的參數(shù)
2.2 當(dāng)子類定義了自己的初始化方法,,但沒有調(diào)用父類的初始化方法,,則父類中的相關(guān)屬性不會(huì)被初始化
2.3 若在子類中重新定義了 init 方法,若仍要繼承父類的屬性,,則需要顯示調(diào)用父類的 init 方法:super().init()
多態(tài)
類的反射
反射原理
通過字符串的形式在運(yùn)行時(shí)動(dòng)態(tài)修改程序的變量,、方法及屬性,所有的修改都在內(nèi)存中進(jìn)行,,所以他并不會(huì)實(shí)際修改代碼,,主要目的就是提高代碼在運(yùn)行時(shí)的靈活性;
反射相關(guān)的方法
hasattr 輸入一個(gè)字符串,,判斷對(duì)象有沒有這個(gè)方法或?qū)傩裕?br>getattr 獲取對(duì)象屬性值或方法的引用,,如果是方法,則返回方法的引用,,如果是屬性,,則返回屬性的值,如果該方法或?qū)傩圆淮嬖?,則拋出異常,;
setattr 動(dòng)態(tài)添加一個(gè)方法或?qū)傩裕?br>delattr 動(dòng)態(tài)刪除一個(gè)方法或?qū)傩浴?/span>
異常處理
Python 異常處理依賴的關(guān)鍵字:
try
except
else
finally
try
try 塊里面放置所有可能引起異常的代碼,一個(gè)異常處理塊里面只能有一個(gè) try;
except
放置要處理的異常類型和相應(yīng)語句塊,,用于表明該 except 要處理的異常類型,;
一個(gè)異常處理塊里面可以跟 1 到 n 個(gè) except 塊;
每個(gè) except 塊后面可以跟 1 到 n 個(gè)異常類型,,也可以不跟任何異常類型,;
else
如果 try 塊里面的語句沒有引起異常,則會(huì)運(yùn)行 else 里面的語句,;
finally
主要用于回收再 try 塊里面打開的物理資源,,異常處理機(jī)制會(huì)保證 finally 塊一定會(huì)被執(zhí)行;
異常處理語法結(jié)構(gòu)
1.只有 try 是必須的
2.如果沒有 try,,就不能有 except 和 finally
3.except 塊和 finally 塊都是可選的,,但 except 和 finally 必須出現(xiàn)其中之一,也可以同時(shí)出現(xiàn)
4.可以有多個(gè) except 塊,,但捕獲父類異常的 except 塊要寫在捕獲子類異常的 except 塊的后面
5.多個(gè) except 塊必須位于 try 塊之后,,finally 塊必須位于所有塊的最后
IO 讀寫 - 文本文件
open (path,mode)
默認(rèn)是 r:只讀模式,文件必須事先存在,,不主動(dòng)生成文件,,從文件開頭開始讀;
r+:讀寫模式,,文件也必須事先存在,,不主動(dòng)生成文件,從文件開頭開始讀或?qū)懀?br>w:只寫模式,,如果用 w 模式打開,,一律會(huì)清空之前文件的所有內(nèi)容,如果文件不存在,,則自動(dòng)創(chuàng)建文件,,從頭開始寫;
w+:讀寫模式,,也會(huì)清空之前文件的所有內(nèi)容,,如果文件不存在,則自動(dòng)創(chuàng)建文件,,從頭開始寫,;
a:追加模式,只寫,,不會(huì)清空以前文件的內(nèi)容,,主動(dòng)生成文件,從文件尾開始寫入,;
a+:追加模式,讀和寫,不會(huì)清空以前文件的內(nèi)容,,主動(dòng)生成文件,,從文件尾開始寫入或讀取,;
二進(jìn)制讀寫,,一般用于圖片或音視頻:rb+,wb+,ab+;
查看和設(shè)置文件指針位置:
with open('user.txt', 'a+') as f:
# 將文件指針重置至開始位置(這樣就不會(huì)導(dǎo)致f.readlines()讀不到數(shù)據(jù)了) f.seek(0)
# 返回文件指針位置 print(f.tell())
with 是 python 中的上下文管理器,,它會(huì)自動(dòng)幫你管理文件的句柄
with open(r'D:\testlog.txt') as f:for line in f.readlines():
print(line,end='')
文件與文件夾
windows 文件路徑用反斜線,,Linux 文件路徑用正斜線,要想將程序在不同系統(tǒng)上運(yùn)行,,則可用 os.path.join() 方法,;
myFiles = ['accounts.txt','details.csv','invite.docx']
for filename in myFiles:
print(os.path.join('c:\\User\\asweigart',filename))-----------------------------------------------------------------------------------------c:\User\asweigart\accounts.txtc:\User\asweigart\details.csvc:\User\asweigart\invite.docx
其余相關(guān)知識(shí)點(diǎn)附張圖吧:
多線程和多進(jìn)程編程
概念
程序:指的是一段靜態(tài)的代碼指令;
進(jìn)程:正在執(zhí)行的程序,,將靜態(tài)的執(zhí)行代碼運(yùn)行起來,,進(jìn)程內(nèi)擁有該程序執(zhí)行所需的全部資源;
線程:是指正在執(zhí)行程序的最小單元,。一個(gè)進(jìn)程中至少必須有一個(gè)線程(主線程),,在程序中線程是獨(dú)立的可運(yùn)行的流;
多線程:在單個(gè)程序中同時(shí)運(yùn)行多個(gè)不同的線程,,完成不同的工作,;
進(jìn)程特征
獨(dú)立性:進(jìn)程是系統(tǒng)中獨(dú)立存在的實(shí)體,擁有獨(dú)立的資源空間,;
動(dòng)態(tài)性:進(jìn)程擁有自己的生命周期,;
并發(fā)性:多個(gè)進(jìn)程可以在單個(gè)處理器上并發(fā)執(zhí)行,互不影響,;
線程特征
每個(gè)線程都有自己的堆棧,,自己的程序計(jì)數(shù)器,自己的局部變量,,這里體現(xiàn)了程序的獨(dú)立性,;
在相同父進(jìn)程下的所有線程共享進(jìn)程內(nèi)所有資源,可以實(shí)現(xiàn)線程間的消息互通,;
多個(gè)線程之間也可以并發(fā)執(zhí)行,,互不影響;
創(chuàng)建多線程-threading
1.使用 threading 模塊的 Thread 類的構(gòu)造器創(chuàng)建線程對(duì)象,。在創(chuàng)建線程對(duì)象時(shí)使用 target 參數(shù)指定函數(shù)線程的執(zhí)行體,;
2.調(diào)用線程對(duì)象的 start() 方法啟動(dòng)線程;
通過 join 方法去阻塞主線程
d = Demo()t1 = threading.Thread(target=d.music,args=('搖籃曲',))t2 = threading.Thread(target=d.movie, args=('灰太狼',))t1.start()t2.start()t1.join()t2.join()
設(shè)置守護(hù)線程
主線程結(jié)束后立即結(jié)束所有設(shè)置為守護(hù)線程的子線程;
多線程鎖
import threadingbalance = 0lock = threading.RLock()def change_it(n):lock.acquire()try:
global balance
balance += n
balance -= nfinally:
lock.release()def run_threading(n):for i in range(100000000):
change_it(n)t1 = threading.Thread(target=run_threading, args=(5,))t2 = threading.Thread(target=run_threading, args=(5,))t1.start()t2.start()t1.join()t2.join()
GIL 全局解釋器鎖
什么是 GIL 全局解釋器鎖:
GIL(Global Interpreter Lock)是 Python 的一個(gè)重要特性,,它是一種機(jī)制,,用于保護(hù)多線程環(huán)境下共享內(nèi)存數(shù)據(jù)的完整性,。它鎖定了整個(gè)解釋器,只允許一個(gè)線程同時(shí)執(zhí)行 Python 字節(jié)碼,,從而避免多線程下出現(xiàn)數(shù)據(jù)競爭問題,。這意味著即使使用多核 CPU,Python 程序也不能充分利用多核優(yōu)勢,。GIL 在性能上可能帶來一定的影響,,因此不適合處理需要大量的 CPU 運(yùn)算的任務(wù)。
什么條件下會(huì)釋放 GIL:
當(dāng)前活躍線程遇到 IO 等待,,比如要訪問網(wǎng)絡(luò)或建立數(shù)據(jù)庫鏈接等情況;
活躍線程執(zhí)行了 100 個(gè)字節(jié)碼的程序后,,GIL 也會(huì)釋放該線程的鎖,然后與其他線程參與競爭;
python 的多線程適合場景:
python 的多線程只適合于 IO 密集型應(yīng)用,,對(duì)于計(jì)算密集型的應(yīng)用最好使用多進(jìn)程或協(xié)程的方式解決,;
可迭代對(duì)象
通俗說,可迭代對(duì)象就是可以放在 for 循環(huán)內(nèi)進(jìn)行迭代的對(duì)象
比如列表,、字典,、元祖、字符串,;
判斷一個(gè)可迭代對(duì)象的依據(jù)是什么:
必須至少實(shí)現(xiàn)getitem或iter這兩個(gè)方法中的其中一個(gè)
迭代器
任何實(shí)現(xiàn)了iter和next方法的對(duì)象都是迭代器(這兩個(gè)方法必須同時(shí)實(shí)現(xiàn)),;
其中iter會(huì)返回迭代器本身;
next會(huì)返回迭代器中的下一個(gè)元素,,如果沒有元素了將拋出 stopIteration 異常,;
迭代器當(dāng)然也可以用到 for 循環(huán)中;
迭代器實(shí)際上就是一種工廠模式,。
迭代器和可迭代對(duì)象的區(qū)別
迭代器是迭代對(duì)象的一種,,迭代器一定是可迭代對(duì)象,可迭代對(duì)象不一定是迭代器
一個(gè)合法的迭代器,,必須同時(shí)實(shí)現(xiàn)iter和next兩個(gè)魔法方法
可迭代對(duì)象只需要實(shí)現(xiàn)iter方法即可
判斷對(duì)象 obj 可迭代的唯一方法就是調(diào)用 iter(obj),,看返回結(jié)果是不是一個(gè)迭代器
每個(gè)迭代器的被迭代過程是一次性的,可迭代對(duì)象則不一定
生成器
特殊的迭代器,,只需要使用 yield 關(guān)鍵字,,那么就會(huì)立即變?yōu)橐粋€(gè)生成器,也就是說,,只要一個(gè)函數(shù)中包含了一個(gè) yield 關(guān)鍵字(不管幾個(gè)),,那么這個(gè)函數(shù)就會(huì)自動(dòng)變成一個(gè)生成器函數(shù);
生成器一定是一個(gè)迭代器,,但反之不一定成立,;
特點(diǎn):
生成器中每次遇到 yield 關(guān)鍵字之后,會(huì)返回相應(yīng)的結(jié)果,;
保留函數(shù)當(dāng)前的運(yùn)行狀態(tài),,等待下一次調(diào)用,,下次調(diào)用時(shí)將從上一次返回 yield 語句處開始執(zhí)行后面的語句;
生成器的 send 方法可以向函數(shù)體內(nèi)去傳遞值,;
對(duì)于 next 和 send 方法的異同:
next 和 send 都可以去調(diào)用一次生成器,,從調(diào)用生成器的角度來說,,他們的作用完全一樣,;
next 無法像生成器內(nèi)部的變量賦值,但 send 可以,;
next(gen) 等同于 send(None),,可以互換;
在生成器中使用 for 循環(huán)
每一次 for 循環(huán)相當(dāng)于調(diào)用一次 next,;
for 循環(huán)會(huì)自動(dòng)幫助我們處理 stopIteration 異常,。
裝飾器
定義
裝飾器本質(zhì)是函數(shù),只是它的作用是為其他函數(shù)添加特定的附加功能,;
編寫裝飾器的原則
裝飾器一定不能修改被裝飾器的函數(shù)的源碼,;
裝飾器一定不能修改被裝飾的函數(shù)的調(diào)用方式;
實(shí)現(xiàn)裝飾器的前置知識(shí)條件
1.函數(shù)即變量
函數(shù)和普通變量的存儲(chǔ)原理是一樣的,,函數(shù)名可以像變量名那樣去使用,,比如可以進(jìn)行賦值;
2.掌握高階函數(shù)相關(guān)知識(shí)
符合下面任意條件之一即為高階函數(shù)
條件一:接收函數(shù)名作為參數(shù)
條件二:返回值中包含函數(shù)名
3.掌握函數(shù)嵌套相關(guān)知識(shí)
通過 def 關(guān)鍵字在一個(gè)函數(shù) A 中去定義另外一個(gè)函數(shù) B,則函數(shù) B 稱為嵌套函數(shù),;
4.裝飾器=高階函數(shù) + 嵌套函數(shù)
了解裝飾器的本質(zhì)優(yōu)勢
1.運(yùn)行時(shí)校驗(yàn):在執(zhí)行階段進(jìn)行特定校驗(yàn),,當(dāng)校驗(yàn)不通過時(shí)終止執(zhí)行:
Django 框架中的用戶登錄態(tài)校驗(yàn)裝飾器@login_required;
2.注入額外參數(shù):在函數(shù)被調(diào)用時(shí)自動(dòng)注入額外的調(diào)用參數(shù):
unittest.mock 模塊的裝飾器@patch,;
3.緩存執(zhí)行結(jié)果:通過調(diào)用參數(shù)等輸入信息,,直接緩存函數(shù)執(zhí)行結(jié)果:
functools 模塊的緩存裝飾器@lru_cache;
4.注冊(cè)函數(shù):將被裝飾函數(shù)注冊(cè)為某個(gè)外部流程的一部分:
Flask 框架的路由注冊(cè)裝飾器@app.route,;
5.替換為復(fù)雜對(duì)象:將原函數(shù) (方法) 替換為更復(fù)雜的對(duì)象,,比如類實(shí)例或特殊的描述符對(duì)象:
靜態(tài)方法的裝飾器@staticmethod。
正則表達(dá)式
正則表達(dá)式匹配步驟:
1.import re
2.用 re.compile() 函數(shù)創(chuàng)建一個(gè) Regex 對(duì)象(記得使用原始字符串)
3.向 Regex 對(duì)象的 search() 方法傳入想查找的字符串,。它返回一個(gè) Match 對(duì)象(一般用 mo 接收)
4.調(diào)用 Match 對(duì)象的 group() 方法,,返回實(shí)際匹配的字符串
demo:
import re>>> phoneNumRegex = re.compile(r'(\d\d\d)-(\d\d\d-\d\d\d\d)')>>> mo = phoneNumRegex.search('my number is 415-555-4242.')>>> mo.group(1)'415'>>> mo.group(2)'555-4242'>>> mo.group()'415-555-4242'>>> mo.group(0)'415-555-4242'
PLus:
我在學(xué)習(xí)中,發(fā)現(xiàn)正則表達(dá)式在任何語言中都占有很大部分的占比,,但正則表達(dá)式相關(guān)的知識(shí)點(diǎn)又過于零碎,,對(duì)于榆木腦袋的我真是學(xué)一遍忘一遍。在實(shí)際工作中,,我自己真正用到正則的地方并不多,,再看同事,目前就發(fā)現(xiàn)前端同學(xué)有可能會(huì)用到正則去做一些事情,,并且用到的時(shí)候都是度娘,,一是自己真記不住,,二是度娘 copy 過來的多數(shù)情況是比自己寫要嚴(yán)謹(jǐn)?shù)亩嗟摹?/span>
基于此,我把正則視為投入產(chǎn)出比太低的事情,,僅需要記住個(gè)大概印象,,真到用時(shí)能分清度娘上哪個(gè)輪子能用哪個(gè)輪子用不了就可以了。
測試基礎(chǔ)-Python篇 基礎(chǔ)②
常用模塊-math
import math
print(math.ceil(3.14)) # 取大于等于 x 的最小整數(shù)
print(math.fabs(-3)) # 取絕對(duì)值
print(math.floor(3.14)) # 取小于等于 x 的最大整數(shù)
print(math.fsum([1,2,3])) # 求和
print(math.pow(3,4)) #3 的 4 次方 等價(jià)于 3**4
print(math.sqrt(3)) # 開平方,,3 的平方根
常用模塊-random
import random
print(random.random()) # 返回 [0.0,1.0) 之間的浮點(diǎn)數(shù)
print(random.randint(10,20)) # 生成 10 到 20 之間的一個(gè)隨機(jī)整數(shù),,也就是 [10,20]
print(random.randrange(10,20)) # 生成 10 到 20 之間的一個(gè)隨機(jī)整數(shù),,也就是 [10,20)
print(random.uniform(10,20)) # 生成 10 到 20 之間的一個(gè)隨機(jī)浮點(diǎn)數(shù),,也就是 [10,20]
print(random.choice([10,20,30])) # 隨機(jī)從列表選擇一個(gè)數(shù)
print(random.choices([10,20,30],k=2)) # 隨機(jī)從列表選擇 k 個(gè)數(shù),返回列表形式,,取出放回方式,,意思是取出的數(shù)可以重復(fù)
print(random.sample(a1,3)) # 隨機(jī)從列表選 k 個(gè)數(shù),,返回列表形式,取出不放回方式,,意思是取出的數(shù)不會(huì)重復(fù)
random.shuffle(a1) # 洗牌,,隨機(jī)變換列表順序
常用模塊-json
用 loads() 函數(shù)讀取 JSON
要將包含 JSON 數(shù)據(jù)的字符串轉(zhuǎn)換為 Python 的值,就將它傳遞給 json.loads() 函數(shù),;
用 dumps() 函數(shù)寫出 JSON
將一個(gè) python 值轉(zhuǎn)換成 JSON 格式的數(shù)據(jù)字符串,,就用 json.dumps() 函數(shù);
import jsond = {'name':'Tom','age':26}j = json.dumps(d)d2 = json.loads(j)print(d)print(type(d))print()print(j)print(type(j))print()print(d2)print(type(d2))-------------------------------------{'name': 'Tom', 'age': 26}<class 'dict'>
{'name': 'Tom', 'age': 26}
<class 'str'>
{'name': 'Tom', 'age': 26}
<class 'dict'>
常用模塊-time
import timen = time.time()print(n)n1 = round(n,3)print(n1)------------------------1675392067.29749661675392067.297
常用模塊-datetime()
import datetimedt = datetime.datetime.now()print(dt)print('dt.year:' + str(dt.year) + '---type:' + str(type(dt.year)))print('dt.month:' + str(dt.month) + '---type:' + str(type(dt.month)))print('dt.day:' + str(dt.day) + '---type:' + str(type(dt.day)))print('dt.hour:' + str(dt.hour) + '---type:' + str(type(dt.hour)))print('dt.minute:' + str(dt.minute) + '---type:' + str(type(dt.minute)))print('dt.second:' + str(dt.second) + '---type:' + str(type(dt.second)))----------------------------------------------------------------------------------------------------------2023-02-03 11:00:08.205691dt.year:2023---type:<class 'int'>
dt.month:2---type:<class 'int'>
dt.day:3---type:<class 'int'>
dt.hour:11---type:<class 'int'>
dt.minute:0---type:<class 'int'>
dt.second:8---type:<class 'int'>
import datetimeimport timenow = time.time()date = datetime.datetime.fromtimestamp(now)print(now)print(date)----------------------------------------------------------------------------1675393953.08603122023-02-03 11:12:33.086031
import datetimeimport timed1 = datetime.datetime.now()time.sleep(1)d2 = datetime.datetime.now()print(d2>d1)-----------------------------------------------True
import datetimeimport timed1 = datetime.datetime.now()time.sleep(1)d2 = datetime.datetime.now()d3 = d2 -d1print(d3)print(type(d3))------------------------------------------------0:00:01.002022<class 'datetime.timedelta'>
import datetimedt = datetime.timedelta(days=11,hours=10,minutes=9,seconds=8)print(dt)print(type(dt))print(dt.days)print(dt.seconds) # 天不參與計(jì)算,10*60*60 + 9*60 + 8 = 36548print(dt.total_seconds()) # 11*24*60*60 + 10*60*60 + 9*60 + 8 = 986948print(str(dt))---------------------------------------------------------------------------------------------------------11 days, 10:09:08<class 'datetime.timedelta'>
11
36548
986948.0
11 days, 10:09:08
import datetimedt = datetime.datetime.now()print(dt)thounsandDays = datetime.timedelta(days=1000)print(thounsandDays)print(dt + thounsandDays)------------------------------------------------------------------------------2023-02-06 14:20:46.2650841000 days, 0:00:002025-11-02 14:20:46.265084
常用模塊-logging
Logging 庫是非常常用的記錄日志庫,,通過 logging 模塊存儲(chǔ)各種格式的日志,主要用于輸出運(yùn)行日志,,可以設(shè)置輸出日志的等級(jí),、日志保存路徑、日志文件回滾等;
import logginglogging.basicConfig(format='%(levelname)s %(asctime)s: %(message)s: %(module)s',level=logging.DEBUG)logging.debug('This message should appear on the console')logging.info('So should this')logging.warning('And this, too')-----------------------------------------------------------------------------------------------------DEBUG 2023-02-07 17:04:37,473: This message should appear on the console: logging_practiceINFO 2023-02-07 17:04:37,473: So should this: logging_practiceWARNING 2023-02-07 17:04:37,473: And this, too: logging_practice
import logginglogging.basicConfig(filename='myProgramLog',format='%(levelname)s %(asctime)s: %(message)s: %(module)s',level=logging.DEBUG)logging.debug('This message should appear on the console')logging.info('So should this')logging.warning('And this, too')
import logginglogging.disable(logging.CRITICAL)logging.basicConfig(filename='myProgramLog',format='%(levelname)s %(asctime)s: %(message)s: %(module)s',level=logging.DEBUG)logging.debug('This message should appear on the console')logging.info('So should this')logging.warning('And this, too')
常用模塊-threading
import timeimport threadingprint('Start of program.')def takeANap():
time.sleep(5)
print('Wake up!')threadObj = threading.Thread(target=takeANap)threadObj.start()print('End of program')----------------------------------------------------------------------------Start of program.End of programWake up!
注意:target 參數(shù)名后傳的是方法名,不加 (),,因?yàn)榇颂幉⒉皇钦{(diào)用,。
import threadingl = [1,2,3,4]def a(*args):
for _ in args:
print(_)thread_a = threading.Thread(target=a,args=l)thread_a.start()------------------------------------------------------------------------1234
import threadingd = {'name': 'Tom', 'age': 18}def b(**kwargs):
for k, v in kwargs.items():
print(str(k) + ':' + str(v))thread_b = threading.Thread(target=b, kwargs=d)thread_b.start()----------------------------------------------------------------------------name:Tomage:18
并發(fā)問題需要注意的是:為了避免并發(fā)問題,,絕不讓多個(gè)線程讀取或?qū)懭胂嗤兞俊.?dāng)創(chuàng)建一個(gè)新的 Thread 對(duì)象時(shí),,要確保其目標(biāo)函數(shù)只使用該函數(shù)中的局部變量,。
線程阻塞-thread.join()
thread.join() 方法的作用是阻塞當(dāng)前線程,直到調(diào)用 join() 方法的線程結(jié)束,。也就是說,,如果你有多個(gè)線程并希望在其中一個(gè)線程結(jié)束之后再繼續(xù)執(zhí)行,,則可以使用 join() 方法,。
# 不使用join,兩個(gè)線程并行運(yùn)行import timeimport threadingdef a():
time.sleep(1)
print('我是a:1/3')
time.sleep(1)
print('我是a:2/3')
time.sleep(1)
print('我是a:3/3')def b():
print('我是b:1/2')
print('我是b:2/2')thread_a = threading.Thread(target=a)thread_b = threading.Thread(target=b)thread_a.start()thread_b.start()-------------------------------------------------------------我是b:1/2我是b:2/2我是a:1/3我是a:2/3我是a:3/3
# 使用join,,線程b需要等線程a運(yùn)行完后再運(yùn)行import timeimport threadingdef a():
time.sleep(1)
print('我是a:1/3')
time.sleep(1)
print('我是a:2/3')
time.sleep(1)
print('我是a:3/3')def b():
print('我是b:1/2')
print('我是b:2/2')thread_a = threading.Thread(target=a)thread_b = threading.Thread(target=b)thread_a.start()thread_a.join()thread_b.start()--------------------------------------------------------------我是a:1/3我是a:2/3我是a:3/3我是b:1/2我是b:2/2
# join()方法可以自定義timeout參數(shù),,意為最長暫用CPU時(shí)間,如果不設(shè)置的話就永遠(yuǎn)等待,;import timeimport threadingdef a():
time.sleep(1)
print('我是a:1/3')
time.sleep(1)
print('我是a:2/3')
time.sleep(1)
print('我是a:3/3')def b():
print('我是b:1/2')
print('我是b:2/2')thread_a = threading.Thread(target=a)thread_b = threading.Thread(target=b)thread_a.start()thread_a.join(timeout=2)thread_b.start()-------------------------------------------------------------我是a:1/3我是a:2/3我是b:1/2我是b:2/2我是a:3/3
深拷貝淺拷貝
不可變數(shù)據(jù)類型(如整型,,字符串等)在 Python 中只是拷貝了值,因此在執(zhí)行淺拷貝時(shí)實(shí)際上是創(chuàng)建了一個(gè)新的副本,,而不是拷貝引用,。因此,對(duì)原數(shù)據(jù)的更改不會(huì)影響到拷貝后的數(shù)據(jù),。
import copya = 1000b = ac = copy.copy(a)d = copy.deepcopy(a)print(a, b, c, d)print(id(a), id(b), id(c), id(d))a += 1print(a, b, c, d)print(id(a), id(b), id(c), id(d))----------------------------------------------1000 1000 1000 10002518799374640 2518799374640 2518799374640 25187993746401001 1000 1000 10002518805613936 2518799374640 2518799374640 2518799374640
對(duì)于可變數(shù)據(jù)類型,,淺拷貝只拷貝第一層中的引用,深拷貝在拷貝時(shí),,會(huì)逐層進(jìn)行拷貝,,直到所有的引用都是不可變對(duì)象為止。
import copya = [1, 2, [3, 4]]b = ac = copy.copy(a)d = copy.deepcopy(a)e = a.copy()f = a[:]print(a, b, c, d, e,f)print(id(a), id(b), id(c), id(d), id(e),id(f))print()a.append(5)print(a, b, c, d, e,f)print(id(a), id(b), id(c), id(d), id(e),id(f))print()a[2].append(6)print(a, b, c, d, e,f)print(id(a), id(b), id(c), id(d), id(e),id(f))----------------------------------------------------[1, 2, [3, 4]] [1, 2, [3, 4]] [1, 2, [3, 4]] [1, 2, [3, 4]] [1, 2, [3, 4]] [1, 2, [3, 4]]2213595331584 2213595331584 2213595362304 2213595356992 2213595443008 2213595442368[1, 2, [3, 4], 5] [1, 2, [3, 4], 5] [1, 2, [3, 4]] [1, 2, [3, 4]] [1, 2, [3, 4]] [1, 2, [3, 4]]2213595331584 2213595331584 2213595362304 2213595356992 2213595443008 2213595442368[1, 2, [3, 4, 6], 5] [1, 2, [3, 4, 6], 5] [1, 2, [3, 4, 6]] [1, 2, [3, 4]] [1, 2, [3, 4, 6]] [1, 2, [3, 4, 6]]2213595331584 2213595331584 2213595362304 2213595356992 2213595443008 2213595442368
Python 有多種方式實(shí)現(xiàn)淺拷貝,,copy 模塊的 copy 函數(shù) ,,對(duì)象的 copy 函數(shù) ,工廠方法,,切片等,。
賦值符號(hào)'=':如果是可變類型,就是引用傳遞,;如果是不可變類型,,就是值傳遞。
淺拷貝的優(yōu)點(diǎn):拷貝速度快,,占用空間少,,拷貝效率高,。
因?yàn)闇\拷貝不能解決嵌套問題,所以引出了深拷貝,,深拷貝會(huì)遍歷并拷貝 items 里所有的內(nèi)容 - 包括他嵌套的子列表,;
對(duì)象的可哈希性
不可變的內(nèi)置類型都是可哈希的,比如 str,、int,、float、frozenset
可變的內(nèi)置類型都是不可以哈希的,,比如 list,、dict
對(duì)于不可變?nèi)萜黝愋停╰uple、frozenset),,僅當(dāng)他的所有成員都不可變時(shí),,他自身才是可哈希的
用戶定義的類型默認(rèn)都是可哈希的
注意:只有可哈希對(duì)象才能被放進(jìn)集合或者作為字典的鍵
sorted() 函數(shù)
sorted 函數(shù)是 Python 內(nèi)置函數(shù),用于對(duì)可迭代對(duì)象進(jìn)行排序,,并返回一個(gè)新的列表,。
注意:sorted 函數(shù)不會(huì)改變?cè)瓉淼目傻鷮?duì)象,而是返回一個(gè)新的列表,。如果需要改變?cè)瓉淼目傻鷮?duì)象,,可以使用 sort 方法,但它只能用于列表,。
參數(shù):
iterable:可以是列表,、元組、字典等任意可迭代對(duì)象,。
key:一個(gè)函數(shù),,用于提取每個(gè)元素的排序關(guān)鍵字。默認(rèn)為 None,,表示按元素本身的順序進(jìn)行排序,。
reverse:是否按降序排列,默認(rèn)為 False,,表示按升序排列,。
enumerate() 函數(shù)
enumerate() 適用于任何'可迭代對(duì)象',可以用于列表,、元祖,、字典、字符串等,。
def enumerate_func():
names = ['lily','wenwen','tom']
for index, s in enumerate(names,start=1):
print(index,s)---------------------------------------------1 lily2 wenwen3 tom
如果不指定 start 參數(shù),,則 index 從 0 開始
測試基礎(chǔ)-Python篇 基礎(chǔ)③
浮點(diǎn)數(shù)精度問題
print(0.1+0.2)----------------------0.30000000000000004
可以使用 decimal 模塊解決浮點(diǎn)數(shù)精度問題:
from decimal import Decimalprint(Decimal('0.1') + Decimal('0.2'))print(type(Decimal('0.1') + Decimal('0.2')))print(type(Decimal('0.1')))---------------------------------------------------------0.3<class 'decimal.Decimal'>
<class 'decimal.Decimal'>
注意:在使用 Decimal 時(shí)要用字符串來表示數(shù)字
布爾值其實(shí)也是數(shù)字
def sum_even(numbers: list[int]):
'''
返回numbers中偶數(shù)的個(gè)數(shù)
:param numbers: 整數(shù)列表
'''
return sum(i % 2 == 0 for i in numbers)
不常用但特別好用的字符串方法
str.partition(sep) 按照切分符 sep 切分字符串,返回一個(gè)包含三個(gè)成員的元祖 (part_before, sep, part_after),;若 s 不包括分隔符,,則最后一個(gè)成員默認(rèn)是空字符串'';
s = 'TomAndMarry's2 = s.partition('And')print(s2)--------------------------------('Tom ', 'And', ' Marry')
s = '明明是中文,卻使用了英文標(biāo)點(diǎn).'table = s.maketrans(',.', ',,。')s2 = s.translate(table)print(s2)-----------------------------------------------明明是中文,,卻使用了英文標(biāo)點(diǎn)。
使用枚舉類型來替代字面量
# 用戶每日獎(jiǎng)勵(lì)積分?jǐn)?shù)量DAILY_POINTS_REWARDS = 100# VIP用戶額外獎(jiǎng)勵(lì)20VIP_EXTRA_POINTS = 20from enum import Enumclass UserType(int, Enum):
# VIP用戶 VIP = 3
# 小黑屋用戶 BANNED = 13def add_daily_points(user):
'''用戶每天第一次登錄增加積分'''
if user.type == UserType.BANNED:
return
if user.type == UserType.VIP:
user.points += DAILY_POINTS_REWARDS + VIP_EXTRA_POINTS
return
user.points += DAILY_POINTS_REWARDS
return
生成器
定義一個(gè)生成器需要生成器函數(shù)和 yield 關(guān)鍵字
yield 和 return 最大的區(qū)別在于,,return 會(huì)一次性返回結(jié)果,,使用它會(huì)直接中斷函數(shù)執(zhí)行,而 yield 可以逐步給調(diào)用方生成結(jié)果
使用生成器的優(yōu)點(diǎn)是它們占用的內(nèi)存比列表要少,,因?yàn)樗鼈冎簧梢粋€(gè)元素并在需要時(shí)生成下一個(gè)元素,。這使得生成器特別適合于處理大量數(shù)據(jù)
每次調(diào)用生成器函數(shù)都會(huì)生成一個(gè)新的生成器對(duì)象
fruits = {'apple','orange','pineapple'}def batch(item):
for _ in item:
yield _print(next(batch(fruits)))print(next(batch(fruits)))print(next(batch(fruits)))---------------------------------------appleappleapple
因?yàn)槊看握{(diào)用生成器函數(shù)都會(huì)生成一個(gè)新的生成器對(duì)象,所以以上程序運(yùn)行結(jié)果會(huì)輸出三個(gè) apple
fruits = {'apple','orange','pineapple'}def batch(item):
for _ in item:
yield _g = batch(fruits)print(next(g))print(next(g))print(next(g))-------------------------------------------------pineappleappleorange
以上代碼再次驗(yàn)證了'每次調(diào)用生成器函數(shù)都會(huì)生成一個(gè)新的生成器對(duì)象'結(jié)論
def batch_process(item):
result = []
for i in item:
# process_item = ..處理item result.append(process_item)
return result# 以上方法會(huì)有一個(gè)問題,,當(dāng)item過大時(shí),會(huì)導(dǎo)致函數(shù)執(zhí)行很耗時(shí),,并且若調(diào)用方想在某個(gè)process_item達(dá)到條件時(shí)中斷,,以上方法也是做不到的。所以可以使用生成器函數(shù)替代,。def batch_process_2(item):
for i in item:
# process_item = ..處理item yield process_item# 調(diào)用方for processed_item in batch_process_2(items):
# 如果某個(gè)處理對(duì)象過期了,,就中斷當(dāng)前的所有處理 if processed_item.has_expired():
break
面向?qū)ο缶幊?/strong>
內(nèi)置類方法裝飾器
類方法
1.用 def 在類里定義一個(gè)函數(shù)時(shí),這個(gè)函數(shù)通常被稱作方法,。調(diào)用這個(gè)方法需要先創(chuàng)建一個(gè)類實(shí)例,;
2.可以使用@classmethod裝飾器定義類方法,它屬于類,,無需實(shí)例化也能調(diào)用,;
3.作為一種特殊方法,類方法最常見的使用場景,,就是定義工廠方法來生成新實(shí)例,,類方法的主角是類型本身,當(dāng)發(fā)現(xiàn)某個(gè)行為不屬于實(shí)例,,而是屬于整個(gè)類型是,,可以考慮使用類方法;
靜態(tài)方法
1.如果發(fā)現(xiàn)某個(gè)方法不需要使用當(dāng)前實(shí)例里的任何內(nèi)容,,那可以使用@staticmethod來定義一個(gè)靜態(tài)方法,;
2.和普通方法相比,,靜態(tài)方法不需要訪問實(shí)例的任何狀態(tài),是一種與狀態(tài)無關(guān)的方法,,因此靜態(tài)方法其實(shí)可以寫成脫離于類的外部普通函數(shù),;
2.1.如果靜態(tài)方法特別通用,與類關(guān)系不大,,那么把他改成普通函數(shù)會(huì)更好;
2.2.如果靜態(tài)方法與類關(guān)系密切,,那么用靜態(tài)方法更好;
2.3.相比函數(shù),靜態(tài)方法有一些先天優(yōu)勢,,比如能被子類繼承和重寫;
屬性裝飾器
1.@property 裝飾器模糊了屬性和方法間的界限,,使用它,可以把方法通過屬性的方式暴露出來;
2.@property 除了可以定義屬性的讀取邏輯外,,還支持自定義寫入和刪除邏輯;
class FilePath:
@property
def basename(self):
....
@property.setter
def basename(self, name):
....
@property.deleter
def basename(self):
....
經(jīng)過@property的裝飾以后,,basename 已經(jīng)從一個(gè)普通的方法變成了 property 對(duì)象,所以可以使用 basename.setter 和 basename.deleter 方法;
定義 setter 方法,,該方法會(huì)在對(duì)屬性賦值是被調(diào)用;
定義 deleter 方法,,該方法會(huì)在刪除屬性時(shí)被調(diào)用;
鴨子類型及其局限性
在鴨子類型編程風(fēng)格下,如果想操作某個(gè)對(duì)象,,你不會(huì)去判斷他是否屬于某種類型,,而會(huì)直接判斷他是不是有你需要的方法 (或?qū)傩??;蛘吒みM(jìn)一些,。你甚至?xí)苯訃L試調(diào)用需要的方法,假如失敗了,,那就讓她報(bào)錯(cuò)好了;
鴨子類型的優(yōu)點(diǎn)就是編寫簡單,,使用靈活;
鴨子類型的缺點(diǎn)就是缺乏標(biāo)準(zhǔn)、過于隱式;
可以使用類型注解,、靜態(tài)檢查 (mypy),、抽象類來補(bǔ)充鴨子類型;
抽象類
isinstance() 函數(shù)
利用 isinstance() 函數(shù),我們可以判斷對(duì)象是否屬于特定類型,;
isinstance() 函數(shù)能理解類之間的繼承關(guān)系,,因此子類的實(shí)例同樣可以通過基類的校驗(yàn);
校驗(yàn)對(duì)象是否是 Iterable 類型
在 collections.abc 模塊中,,有許多和容器相關(guān)的抽象類,,比如代表集合的 Set、代表序列的 Sequence 等,,其中有一個(gè)最簡單的抽象類:Iterable,,他表示的是可迭代類型;
鴨子類型和抽象類總結(jié)
鴨子類型是一種編碼風(fēng)格,在這種風(fēng)格下,,代碼只關(guān)心對(duì)象的行為,,不關(guān)心對(duì)象的類型;
鴨子類型降低了類型校驗(yàn)的成本,,讓代碼變得更靈活,;
傳統(tǒng)的鴨子類型里,各種對(duì)象接口和協(xié)議都是隱式的,,沒有統(tǒng)一的顯示標(biāo)準(zhǔn),;
傳統(tǒng)的 isinstance() 類型檢查和鴨子類型的理念是相違背的;
抽象類是一種特殊的類,,他可以通過鉤子方法來定制動(dòng)態(tài)的子類檢查行為,;
因?yàn)槌橄箢惖亩ㄖ谱宇惢卣鳎琲sinstance() 也變得更靈活,、更契合鴨子類型了,;
使用@abstractmethod裝飾器,抽象類可以強(qiáng)制要求子類在繼承時(shí)重寫特定方法,;
除了抽象方法外,,抽象類也可以實(shí)現(xiàn)普通的基礎(chǔ)方法,供子類繼承使用,;
在 collections.abc 模塊中,,有許多與容器相關(guān)的抽象類;
多重繼承于MRO
Python 里的一個(gè)類可以同時(shí)繼承多個(gè)父類,;
調(diào)用類的 mro() 方法,,可以看到按 MRO 算法排好序的基類列表;
在許多人印象中,。super() 是一個(gè)用來調(diào)用父類方法的工具函數(shù)。但這么說并不準(zhǔn)確,,super() 使用的其實(shí)不是當(dāng)前類的父類,,而是當(dāng)前類在 MRO 鏈條上的上一個(gè)類;
應(yīng)該避免多重繼承,;
學(xué)習(xí)建議
對(duì)于Python入門及進(jìn)階,,我推薦兩本我認(rèn)為值得多次閱讀的書籍:
《Python編程從入門到實(shí)踐(第二版)》- 第一部分為基礎(chǔ)語法部分,建議剛接觸 Python 的同學(xué)多次閱讀并實(shí)踐,,夯實(shí)基礎(chǔ)利器,!
《Python工匠》- 整本無尿點(diǎn),強(qiáng)烈建議多次閱讀并實(shí)踐,,是Python進(jìn)階的不二之選,!
其他瑣碎但十分實(shí)用的知識(shí)點(diǎn)
for......else......的執(zhí)行順序:
當(dāng)?shù)鷮?duì)象完成所有迭代后且此時(shí)的迭代對(duì)象為空時(shí),如果存在 else 子句則執(zhí)行 else 子句,沒有則繼續(xù)執(zhí)行后續(xù)代碼,;如果迭代對(duì)象因?yàn)槟撤N原因(如帶有 break 關(guān)鍵字)提前退出迭代,,則 else 子句不會(huì)被執(zhí)行,程序?qū)?huì)直接跳過 else 子句繼續(xù)執(zhí)行后續(xù)代碼,;
數(shù)值型比較不能使用 not in,,因?yàn)?not in 本質(zhì)是循環(huán)遍歷右側(cè)數(shù)據(jù),用左側(cè)數(shù)據(jù)進(jìn)行比對(duì),,len() in range(1,5) 可以使用,,因?yàn)?range 是一個(gè)集合,可以遍歷,, 'li' in 'lili'不建議使用,,因?yàn)榉祷亟Y(jié)果為 True(包含),達(dá)不到預(yù)期結(jié)果,,所以準(zhǔn)確比較建議使用'==',;
字典取值:有兩種方式,a={'name':'lili'}
第一種:a['name']
第二種:a.get('name')
區(qū)別:a['wenwen'] 報(bào)錯(cuò)-KeyError a.get('wenwen') 不報(bào)錯(cuò)-None
如果在方法中給全局變量賦值,,則要在方法中提前聲明全局變量-global,;
列表轉(zhuǎn)成字符串''.join(list)
用''中的字符串作為連接,拼接 list 列表中的每個(gè)元素 --- 只能用在每個(gè)元素都是字符串的時(shí)候可以用,,要不然就會(huì)報(bào)錯(cuò),;
集合數(shù)據(jù)類型 set 取值
因?yàn)榧希╯et)是一種無序的不重復(fù)的元素的集合。因?yàn)榧现械脑貨]有特定的順序,,所以無法通過下標(biāo)索引來訪問,。
可以使用循環(huán)遍歷取值,也可使用 in 判斷目標(biāo)元素是否在集合中,。
當(dāng)遇到復(fù)雜計(jì)算的數(shù)字字面量時(shí),,保留整個(gè)數(shù)學(xué)公式,提示可讀性也不會(huì)降低性能;
要判斷某個(gè)容器是否包含特定成員,,用集合比用列表更合適,,因?yàn)榧系讓邮褂昧斯1頂?shù)據(jù)結(jié)構(gòu)
# 列表數(shù)據(jù)越多效果越明顯VALID_NAMES = ['pip', 'lili', 'name']VALID_NAMES_SET = set(VALID_NAMES)def validate_name(name):
if name not in VALID_NAMES_SET:
raise ValueError(f'{name} is not a valid name')
nums = [10, 2, 3, 21, 10, 3]def ordered_dict(member: list[int]):
from collections import OrderedDict
result = list(OrderedDict.fromkeys(member).keys())
return resultprint(ordered_dict(nums))----------------------------------------------------[10, 2, 3, 21]
在遍歷時(shí)不要直接修改原列表,,可以啟用一個(gè)新列表來保存修改后的成員;
對(duì)于未來可能會(huì)變動(dòng)的多返回值函數(shù)來說,可以使用 NamedTuple 類型對(duì)返回結(jié)果進(jìn)行建模,,可以減少后期代碼變動(dòng)對(duì)已有程序的影響
from typing import NamedTupleclass Address(NamedTuple):
'''地址信息結(jié)果'''
country: str
province: str
city: strdef latlon_to_address(lat, lon):
return Address(
country = country,
province= province,
city = city,
)addr = latlon_to_address(lat, lon)# 通過屬性名來使用addr
# addr.city / addr.country / addr.province
from itertools import productprint(list(product([1,2],[3,4])))----------------------------------------[(1, 3), (1, 4), (2, 3), (2, 4)]
# 常用多層嵌套循環(huán)def find_twelve(nem_list1, num_list2, num_list3):
'從這三個(gè)數(shù)字列表中,,尋找是否存在和為12的3個(gè)數(shù)'
for num1 in num_list1:
for num2 in num_list2:
for num3 in num_list3:
if num1 + num2 + num3 == 12:
return num1, num2, num3# 使用product()扁平化多層嵌套循環(huán)from itertools import productdef find_tewlve_v2(num_list1, num_list2, num_list3):
for num1, num2, num3 in product(num_list1, num_list2, num_list3):
if num1 + num2 + num3 == 12:
return num1, num2, num3
# 方法1:使用enumeratedef parse_titles(filename):
'''從各行數(shù)據(jù)文件中取數(shù)據(jù)'''
with open(filename, 'r') as fp:
for i, line in enumerate(fp):
if i % 2 == 0:
yield lineif __name__ == '__main__':
message_generator = parse_titles('logs.txt')
while True:
try:
print(next(message_generator))
except StopIteration as e:
break
但如果需求變更為每隔3行讀取或者每隔4行讀取,那我們按照以上的寫法應(yīng)該怎么篩選呢,?
# 方法2:使用islicefrom itertools import islicedef parse_titles_v2(filename):
'''使用slice實(shí)現(xiàn)隔行取值'''
with open(filename, 'r') as fp:
for line in islice(fp, 0, None, 2): # islice(seq, start, end, step) yield lineif __name__ == '__main__':
message_generator = parse_titles_v2('logs.txt')
while True:
try:
print(next(message_generator))
except StopIteration as e:
break
如果需求變更為每隔3行讀取或者每隔4行讀取,,我們只需要將 islice(seq, start, end, step) 中的 step 改成3或者4就行了
面對(duì)洋洋灑灑的知識(shí)點(diǎn),我往往 “一看就會(huì),,一寫就廢”,,為了更有針對(duì)性的加深知識(shí)點(diǎn)的印象,接下來,,我將以做題的形式繼續(xù)總結(jié)Python系列,,如果有不正確的地方,希望各位佬兒哥指正糾偏:
1.列表的增刪查改,?
增
l.insert(idx, value) ---指定索引位置增加
l.append(value) ---在末尾追加
l.extend(iterable) ---取出可迭代對(duì)象的值,,追加到列表末尾
l1 = [1,2,3,3,4,5]l1.extend([1,[2]])print(l1)--------------------------[1, 2, 3, 3, 4, 5, 1, [2]]
刪
del l[idx] ---刪除索引處元素,索引超出會(huì)報(bào)錯(cuò):IndexError: list assignment index out of range
del l ---徹底刪除列表
l.pop(idx) ---刪除索引處元素,,索引超出會(huì)報(bào)錯(cuò):IndexError: pop index out of range
l.pop() ---刪除列表最后一個(gè)元素,,列表為空會(huì)報(bào)錯(cuò):IndexError: pop from empty list
l.remove(value) ---刪除列表中第一個(gè)出現(xiàn) value 的元素,值不在會(huì)報(bào)錯(cuò):ValueError: list.remove(x): x not in list
l.clear() --清除列表中的所有元素
查
l[idx]
l.count(value) ---統(tǒng)計(jì)列表中指定元素出現(xiàn)次數(shù),,指定元素不在列表中會(huì)返回:0
l.index(value) ---返回列表中第一個(gè)指定元素的索引,,指定元素不在列表中會(huì)報(bào)錯(cuò):ValueError: 11 is not in list
改
l[idx] = value
2.字典的增刪查改?
增
d[new_key] = value ---如果 key 已存在則是更新操作
d.update({key: value}) ---如果 key 存在則是更新操作
d = dict.fromkeys(keys, value) ---dict.fromkeys(keys, value) 方法用于創(chuàng)建一個(gè)新字典,,其中包含指定的鍵,,并將所有鍵的值設(shè)置為相同的值
d.setdefault(key, default_value) ---如果 key 已存在,則返回對(duì)應(yīng)的 value,,若 key 不存在,,則返回 default_value,并在原字典中新增鍵值對(duì) key: default_value
# 可用setdefault()統(tǒng)計(jì)每個(gè)單詞的出現(xiàn)次數(shù)text = 'Hello world! Hello python! Hello chatbot!'word_list = text.split()word_count = {}for word in word_list:word_count[word] = word_count.setdefault(word, 0) + 1print(word_count)--------------------------------------------------------------------------------------------{'Hello': 3, 'world!': 1, 'python!': 1, 'chatbot!': 1}
刪
d.pop(key) ---key 不存在會(huì)報(bào)錯(cuò):KeyError: 'addr'
d.popitem() ---隨機(jī)刪除一個(gè)鍵值對(duì),,因?yàn)樽值錈o序,,所以是隨機(jī)刪除,字典為空則報(bào)錯(cuò):KeyError: 'popitem(): dictionary is empty'
del d[key] ---刪除指定 key,,若 key 不存在則報(bào)錯(cuò):KeyError: 'addr'
del d ---徹底刪除字典
d.clear ---清空字典
查
d[key] ---若 key 不存在則報(bào)錯(cuò):KeyError: 'addr'
d.get(key) ---若 key 不存在則返回 None
d.keys() ---以列表形式返回字典的所有 key
d.values() ---以列表的形式返回字典的所有 value
d.items() --以列表的形式返回字典的所有鍵值對(duì),,每一組鍵值對(duì)是一組元祖
d1 = {'name': 'Tom', 'age': 25}print(d1.keys())print(type(d1.keys()))print()print(d1.values())print(type(d1.values()))print()print(d1.items())print(type(d1.items()))------------------------------------------------dict_keys(['name', 'age'])<class 'dict_keys'>
dict_values(['Tom', 25])
<class 'dict_values'>
dict_items([('name', 'Tom'), ('age', 25)])
<class 'dict_items'>
d[key] = value
d1.update(d2) ---將 d2 更新到 d1 中,相同的 key 則更改 d1 中的 value
3.元祖的增刪查改
因?yàn)樵媸遣豢勺償?shù)據(jù)類型,,所以不能不能在原元祖新增
t = (1,2,'hello')t2 = (2,3,'world')print(id(t))t += t2print(t)print(id(t))-------------------------2049302192960(1, 2, 'hello', 2, 3, 'world')2049302145920
del t ---不能 del t[idx],否則報(bào)錯(cuò):TypeError: 'tuple' object doesn't support item deletion
t[idx] ---idx 不能越界,,否則報(bào)錯(cuò):IndexError: tuple index out of range
可遍歷元祖
for _ in t:
print(_)
t.count(value) ---返回元祖中 value 的個(gè)數(shù),,value 不存在返回 0
t.index(value) ---返回元祖中首個(gè) value 的索引,value 不存在則報(bào)錯(cuò):ValueError: tuple.index(x): x not in tuple
元組是不可變的,,因此不能修改元組中的任何元素,。
4.例舉Python6種基本的數(shù)據(jù)類型,,并標(biāo)出哪些是不可變數(shù)據(jù)類型?
整形-int-不可變,、浮點(diǎn)型-float-不可變,、字符型-str-不可變、列表-list-可變,、元祖-tuple-不可變,、字典-dict-可變
5.請(qǐng)說明循環(huán)結(jié)構(gòu)和異常處理中的 else 在什么情況下會(huì)執(zhí)行?
在 for.else 循環(huán)結(jié)構(gòu)中,,當(dāng)循環(huán)提全部循環(huán)完畢后,,沒有 break 或者 return 的情況下,會(huì)執(zhí)行 else 代碼段,;
在異常處理中,,try 下的代碼段沒有出現(xiàn)異常的情況下,會(huì)執(zhí)行 else 代碼
條件分支語句用 else 來表示'否則執(zhí)行某件事'
6.列舉python函數(shù)定義中有哪些不同的參數(shù)類型,?
1.位置參數(shù):根據(jù)參數(shù)在函數(shù)定義中的位置來確定,。
2.默認(rèn)參數(shù):在函數(shù)定義中指定的參數(shù)值。
3.關(guān)鍵字參數(shù):在調(diào)用函數(shù)時(shí)指定參數(shù)名稱和對(duì)應(yīng)的值,。
4.星號(hào)參數(shù):在函數(shù)定義中使用來捕獲剩余的參數(shù),。
5.雙星號(hào)參數(shù):在函數(shù)定義中使用* 來捕獲剩余的關(guān)鍵字參數(shù)。
7.python中==和is的區(qū)別,?
==比較的是兩個(gè)對(duì)象的值,,is 比較的是兩個(gè)對(duì)象的內(nèi)存地址。
不能用 is 替代==,,僅當(dāng)你需要判斷某個(gè)對(duì)象是否是 None,、False、True 時(shí),,使用 is,,其他情況下請(qǐng)使用==。
a = [1,2,3]b = [1,2,3]print(id(a))print(id(b))print(a == b)print(a is b)--------------------22782856545922278285654272TrueFalse
a = [1,2,3]b = aprint(id(a))print(id(b))print(a == b)print(a is b)---------------------20215765550722021576555072TrueTrue
額外:關(guān)于賦值或者復(fù)制后 id() 是否異同的知識(shí)點(diǎn),,結(jié)論:除了'='賦值,,其余的 id() 都不一樣,直接舉例:
import copya = [1,2,3]b = ac = a.copy()d = copy.copy(a)e = copy.deepcopy(a)f = a[:]print(id(a))print(id(b))print(id(c))print(id(d))print(id(e))print(id(f))------------------192714345516819271434551681927140937408192714093715219271435578241927143558528
8.請(qǐng)描述global關(guān)鍵字在什么條件下必須被使用,?
在函數(shù)局部要重新賦值全局變量之前,,需要使用 global 關(guān)鍵字聲明全局變量。
9.請(qǐng)說明if name == 'main':語句的作用,?
在 Python 中,,當(dāng)一個(gè)模塊被執(zhí)行時(shí),if name == 'main':語句塊會(huì)被執(zhí)行,。此語句塊可以用來測試模塊的代碼,,而不會(huì)影響模塊的其他功能,。
如果模塊被其他模塊導(dǎo)入,則name的值為該模塊的名稱,,而不是main,。如果該模塊是主程序,則name的值為main,,此時(shí)該語句塊會(huì)被執(zhí)行,。
這樣的語句使得可以在模塊被其他模塊導(dǎo)入時(shí)忽略測試代碼,并且只在模塊被獨(dú)立運(yùn)行時(shí)執(zhí)行測試代碼,。
10.面向?qū)ο缶幊逃心娜筇匦???qǐng)說明各個(gè)特性的意義。
封裝:隱藏內(nèi)部狀態(tài)和實(shí)現(xiàn)細(xì)節(jié),,僅提供必要的接口給外部使用,。
繼承:允許創(chuàng)建新的對(duì)象類型,并基于現(xiàn)有的對(duì)象類型派生,,從而繼承其行為和狀態(tài),。
多態(tài):允許不同類型的對(duì)象對(duì)相同消息做出不同的響應(yīng)。
11.類反射中常用的方法及含義,?
常用的類反射方法有:
type(object):獲取對(duì)象的類型,,返回一個(gè) type 對(duì)象。
isinstance(object, classinfo):判斷對(duì)象是否是某種類型的實(shí)例,,返回布爾值,。
issubclass(class, classinfo):判斷一個(gè)類是否是另一個(gè)類的子類,返回布爾值,。
getattr(object, name[, default]):獲取對(duì)象的屬性或方法,,如果不存在,可以返回 default 參數(shù)指定的默認(rèn)值,。
hasattr(object, name):判斷對(duì)象是否具有某個(gè)屬性或方法,,返回布爾值。
setattr(object, name, value):設(shè)置對(duì)象的屬性值,。
delattr(object, name):刪除對(duì)象的屬性,。
使用類反射可以動(dòng)態(tài)地獲取和操作類的信息,是動(dòng)態(tài)語言的重要特性,。
12.python中創(chuàng)建一個(gè)新線程有哪幾種方式,?
1.使用 threading 模塊:通過定義一個(gè)繼承自 Thread 的類并重寫其 run 方法,然后通過該類的實(shí)例調(diào)用 start 方法啟動(dòng)線程,。
2.使用 multiprocessing 模塊:通過使用 Process 類創(chuàng)建新的進(jìn)程,。
3.使用協(xié)程:通過使用生成器實(shí)現(xiàn)協(xié)程,在協(xié)程內(nèi)部通過 yield 實(shí)現(xiàn)非阻塞的多任務(wù)執(zhí)行,。
多線程編程是高并發(fā)編程的一種常見形式,,可以提高程序的執(zhí)行效率。
13.python中GIL全局解釋器鎖在什么情況下會(huì)被釋放,?
Python 中的 GIL (Global Interpreter Lock) 是一種機(jī)制,,它限制任意時(shí)刻僅有一個(gè)線程可以運(yùn)行在 Python 解釋器中。GIL 在以下情況下會(huì)被釋放:
解釋器在執(zhí)行 CPU 密集型任務(wù)時(shí):例如運(yùn)算,,在這種情況下,,GIL 會(huì)每隔一定時(shí)間被釋放,以便其他線程有機(jī)會(huì)被調(diào)度執(zhí)行,。
解釋器在執(zhí)行 I/O 密集型任務(wù)時(shí):例如讀取文件,,在這種情況下,由于 I/O 操作需要等待外部設(shè)備,,所以 GIL 會(huì)在 I/O 操作期間被釋放,。
GIL 可能會(huì)影響多線程程序的性能,因此通常不建議在 Python 中開發(fā) CPU 密集型的多線程程序,??梢允褂枚噙M(jìn)程來代替多線程以提高性能。
14.描述編寫裝飾器的原則是什么,?
1.不改變?cè)瘮?shù)的內(nèi)部邏輯
2.不改變?cè)瘮?shù)的調(diào)用方法
15.現(xiàn)在有一個(gè)Animal類有初始化方法定義如下:
class Animal:
def init(self, skin, legs):
self.skin = skin
self.legs = legs
如果現(xiàn)在想定義一個(gè)Dog類,,并繼承于這個(gè)Animal類,并想給這個(gè)Dog類增加一個(gè)nickname對(duì)象屬性,,Dog類的初始化方法應(yīng)該怎么定義才能保證 Dog 類和其父類均能初始化成功,?
# 兩種寫法,第二種以Cat舉例class Animal:
def __init__(self, skin, legs):
self.skin = skin
self.legs = legsclass Dog(Animal):
def __init__(self, skin, legs, nickname):
super().__init__(skin, legs)
self.nickname = nicknameclass Cat(Animal):
def __init__(self, skin, legs, hobby):
Animal.__init__(self, skin, legs)
self.hobby = hobbya = Animal(skin='sss', legs='lll')d = Dog(skin='sss', legs='lll', nickname='nnn')c = Cat(skin='sss', legs='lll', hobby='hhh')print(a.skin)print(d.nickname)print(c.hobby)print(c.skin)----------------------------------------------------------------------sssnnnhhhsss
super 方法是 Python 中的一種特殊方法,,用于引用父類,。它常用于多重繼承,當(dāng)子類需要調(diào)用父類的方法時(shí),,就可以使用 super 方法,。這個(gè)方法可以直接調(diào)用父類的方法,而無需顯式命名父類名稱,。
16.文件zen.txt中保存著python之禪,,請(qǐng)使用python代碼統(tǒng)計(jì)該文件中每個(gè)單詞出現(xiàn)的次數(shù)。
file_path = r'C:\Users\EDZ\Desktop\zen.txt'with open(file_path, 'r') as f:
text = f.read()words = text.split()word_counts = {}for word in words:
if word in word_counts:
word_counts[word] += 1
else:
word_counts[word] = 1print(word_counts)
17.編寫一個(gè)裝飾器,,使用該裝飾器能夠顯示任意函數(shù)運(yùn)行所需時(shí)間,。
def running_time(fun):
def wrapper(*args, **kwargs):
start_time = time.time()
result = fun(*args, **kwargs)
end_time = time.time()
print(f'{fun.__name__}運(yùn)行花費(fèi)了:{end_time-start_time:.2f} 秒。')
return result
return wrapper@running_timedef take_time():
time.sleep(2)take_time()----------------------------------------------------take_time運(yùn)行花費(fèi)了:2.01 秒,。
18.用兩種方法合并下面列表
x = ['a', 'b']y = ['c', 'd', 'e']x.extend(y)# 或x += y
19.計(jì)算得到列表當(dāng)中長度最長的字符串words = ['Python', 'is', 'awesome']
words = ['Python', 'is', 'awesome']# 我的笨方法s = ''for _ in words:
if len(_) > len(s):
s = _print(s)# 標(biāo)答給的方法
# 使用內(nèi)置函數(shù) max() 和 len() 計(jì)算,,在 max() 函數(shù)中使用 key 參數(shù)指定了用于比較大小的函數(shù)為 len(),這樣比較的就是字符串的長度,,而不是字典序,。longest_word = max(words, key=len)print(longest_word)
20.將列表中的順序倒轉(zhuǎn) (2 種方法) words = ['Python', 'is', 'awesome']
words = ['Python', 'is', 'awesome']# 方法1,,列表的reverse()方法(改變?cè)斜?words.reverse()print(words)# 方法2,列表切片(生成新列表,,原列表不變)w = words[::-1]print(w)
21.將字典當(dāng)中的鍵值對(duì)位置調(diào)換
staff = {'Data Scientist': 'Mike', 'Django Developer': 'Dylan'}
答:
staff = {'Data Scientist': 'Mike', 'Django Developer': 'Dylan'}# 我的笨方法reverse = {}for k, v in staff.items():
reverse[v] = kprint(reverse)# 標(biāo)答給的方法(字典推導(dǎo)式)inverted_staff = {v: k for k, v in staff.items()}print(inverted_staff)
22.將嵌套列表合并為一個(gè)列表
l = [[1, 2, 3], [4, 5], [6], [7, 8], [9]]
答:
# 針對(duì)此題目,,我想到的是循環(huán)遍歷result = []for i in l:
for n in i:
result.append(n)print(result)# 標(biāo)答給的方法1:
# 在 sum() 函數(shù)中使用的第二個(gè)參數(shù)是空列表,表示從空列表開始計(jì)算和,。merged_list = sum(l, [])print(merged_list) # 標(biāo)答給的方法2:列表推導(dǎo)式merged_list = [item for sublist in l for item in sublist]print(merged_list)# 可如上3個(gè)方法只能針對(duì)此題目,,一旦題目列表沒這么規(guī)范,比如下面的列表,,那么如上3個(gè)方法就無法實(shí)現(xiàn)l = [0, [1, 2, [3]], [4, 5], [6], [7, 8], [9]]# 能夠同時(shí)解決如上問題的方法是使用遞歸函數(shù)def flatten_list(l):
flat_list = []
for item in l:
if type(item) == list:
flat_list.extend(flatten_list(item))
else:
flat_list.append(item)
return flat_listprint(flatten_list(l))
23.列表當(dāng)中數(shù)據(jù)類型的轉(zhuǎn)換
我們要將其轉(zhuǎn)換成整數(shù)類型====>['1', '2', '3']
我們要將其轉(zhuǎn)換成浮點(diǎn)數(shù)類型====>['1', 2, '3.0', 4.0, '5', 6]
答:
l = ['1', '2', '3']l1 = [int(i) for i in l]print(l1)l2 = ['1', 2, '3.0', 4.0, '5', 6]l3 = [float(i) for i in l2]print(l3)
24.將列表轉(zhuǎn)化成字典
cars = ['Audi', 'BMW', 'Ford', 'Tesla', 'Volvo']
答:
cars = ['Audi', 'BMW', 'Ford', 'Tesla', 'Volvo']d = dict.fromkeys(cars, 0)print(d)
25.將列表當(dāng)中的重復(fù)元素去除
['a', 'a', 'b', 'a', 'c']
答:
l = ['a', 'a', 'b', 'a', 'c']l1 = list(set(l))print(l1)
26.從列表中篩選出特定元素 (2種方法)
cars = ['Audi', 'BMW', 'Ford', 'Tesla', 'Volvo']
答:
cars = ['Audi', 'BMW', 'Ford', 'Tesla', 'Volvo']# 我想到的是列表推導(dǎo)式l = [i for i in cars if i == 'Volvo']print(l)# 標(biāo)答使用filterl2 = filter(lambda car: car == 'Volvo', cars)print(list(l2))# filter 函數(shù)在 Python 中返回一個(gè)過濾器對(duì)象,,它是一個(gè)迭代器,所以想打印值需要使用list()
27.列表中的元素排序
numbers = [55, -30, 28, -36, 48, 20]
cars = ['Ford', 'Tesla', 'BMW', 'Volvo', 'Audi']
答:
numbers.sort()print(numbers)cars.sort()print(cars)
28.合并集合
set1 = {'1', '2', '5'}
set2 = {'4', '6', '7'}
答:
set1.update(set2)print(set1)
29.根據(jù)鍵來對(duì)字典進(jìn)行排序
d = {'one': 1, 'three': 4, 'five': 8, 'six': 10, 'two': 2}
答:
sorted_dict = sorted(d.items(), key=lambda x: x[0])print(sorted_dict)
30.根據(jù)鍵值來對(duì)字典進(jìn)行排序
d = {'one': 1, 'three': 4, 'five': 8, 'six': 10, 'two': 2}
答:
sorted_dict = sorted(d.items(), key=lambda x: x[1])print(sorted_dict)
31.替換字符串
s = 'Python is a programming language. Python is awesome'# 字符類型是不可變數(shù)據(jù)類型,,str.replace()方法不會(huì)改變?cè)址?,?huì)生成新值ss = s.replace('P','p')print(ss)
32.計(jì)算指定字符串出現(xiàn)的次數(shù)
a = 'python is a programming language. python is python.'
答:
# 我得笨方法:d = {}for _ in a:
if _ not in d:
d[_] = 1
else:
d[_] += 1print(d['p'])# 標(biāo)答print(a.count('p'))
33.將矩陣轉(zhuǎn)置
a = [[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]
答:
b = [list(s) for s in zip(*a)]print(b)
34.生成斐波那契數(shù)列
斐波那契數(shù)列是一個(gè)數(shù)列,其中的每個(gè)數(shù)都是前兩個(gè)數(shù)的和,。
答:
def fibonacci(n):
if n <= 0:
return []
elif n == 1:
return [0, ]
elif n == 2:
return [0, 1]
else:
fib = [0, 1]
for i in range(2, n):
fib.append(fib[-1] + fib[-2])
return fibprint(fibonacci(10))-----------------------------------------------------[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
35.冒泡排序
def bubble(l):
for i in range(len(l) - 1):
for j in range(len(l) - 1 - i):
if l[j] > l[j + 1]:
l[j], l[j + 1] = l[j + 1], l[j]
return l
36.Python的解包是什么,?
解包是 Python 里的一種特殊賦值語句,可以把可迭代對(duì)象 (列表,,元祖,,字典,字符串) 一次性賦給多個(gè)值,。
a, b, c = (1, 2, 3)
a, b = b, a
numbers = [1, 2, 3, 4, 5]for a, b in zip(numbers, numbers[1:]):
print(a, b)---------------------------------------------------------1 22 33 44 5
注意:
普通變量解包,,需要注意變量數(shù)量和列表中元素?cái)?shù)量應(yīng)保持一致,否則報(bào)'SyntaxError: cannot assign to literal',;
如果可迭代對(duì)象是字典,,則變量個(gè)數(shù)要等于字典中的鍵值對(duì)個(gè)數(shù),若不指定字典的取值,,則默認(rèn)取字典的 key 值,,若指定字典的值為 items(),則變量為字典鍵值對(duì)的元組形式,;
37.有一個(gè)key為姓名,,value為年齡的字典,根據(jù)年齡正序排列姓名,,并輸出姓名列表,,若沒有年齡,則放在最后,;
users = {'tom': 19, 'jerry': 13, 'jack': None, 'andrew': 43}
答:
知識(shí)點(diǎn):在排序前將年齡為 None 的值變更為正無窮大,;
正無窮:float('inf')
負(fù)無窮:float('-inf')
# 我想到的方法:
# 先將字典中年齡為None的值變更成正無窮大def key_func(users):
for key in users.keys():
if users[key] is None:
users[key] = float('inf')# 根據(jù)年齡進(jìn)行正序排序,最后以列表形式輸入排序好的姓名def sort_user(user: dict):
sort_item_for_v = sorted(user.items(), key=lambda x: x[1])
return [user[0] for user in sort_item_for_v]key_func(users)print(sort_user(users))-------------------------------------------------------------------------------['jerry', 'tom', 'andrew', 'jack']
# 參考答案:def sort_user_inf(users: dict):
'''
接收一個(gè)key為姓名,value為年齡的字典,,根據(jù)年齡正序排列姓名,,若沒有年齡,則放在最后
:param users: 用戶名:年齡字典
:return: 返回姓名列表
'''
def key_func(username):
age = users[username]
# 當(dāng)年齡為空時(shí),,返回正無窮大作為key,,因此就會(huì)被排到最后 return age if age is not None else float('inf')
return sorted(users.keys(), key=key_func)print(sort_user_inf(users))-----------------------------------------------------------------------------['jerry', 'tom', 'andrew', 'jack']
38.合并字典的多種方式?
d1 = {'name': 'Lili', 'score': 90}d2 = {'name': 'Tom', 'hobby': 'run'}d1.update(d2)print(d1)-----------------------------{'name': 'Tom', 'score': 90, 'hobby': 'run'}# 這種方法會(huì)改變d1的原始值
d1 = {'name': 'Lili', 'score': 90}d2 = {'name': 'Tom', 'hobby': 'run'}def update_dict(d1: dict, d2: dict):
d = d1.copy()
d.update(d2)
return dprint(update_dict(d1,d2))print(d1)print(d2)---------------------------------------{'name': 'Tom', 'score': 90, 'hobby': 'run'}{'name': 'Lili', 'score': 90}{'name': 'Tom', 'hobby': 'run'}
d1 = {'name': 'Lili', 'score': 90}d2 = {'name': 'Tom', 'hobby': 'run'}print({**d1, **d2})print({**d2, **d1})print(d1)print(d2)--------------------------------------{'name': 'Tom', 'score': 90, 'hobby': 'run'}{'name': 'Lili', 'hobby': 'run', 'score': 90}{'name': 'Lili', 'score': 90}{'name': 'Tom', 'hobby': 'run'}
d1 = {'name': 'Lili', 'score': 90}d2 = {'name': 'Tom', 'hobby': 'run'}print(d1|d2)print(d2|d1)print(d1)print(d2)-----------------------------{'name': 'Tom', 'score': 90, 'hobby': 'run'}{'name': 'Lili', 'hobby': 'run', 'score': 90}{'name': 'Lili', 'score': 90}{'name': 'Tom', 'hobby': 'run'}
39.json和Python中的dict有什么區(qū)別,?
1.JSON 的類型是字符串,字典的類型是 dict,;
2.JSON 的 key 只能是字符串,,字典的 key 可以是任何可 hash 對(duì)象,如:字符串,,數(shù)字,,元祖;
3.JSON 的 key 是有序的,,可以重復(fù)的,;字典的 key 不能重復(fù);
4.JSON 的 key 有默認(rèn)值 undefined,,字典的 key 默認(rèn)沒有默認(rèn)值,;
5.JSON 的 value 可以是字符串、浮點(diǎn)數(shù),、布爾值,、null 或者他們組成的數(shù)組或?qū)ο螅值涞?value 可以是任意類型的對(duì)象,;
6.JSON 的 value 訪問方式可以是 [] 或者.,,字典的 value 訪問方式只能是 key 值;
7.JSON 的字符串強(qiáng)制使用雙引號(hào),,字典的字符串可以是單引號(hào)也可以是雙引號(hào),;
8.字典可以嵌套元祖,JSON 只有數(shù)組,;
9.真假空的表示:JSON(true,,false,null),,字典(True,,F(xiàn)alse,None),;
10.JSON 的中文必須是 Unicode 編碼,,如'\u6211'。
40.Python列表和字符串的相互轉(zhuǎn)換?
第一種類型:
s = '1,2,3,4,5'l = s.split(',')print(l)l2 = [int(i) for i in l]print(l2)--------------------['1', '2', '3', '4', '5'][1, 2, 3, 4, 5]
第二種類型:
l1 = ['1','2','3']s1 = ','.join(l1)print(s1)---------------1,2,3
第三種類型:
l2 = [1,2,3]s2 = ','.join([str(i) for i in l2])print(s2)-----------------------------1,2,3
作者以往文章: