本文為T(mén)esterHome社區(qū)同學(xué)耿曉分享的Python基礎(chǔ)系列文章:作者的話:
再梳理一遍Python系列知識(shí)點(diǎn),夯實(shí)基礎(chǔ),無(wú)他,唯手熟爾!
Python系列總結(jié)都是我自己平時(shí)的學(xué)習(xí)筆記,如果有不正確的地方,希望各位佬兒哥指正糾偏~
測(cè)試基礎(chǔ)-Python篇 基礎(chǔ)①
變量名命名規(guī)則 - 遵循PEP8原則
普通變量:max_value
全局變量:MAX_VALUE
內(nèi)部變量:_local_var
和關(guān)鍵字重名:class_
函數(shù)名:bar_function
類(lèi)名:FooClass
布爾類(lèi)型的變量名用 is,has 這類(lèi)詞語(yǔ)前綴
is_superuser
has_errors
allow_empty
釋義為數(shù)字的單詞
port
age
radius
以_id 為結(jié)尾的單詞
user_id
port_id
以 length/count 開(kāi)頭或結(jié)尾的詞
length_of_username
max_length
users_count
注:不要用名詞的復(fù)數(shù)形式來(lái)作為 int 類(lèi)型的變量名,因?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之后,可以使用類(lèi)型注解功能來(lái)注明變量類(lèi)型,在變量后添加類(lèi)型,并用冒號(hào)隔開(kāi);
def repeat_message(message: str, count: int) -> str:
return message * count
算術(shù)運(yùn)算符
不同類(lèi)型變量之間的計(jì)算
獲取輸入的信息-input
input 輸入的數(shù)據(jù)類(lèi)型都是字符串類(lèi)型
格式化輸出
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:
條件滿(mǎn)足時(shí),做的事情 1
條件滿(mǎn)足時(shí),做的事情 2
條件滿(mǎn)足時(shí),做的事情 3
……
while 條件 2:
條件滿(mǎn)足時(shí),做的事情 1
條件滿(mǎn)足時(shí),做的事情 2
條件滿(mǎn)足時(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)容;
語(yǔ)法格式如下:
print('*',end='')
轉(zhuǎn)義字符
列表
列表通過(guò)索引取值,列表索引從0開(kāi)始,且不能超過(guò)范圍;
len(列表)--獲取列表的長(zhǎng)度
列表.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(元組)與列表類(lèi)似,不同之處在于元組的 元素不能修改;
創(chuàng)建空元組:info_tuple = ()
元組中只包含一個(gè)元素時(shí),需要在元素后面添加逗號(hào):info_tuple = (50, )
len(元組)--獲取元組的長(zhǎng)度 n+1;
元組.count(數(shù)據(jù))--數(shù)據(jù)在元組中出現(xiàn)的次數(shù);
元組 [索引]--從元祖中取值;
元組.index(數(shù)據(jù))--獲取數(shù)據(jù)第一次出現(xiàn)的索引。
元組和列表之間的轉(zhuǎn)換
字典
Python3.6 之后的字典是有序的,如果解釋器版本沒(méi)有那么新,也可以使用 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ù)類(lèi)型,但鍵只能使用字符串、數(shù)字或元組;
字典.keys()--所有 key 列表;
字典.values()--所有 value 列表;
字典.items()--所有(key,value)元組列表;
字典 [key]--可以從字典中取值,key 不存在會(huì)報(bào)錯(cuò);
1.返回的數(shù)據(jù)類(lèi)型類(lèi)似列表,但不是真正意義的列表,沒(méi)有 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(字符串)--獲取字符串的長(zhǎng)度;
字符串.count(字符串)--小字符串在大字符串中出現(xiàn)的次數(shù);
字符串 [索引]--從字符串中取出單個(gè)字符;
字符串.index(字符串)--獲得小字符串第一次出現(xiàn)的索引;
string.istitle() | 如果 string 是標(biāo)題化的 (每個(gè)單詞的首字母大寫(xiě)) 則返回 True;
string.startswith(str) | 檢查字符串是否是以 str 開(kāi)頭,是則返回 True;
string.endswith(str) | 檢查字符串是否是以 str 結(jié)束,是則返回 True;
string.find(str, start=0, end=len(string)) | 檢測(cè) str 是否包含在 string 中,如果 start 和 end 指定范圍,則檢查是否包含在指定范圍內(nèi),如果是返回開(kāi)始的索引值,否則返回 -1
;
string.index(str, start=0, end=len(string)) | 跟 find() 方法類(lèi)似,不過(guò)如果 str 不在 string 會(huì)報(bào)錯(cuò);
string.replace(old_str, new_str, num=string.count(old)) | 把 string 中的 old_str 替換成 new_str,如果 num 指定,則替換不超過(guò) num 次;
string.capitalize() | 把字符串的第一個(gè)字符大寫(xiě);
string.title() | 把字符串的每個(gè)單詞首字母大寫(xiě);
string.lower() | 轉(zhuǎn)換 string 中所有大寫(xiě)字符為小寫(xiě);
string.upper() | 轉(zhuǎn)換 string 中的小寫(xiě)字母為大寫(xiě);
string.swapcase() | 翻轉(zhuǎn) string 中的大小寫(xiě);
字符串 - 切片
切片方法適用于字符串、列表、元組;
字符串 [開(kāi)始索引:結(jié)束索引:步長(zhǎng)];
切片:正反向索引(正:從 0 開(kāi)始,反:從-1 開(kāi)始)
切片索引:[start
step]
start:開(kāi)始截取的位置,包含在截取內(nèi)容內(nèi)
end:結(jié)束截取的位置,結(jié)束截取的位置并不包含
step:截取的步長(zhǎng),默認(rèn)值為 1
step:為正,表示從左到右進(jìn)行截取,start 必須在 end 之前(從左開(kāi)始算前,下標(biāo)必須從左到右)
step:為負(fù),表示從右到左進(jìn)行截取,start 必須在 end 之前(從右開(kāi)始算前,下標(biāo)必須從右到左)
s = 'hello,world'
print(s[:]) # 取全部
print(s[1:]) # 從第 2 位取到最后
print(s[:-1]) # 從開(kāi)始取到倒數(shù)第二位
print(s[::2]) # 步長(zhǎng)為 2
print(s[::-1]) # 反序
指定的區(qū)間屬于左閉右開(kāi)型 [開(kāi)始索引, 結(jié)束索引) => 開(kāi)始索引 >= 范圍 < 結(jié)束索引
從 起始位開(kāi)始,到 結(jié)束位的前一位 結(jié)束(不包含結(jié)束位本身)
從頭開(kāi)始,開(kāi)始索引 數(shù)字可以省略,冒號(hào)不能省略
到末尾結(jié)束,結(jié)束索引 數(shù)字可以省略,冒號(hào)不能省略
步長(zhǎng)默認(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}的成績(jī)是{1}'.format(username, sore))
集合
集合是一個(gè)無(wú)序的可變?nèi)萜黝?lèi)型,他最大的特點(diǎn)就是成員不能重復(fù)
要初始化一個(gè)空集合只能調(diào)用 set() 方法,因?yàn)閧}表示的是一個(gè)空字典,而不是一個(gè)空集合
集合也有自己的推導(dǎo)式-nums = {n for n in range(10) if n % 2 == 0}
集合是可變類(lèi)型,可以通過(guò).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ì)象是一定的,比如說(shuō)在一個(gè)固定的字符串或列表中進(jìn)行循環(huán),那么最好使用 for
什么時(shí)候用 while:當(dāng)循環(huán)次數(shù)不是一定的,只是滿(mǎn)足某個(gè)條件時(shí)才進(jìn)行循環(huán),那么最好使用 while
沒(méi)有 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))
類(lèi)
類(lèi)定義
類(lèi)方法
實(shí)例方法
1、只能通過(guò)對(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ì)定義
類(lèi)方法
1、可以直接通過(guò)類(lèi)名調(diào)用的方法,也可以通過(guò)實(shí)例調(diào)用
2、類(lèi)方法必須通過(guò)@classmethod裝飾器進(jìn)行裝飾
3、所有的類(lèi)方法第一個(gè)參數(shù)必須是 cls
4、類(lèi)方法不能訪問(wèn)實(shí)例屬性,只能訪問(wèn)類(lèi)屬性
屬性方法
使用場(chǎng)景:屬性方法對(duì)應(yīng)的屬性的值無(wú)法直接確定,要通過(guò)一系列的操作才能得到這個(gè)值,而且用戶(hù)不關(guān)心這個(gè)操作過(guò)程,只想得到這個(gè)值。
定義:當(dāng)成屬性使用的方法,調(diào)用屬性方法時(shí)不需要加 ()
靜態(tài)方法
1、通過(guò)@staticmethod裝飾器來(lái)進(jìn)行裝飾的方法
2、靜態(tài)方法既不能訪問(wèn)實(shí)例屬性,也不能訪問(wèn)類(lèi)屬性
3、可以通過(guò)類(lèi)名直接調(diào)用,也可以通過(guò)對(duì)象調(diào)用
類(lèi)的三大特征
類(lèi)的反射
反射原理
通過(guò)字符串的形式在運(yùn)行時(shí)動(dòng)態(tài)修改程序的變量、方法及屬性,所有的修改都在內(nèi)存中進(jìn)行,所以他并不會(huì)實(shí)際修改代碼,主要目的就是提高代碼在運(yùn)行時(shí)的靈活性;
反射相關(guān)的方法
hasattr 輸入一個(gè)字符串,判斷對(duì)象有沒(méi)有這個(gè)方法或?qū)傩裕?br>getattr 獲取對(duì)象屬性值或方法的引用,如果是方法,則返回方法的引用,如果是屬性,則返回屬性的值,如果該方法或?qū)傩圆淮嬖?,則拋出異常;
setattr 動(dòng)態(tài)添加一個(gè)方法或?qū)傩裕?br>delattr 動(dòng)態(tài)刪除一個(gè)方法或?qū)傩浴?/span>
異常處理
Python 異常處理依賴(lài)的關(guān)鍵字:
try
except
else
finally
try
try 塊里面放置所有可能引起異常的代碼,一個(gè)異常處理塊里面只能有一個(gè) try;
except
放置要處理的異常類(lèi)型和相應(yīng)語(yǔ)句塊,用于表明該 except 要處理的異常類(lèi)型;
一個(gè)異常處理塊里面可以跟 1 到 n 個(gè) except 塊;
每個(gè) except 塊后面可以跟 1 到 n 個(gè)異常類(lèi)型,也可以不跟任何異常類(lèi)型;
else
如果 try 塊里面的語(yǔ)句沒(méi)有引起異常,則會(huì)運(yùn)行 else 里面的語(yǔ)句;
finally
主要用于回收再 try 塊里面打開(kāi)的物理資源,異常處理機(jī)制會(huì)保證 finally 塊一定會(huì)被執(zhí)行;
異常處理語(yǔ)法結(jié)構(gòu)
1.只有 try 是必須的
2.如果沒(méi)有 try,就不能有 except 和 finally
3.except 塊和 finally 塊都是可選的,但 except 和 finally 必須出現(xiàn)其中之一,也可以同時(shí)出現(xiàn)
4.可以有多個(gè) except 塊,但捕獲父類(lèi)異常的 except 塊要寫(xiě)在捕獲子類(lèi)異常的 except 塊的后面
5.多個(gè) except 塊必須位于 try 塊之后,finally 塊必須位于所有塊的最后
IO 讀寫(xiě) - 文本文件
open (path,mode)
默認(rèn)是 r:只讀模式,文件必須事先存在,不主動(dòng)生成文件,從文件開(kāi)頭開(kāi)始讀;
r+:讀寫(xiě)模式,文件也必須事先存在,不主動(dòng)生成文件,從文件開(kāi)頭開(kāi)始讀或?qū)懀?br>w:只寫(xiě)模式,如果用 w 模式打開(kāi),一律會(huì)清空之前文件的所有內(nèi)容,如果文件不存在,則自動(dòng)創(chuàng)建文件,從頭開(kāi)始寫(xiě);
w+:讀寫(xiě)模式,也會(huì)清空之前文件的所有內(nèi)容,如果文件不存在,則自動(dòng)創(chuàng)建文件,從頭開(kāi)始寫(xiě);
a:追加模式,只寫(xiě),不會(huì)清空以前文件的內(nèi)容,主動(dòng)生成文件,從文件尾開(kāi)始寫(xiě)入;
a+:追加模式,讀和寫(xiě),不會(huì)清空以前文件的內(nèi)容,主動(dòng)生成文件,從文件尾開(kāi)始寫(xiě)入或讀?。?br>二進(jìn)制讀寫(xiě),一般用于圖片或音視頻:rb+,wb+,ab+;
查看和設(shè)置文件指針位置:
with open('user.txt', 'a+') as f:
# 將文件指針重置至開(kāi)始位置(這樣就不會(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)行起來(lái),進(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 類(lèi)的構(gòu)造器創(chuàng)建線程對(duì)象。在創(chuàng)建線程對(duì)象時(shí)使用 target 參數(shù)指定函數(shù)線程的執(zhí)行體;
2.調(diào)用線程對(duì)象的 start() 方法啟動(dòng)線程;
通過(guò) 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ù)競(jìng)爭(zhēng)問(wèn)題。這意味著即使使用多核 CPU,Python 程序也不能充分利用多核優(yōu)勢(shì)。GIL 在性能上可能帶來(lái)一定的影響,因此不適合處理需要大量的 CPU 運(yùn)算的任務(wù)。
什么條件下會(huì)釋放 GIL:
當(dāng)前活躍線程遇到 IO 等待,比如要訪問(wèn)網(wǎng)絡(luò)或建立數(shù)據(jù)庫(kù)鏈接等情況;
活躍線程執(zhí)行了 100 個(gè)字節(jié)碼的程序后,GIL 也會(huì)釋放該線程的鎖,然后與其他線程參與競(jìng)爭(zhēng);
python 的多線程適合場(chǎng)景:
python 的多線程只適合于 IO 密集型應(yīng)用,對(duì)于計(jì)算密集型的應(yīng)用最好使用多進(jìn)程或協(xié)程的方式解決;
可迭代對(duì)象
迭代器
任何實(shí)現(xiàn)了iter和next方法的對(duì)象都是迭代器(這兩個(gè)方法必須同時(shí)實(shí)現(xiàn));
其中iter會(huì)返回迭代器本身;
next會(huì)返回迭代器中的下一個(gè)元素,如果沒(méi)有元素了將拋出 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è)迭代器的被迭代過(guò)程是一次性的,可迭代對(duì)象則不一定
生成器
特殊的迭代器,只需要使用 yield 關(guān)鍵字,那么就會(huì)立即變?yōu)橐粋€(gè)生成器,也就是說(shuō),只要一個(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 語(yǔ)句處開(kāi)始執(zhí)行后面的語(yǔ)句;
生成器的 send 方法可以向函數(shù)體內(nèi)去傳遞值;
對(duì)于 next 和 send 方法的異同:
next 和 send 都可以去調(diào)用一次生成器,從調(diào)用生成器的角度來(lái)說(shuō),他們的作用完全一樣;
next 無(wú)法像生成器內(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ù)添加特定的附加功能;
編寫(xiě)裝飾器的原則
裝飾器一定不能修改被裝飾器的函數(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í)
通過(guò) def 關(guān)鍵字在一個(gè)函數(shù) A 中去定義另外一個(gè)函數(shù) B,則函數(shù) B 稱(chēng)為嵌套函數(shù);
4.裝飾器=高階函數(shù) + 嵌套函數(shù)
了解裝飾器的本質(zhì)優(yōu)勢(shì)
1.運(yùn)行時(shí)校驗(yàn):在執(zhí)行階段進(jìn)行特定校驗(yàn),當(dāng)校驗(yàn)不通過(guò)時(shí)終止執(zhí)行:
Django 框架中的用戶(hù)登錄態(tài)校驗(yàn)裝飾器@login_required;
2.注入額外參數(shù):在函數(shù)被調(diào)用時(shí)自動(dòng)注入額外的調(diào)用參數(shù):
unittest.mock 模塊的裝飾器@patch;
3.緩存執(zhí)行結(jié)果:通過(guò)調(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ì)象,比如類(lèi)實(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á)式在任何語(yǔ)言中都占有很大部分的占比,但正則表達(dá)式相關(guān)的知識(shí)點(diǎn)又過(guò)于零碎,對(duì)于榆木腦袋的我真是學(xué)一遍忘一遍。在實(shí)際工作中,我自己真正用到正則的地方并不多,再看同事,目前就發(fā)現(xiàn)前端同學(xué)有可能會(huì)用到正則去做一些事情,并且用到的時(shí)候都是度娘,一是自己真記不住,二是度娘 copy 過(guò)來(lái)的多數(shù)情況是比自己寫(xiě)要嚴(yán)謹(jǐn)?shù)亩嗟摹?/span>
基于此,我把正則視為投入產(chǎn)出比太低的事情,僅需要記住個(gè)大概印象,真到用時(shí)能分清度娘上哪個(gè)輪子能用哪個(gè)輪子用不了就可以了。
測(cè)試基礎(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)) # 開(kāi)平方,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ù)寫(xiě)出 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 庫(kù)是非常常用的記錄日志庫(kù),通過(guò) 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ā)問(wèn)題需要注意的是:為了避免并發(fā)問(wèn)題,絕不讓多個(gè)線程讀取或?qū)懭胂嗤兞?。?dāng)創(chuàng)建一個(gè)新的 Thread 對(duì)象時(shí),要確保其目標(biāo)函數(shù)只使用該函數(shù)中的局部變量。
線程阻塞-thread.join()
thread.join() 方法的作用是阻塞當(dāng)前線程,直到調(diào)用 join() 方法的線程結(jié)束。也就是說(shuō),如果你有多個(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ù),意為最長(zhǎng)暫用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ù)類(lèi)型(如整型,字符串等)在 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ù)類(lèi)型,淺拷貝只拷貝第一層中的引用,深拷貝在拷貝時(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)'=':如果是可變類(lèi)型,就是引用傳遞;如果是不可變類(lèi)型,就是值傳遞。
淺拷貝的優(yōu)點(diǎn):拷貝速度快,占用空間少,拷貝效率高。
因?yàn)闇\拷貝不能解決嵌套問(wèn)題,所以引出了深拷貝,深拷貝會(huì)遍歷并拷貝 items 里所有的內(nèi)容 - 包括他嵌套的子列表;
對(duì)象的可哈希性
不可變的內(nèi)置類(lèi)型都是可哈希的,比如 str、int、float、frozenset
可變的內(nèi)置類(lèi)型都是不可以哈希的,比如 list、dict
對(duì)于不可變?nèi)萜黝?lèi)型(tuple、frozenset),僅當(dāng)他的所有成員都不可變時(shí),他自身才是可哈希的
用戶(hù)定義的類(lèi)型默認(rèn)都是可哈希的
注意:只有可哈希對(duì)象才能被放進(jìn)集合或者作為字典的鍵
sorted() 函數(shù)
sorted 函數(shù)是 Python 內(nèi)置函數(shù),用于對(duì)可迭代對(duì)象進(jìn)行排序,并返回一個(gè)新的列表。
注意:sorted 函數(shù)不會(huì)改變?cè)瓉?lái)的可迭代對(duì)象,而是返回一個(gè)新的列表。如果需要改變?cè)瓉?lái)的可迭代對(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 開(kāi)始
測(cè)試基礎(chǔ)-Python篇 基礎(chǔ)③
浮點(diǎn)數(shù)精度問(wèn)題
print(0.1+0.2)----------------------0.30000000000000004
可以使用 decimal 模塊解決浮點(diǎn)數(shù)精度問(wèn)題:
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í)要用字符串來(lái)表示數(shù)字
布爾值其實(shí)也是數(shù)字
布爾類(lèi)型其實(shí)是整型的子類(lèi)型
True 和 False 這兩個(gè)布爾值可以直接當(dāng)做 1 和 0 來(lái)使用
通過(guò)這個(gè)特點(diǎn),最常用于統(tǒng)計(jì)總數(shù)
def sum_even(numbers: list[int]):
'''
返回numbers中偶數(shù)的個(gè)數(shù)
:param numbers: 整數(shù)列表
'''
return sum(i % 2 == 0 for i in numbers)
不常用但特別好用的字符串方法
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)。
使用枚舉類(lèi)型來(lái)替代字面量
# 用戶(hù)每日獎(jiǎng)勵(lì)積分?jǐn)?shù)量DAILY_POINTS_REWARDS = 100# VIP用戶(hù)額外獎(jiǎng)勵(lì)20VIP_EXTRA_POINTS = 20from enum import Enumclass UserType(int, Enum):
# VIP用戶(hù) VIP = 3
# 小黑屋用戶(hù) BANNED = 13def add_daily_points(user):
'''用戶(hù)每天第一次登錄增加積分'''
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è)問(wèn)題,當(dāng)item過(guò)大時(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ì)象過(guò)期了,就中斷當(dāng)前的所有處理 if processed_item.has_expired():
break
面向?qū)ο缶幊?/strong>
內(nèi)置類(lèi)方法裝飾器
類(lèi)方法
1.用 def 在類(lèi)里定義一個(gè)函數(shù)時(shí),這個(gè)函數(shù)通常被稱(chēng)作方法。調(diào)用這個(gè)方法需要先創(chuàng)建一個(gè)類(lèi)實(shí)例;
2.可以使用@classmethod裝飾器定義類(lèi)方法,它屬于類(lèi),無(wú)需實(shí)例化也能調(diào)用;
3.作為一種特殊方法,類(lèi)方法最常見(jiàn)的使用場(chǎng)景,就是定義工廠方法來(lái)生成新實(shí)例,類(lèi)方法的主角是類(lèi)型本身,當(dāng)發(fā)現(xiàn)某個(gè)行為不屬于實(shí)例,而是屬于整個(gè)類(lèi)型是,可以考慮使用類(lèi)方法;
靜態(tài)方法
1.如果發(fā)現(xiàn)某個(gè)方法不需要使用當(dāng)前實(shí)例里的任何內(nèi)容,那可以使用@staticmethod來(lái)定義一個(gè)靜態(tài)方法;
2.和普通方法相比,靜態(tài)方法不需要訪問(wèn)實(shí)例的任何狀態(tài),是一種與狀態(tài)無(wú)關(guān)的方法,因此靜態(tài)方法其實(shí)可以寫(xiě)成脫離于類(lèi)的外部普通函數(shù);
2.1.如果靜態(tài)方法特別通用,與類(lèi)關(guān)系不大,那么把他改成普通函數(shù)會(huì)更好;
2.2.如果靜態(tài)方法與類(lèi)關(guān)系密切,那么用靜態(tài)方法更好;
2.3.相比函數(shù),靜態(tài)方法有一些先天優(yōu)勢(shì),比如能被子類(lèi)繼承和重寫(xiě);
屬性裝飾器
1.@property 裝飾器模糊了屬性和方法間的界限,使用它,可以把方法通過(guò)屬性的方式暴露出來(lái);
2.@property 除了可以定義屬性的讀取邏輯外,還支持自定義寫(xiě)入和刪除邏輯;
class FilePath:
@property
def basename(self):
....
@property.setter
def basename(self, name):
....
@property.deleter
def basename(self):
....
經(jīng)過(guò)@property的裝飾以后,basename 已經(jīng)從一個(gè)普通的方法變成了 property 對(duì)象,所以可以使用 basename.setter 和 basename.deleter 方法;
定義 setter 方法,該方法會(huì)在對(duì)屬性賦值是被調(diào)用;
定義 deleter 方法,該方法會(huì)在刪除屬性時(shí)被調(diào)用;
鴨子類(lèi)型及其局限性
在鴨子類(lèi)型編程風(fēng)格下,如果想操作某個(gè)對(duì)象,你不會(huì)去判斷他是否屬于某種類(lèi)型,而會(huì)直接判斷他是不是有你需要的方法 (或?qū)傩?。或者更激進(jìn)一些。你甚至?xí)苯訃L試調(diào)用需要的方法,假如失敗了,那就讓她報(bào)錯(cuò)好了;
鴨子類(lèi)型的優(yōu)點(diǎn)就是編寫(xiě)簡(jiǎn)單,使用靈活;
鴨子類(lèi)型的缺點(diǎn)就是缺乏標(biāo)準(zhǔn)、過(guò)于隱式;
可以使用類(lèi)型注解、靜態(tài)檢查 (mypy)、抽象類(lèi)來(lái)補(bǔ)充鴨子類(lèi)型;
抽象類(lèi)
isinstance() 函數(shù)
利用 isinstance() 函數(shù),我們可以判斷對(duì)象是否屬于特定類(lèi)型;
isinstance() 函數(shù)能理解類(lèi)之間的繼承關(guān)系,因此子類(lèi)的實(shí)例同樣可以通過(guò)基類(lèi)的校驗(yàn);
校驗(yàn)對(duì)象是否是 Iterable 類(lèi)型
在 collections.abc 模塊中,有許多和容器相關(guān)的抽象類(lèi),比如代表集合的 Set、代表序列的 Sequence 等,其中有一個(gè)最簡(jiǎn)單的抽象類(lèi):Iterable,他表示的是可迭代類(lèi)型;
鴨子類(lèi)型和抽象類(lèi)總結(jié)
鴨子類(lèi)型是一種編碼風(fēng)格,在這種風(fēng)格下,代碼只關(guān)心對(duì)象的行為,不關(guān)心對(duì)象的類(lèi)型;
鴨子類(lèi)型降低了類(lèi)型校驗(yàn)的成本,讓代碼變得更靈活;
傳統(tǒng)的鴨子類(lèi)型里,各種對(duì)象接口和協(xié)議都是隱式的,沒(méi)有統(tǒng)一的顯示標(biāo)準(zhǔn);
傳統(tǒng)的 isinstance() 類(lèi)型檢查和鴨子類(lèi)型的理念是相違背的;
抽象類(lèi)是一種特殊的類(lèi),他可以通過(guò)鉤子方法來(lái)定制動(dòng)態(tài)的子類(lèi)檢查行為;
因?yàn)槌橄箢?lèi)的定制子類(lèi)化特征,isinstance() 也變得更靈活、更契合鴨子類(lèi)型了;
使用@abstractmethod裝飾器,抽象類(lèi)可以強(qiáng)制要求子類(lèi)在繼承時(shí)重寫(xiě)特定方法;
除了抽象方法外,抽象類(lèi)也可以實(shí)現(xiàn)普通的基礎(chǔ)方法,供子類(lèi)繼承使用;
在 collections.abc 模塊中,有許多與容器相關(guān)的抽象類(lèi);
多重繼承于MRO
Python 里的一個(gè)類(lèi)可以同時(shí)繼承多個(gè)父類(lèi);
調(diào)用類(lèi)的 mro() 方法,可以看到按 MRO 算法排好序的基類(lèi)列表;
在許多人印象中。super() 是一個(gè)用來(lái)調(diào)用父類(lèi)方法的工具函數(shù)。但這么說(shuō)并不準(zhǔn)確,super() 使用的其實(shí)不是當(dāng)前類(lèi)的父類(lèi),而是當(dāng)前類(lèi)在 MRO 鏈條上的上一個(gè)類(lèi);
應(yīng)該避免多重繼承;
學(xué)習(xí)建議
對(duì)于Python入門(mén)及進(jìn)階,我推薦兩本我認(rèn)為值得多次閱讀的書(shū)籍:
其他瑣碎但十分實(shí)用的知識(shí)點(diǎn)
for......else......的執(zhí)行順序:
當(dāng)?shù)鷮?duì)象完成所有迭代后且此時(shí)的迭代對(duì)象為空時(shí),如果存在 else 子句則執(zhí)行 else 子句,沒(méi)有則繼續(xù)執(zhí)行后續(xù)代碼;如果迭代對(duì)象因?yàn)槟撤N原因(如帶有 break 關(guān)鍵字)提前退出迭代,則 else 子句不會(huì)被執(zhí)行,程序?qū)?huì)直接跳過(guò) 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ù)類(lèi)型 set 取值
因?yàn)榧希╯et)是一種無(wú)序的不重復(fù)的元素的集合。因?yàn)榧现械脑貨](méi)有特定的順序,所以無(wú)法通過(guò)下標(biāo)索引來(lái)訪問(wèn)。
可以使用循環(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]
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)# 通過(guò)屬性名來(lái)使用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行讀取,那我們按照以上的寫(xiě)法應(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ì),一寫(xiě)就廢”,為了更有針對(duì)性的加深知識(shí)點(diǎn)的印象,接下來(lái),我將以做題的形式繼續(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(wú)序,所以是隨機(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ù)類(lèi)型,所以不能不能在原元祖新增
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ù)類(lèi)型,并標(biāo)出哪些是不可變數(shù)據(jù)類(lèi)型?
整形-int-不可變、浮點(diǎn)型-float-不可變、字符型-str-不可變、列表-list-可變、元祖-tuple-不可變、字典-dict-可變
5.請(qǐng)說(shuō)明循環(huán)結(jié)構(gòu)和異常處理中的 else 在什么情況下會(huì)執(zhí)行?
在 for.else 循環(huán)結(jié)構(gòu)中,當(dāng)循環(huán)提全部循環(huán)完畢后,沒(méi)有 break 或者 return 的情況下,會(huì)執(zhí)行 else 代碼段;
在異常處理中,try 下的代碼段沒(méi)有出現(xiàn)異常的情況下,會(huì)執(zhí)行 else 代碼
條件分支語(yǔ)句用 else 來(lái)表示'否則執(zhí)行某件事'
6.列舉python函數(shù)定義中有哪些不同的參數(shù)類(lèi)型?
1.位置參數(shù):根據(jù)參數(shù)在函數(shù)定義中的位置來(lái)確定。
2.默認(rèn)參數(shù):在函數(shù)定義中指定的參數(shù)值。
3.關(guān)鍵字參數(shù):在調(diào)用函數(shù)時(shí)指定參數(shù)名稱(chēng)和對(duì)應(yīng)的值。
4.星號(hào)參數(shù):在函數(shù)定義中使用來(lái)捕獲剩余的參數(shù)。
5.雙星號(hào)參數(shù):在函數(shù)定義中使用* 來(lái)捕獲剩余的關(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)說(shuō)明if name == 'main':語(yǔ)句的作用?
在 Python 中,當(dāng)一個(gè)模塊被執(zhí)行時(shí),if name == 'main':語(yǔ)句塊會(huì)被執(zhí)行。此語(yǔ)句塊可以用來(lái)測(cè)試模塊的代碼,而不會(huì)影響模塊的其他功能。
如果模塊被其他模塊導(dǎo)入,則name的值為該模塊的名稱(chēng),而不是main。如果該模塊是主程序,則name的值為main,此時(shí)該語(yǔ)句塊會(huì)被執(zhí)行。
這樣的語(yǔ)句使得可以在模塊被其他模塊導(dǎo)入時(shí)忽略測(cè)試代碼,并且只在模塊被獨(dú)立運(yùn)行時(shí)執(zhí)行測(cè)試代碼。
10.面向?qū)ο缶幊逃心娜筇匦???qǐng)說(shuō)明各個(gè)特性的意義。
封裝:隱藏內(nèi)部狀態(tài)和實(shí)現(xiàn)細(xì)節(jié),僅提供必要的接口給外部使用。
繼承:允許創(chuàng)建新的對(duì)象類(lèi)型,并基于現(xiàn)有的對(duì)象類(lèi)型派生,從而繼承其行為和狀態(tài)。
多態(tài):允許不同類(lèi)型的對(duì)象對(duì)相同消息做出不同的響應(yīng)。
11.類(lèi)反射中常用的方法及含義?
常用的類(lèi)反射方法有:
type(object):獲取對(duì)象的類(lèi)型,返回一個(gè) type 對(duì)象。
isinstance(object, classinfo):判斷對(duì)象是否是某種類(lèi)型的實(shí)例,返回布爾值。
issubclass(class, classinfo):判斷一個(gè)類(lèi)是否是另一個(gè)類(lèi)的子類(lèi),返回布爾值。
getattr(object, name[, default]):獲取對(duì)象的屬性或方法,如果不存在,可以返回 default 參數(shù)指定的默認(rèn)值。
hasattr(object, name):判斷對(duì)象是否具有某個(gè)屬性或方法,返回布爾值。
setattr(object, name, value):設(shè)置對(duì)象的屬性值。
delattr(object, name):刪除對(duì)象的屬性。
使用類(lèi)反射可以動(dòng)態(tài)地獲取和操作類(lèi)的信息,是動(dòng)態(tài)語(yǔ)言的重要特性。
12.python中創(chuàng)建一個(gè)新線程有哪幾種方式?
1.使用 threading 模塊:通過(guò)定義一個(gè)繼承自 Thread 的類(lèi)并重寫(xiě)其 run 方法,然后通過(guò)該類(lèi)的實(shí)例調(diào)用 start 方法啟動(dòng)線程。
2.使用 multiprocessing 模塊:通過(guò)使用 Process 類(lèi)創(chuàng)建新的進(jìn)程。
3.使用協(xié)程:通過(guò)使用生成器實(shí)現(xiàn)協(xié)程,在協(xié)程內(nèi)部通過(guò) yield 實(shí)現(xiàn)非阻塞的多任務(wù)執(zhí)行。
多線程編程是高并發(fā)編程的一種常見(jiàn)形式,可以提高程序的執(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 中開(kāi)發(fā) CPU 密集型的多線程程序??梢允褂枚噙M(jìn)程來(lái)代替多線程以提高性能。
14.描述編寫(xiě)裝飾器的原則是什么?
1.不改變?cè)瘮?shù)的內(nèi)部邏輯
2.不改變?cè)瘮?shù)的調(diào)用方法
15.現(xiàn)在有一個(gè)Animal類(lèi)有初始化方法定義如下:
class Animal:
def init(self, skin, legs):
self.skin = skin
self.legs = legs
如果現(xiàn)在想定義一個(gè)Dog類(lèi),并繼承于這個(gè)Animal類(lèi),并想給這個(gè)Dog類(lèi)增加一個(gè)nickname對(duì)象屬性,Dog類(lèi)的初始化方法應(yīng)該怎么定義才能保證 Dog 類(lèi)和其父類(lèi)均能初始化成功?
# 兩種寫(xiě)法,第二種以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 中的一種特殊方法,用于引用父類(lèi)。它常用于多重繼承,當(dāng)子類(lèi)需要調(diào)用父類(lèi)的方法時(shí),就可以使用 super 方法。這個(gè)方法可以直接調(diào)用父類(lèi)的方法,而無(wú)需顯式命名父類(lèi)名稱(chēng)。
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.編寫(xiě)一個(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)中長(zhǎng)度最長(zhǎ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(),這樣比較的就是字符串的長(zhǎng)度,而不是字典序。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ù)是空列表,表示從空列表開(kāi)始計(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ì)此題目,一旦題目列表沒(méi)這么規(guī)范,比如下面的列表,那么如上3個(gè)方法就無(wú)法實(shí)現(xiàn)l = [0, [1, 2, [3]], [4, 5], [6], [7, 8], [9]]# 能夠同時(shí)解決如上問(wèn)題的方法是使用遞歸函數(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ù)類(lèi)型的轉(zhuǎn)換
我們要將其轉(zhuǎn)換成整數(shù)類(lèi)型====>['1', '2', '3']
我們要將其轉(zhuǎn)換成浮點(diǎn)數(shù)類(lèi)型====>['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è)過(guò)濾器對(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ù)鍵來(lái)對(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ù)鍵值來(lái)對(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'# 字符類(lèi)型是不可變數(shù)據(jù)類(lèi)型,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 里的一種特殊賦值語(yǔ)句,可以把可迭代對(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ù)年齡正序排列姓名,并輸出姓名列表,若沒(méi)有年齡,則放在最后;
users = {'tom': 19, 'jerry': 13, 'jack': None, 'andrew': 43}
答:
知識(shí)點(diǎn):在排序前將年齡為 None 的值變更為正無(wú)窮大;
# 我想到的方法:
# 先將字典中年齡為None的值變更成正無(wú)窮大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ù)年齡正序排列姓名,若沒(méi)有年齡,則放在最后
:param users: 用戶(hù)名:年齡字典
:return: 返回姓名列表
'''
def key_func(username):
age = users[username]
# 當(dāng)年齡為空時(shí),返回正無(wú)窮大作為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 的類(lèi)型是字符串,字典的類(lèi)型是 dict;
2.JSON 的 key 只能是字符串,字典的 key 可以是任何可 hash 對(duì)象,如:字符串,數(shù)字,元祖;
3.JSON 的 key 是有序的,可以重復(fù)的;字典的 key 不能重復(fù);
4.JSON 的 key 有默認(rèn)值 undefined,字典的 key 默認(rèn)沒(méi)有默認(rèn)值;
5.JSON 的 value 可以是字符串、浮點(diǎn)數(shù)、布爾值、null 或者他們組成的數(shù)組或?qū)ο螅值涞?value 可以是任意類(lèi)型的對(duì)象;
6.JSON 的 value 訪問(wèn)方式可以是 [] 或者.,字典的 value 訪問(wèn)方式只能是 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)換?
第一種類(lèi)型:
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]
第二種類(lèi)型:
l1 = ['1','2','3']s1 = ','.join(l1)print(s1)---------------1,2,3
第三種類(lèi)型:
l2 = [1,2,3]s2 = ','.join([str(i) for i in l2])print(s2)-----------------------------1,2,3
作者以往文章: