日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

長文總結(jié) | Python基礎(chǔ)知識點,建議收藏

 520jefferson 2023-02-15 發(fā)布于北京

來源:TesterHome社區(qū)

作者:耿曉

圖片

本文為TesterHome社區(qū)同學耿曉分享的Python基礎(chǔ)系列文章:

作者的話:

再梳理一遍Python系列知識點,夯實基礎(chǔ),無他,唯手熟爾!

Python系列總結(jié)都是我自己平時的學習筆記,如果有不正確的地方,希望各位佬兒哥指正糾偏~

測試基礎(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
    注:不要用名詞的復數(shù)形式來作為 int 類型的變量名,因為名詞的負數(shù)形式更像是一個容器。建議使用 number_of_apples 或 trips_count;

  • 超短命名
    數(shù)組索引三劍客 i、j、k
    某個整數(shù) n
    某個字符串 s
    某個異常 e
    文件對象 fp

變量注解

在Python3.5之后,可以使用類型注解功能來注明變量類型,在變量后添加類型,并用冒號隔開;

def repeat_message(message: str, count: int) -> str:
   return message * count

算術(shù)運算符

  • // 取整除

  • % 取余

  • ** 冪

不同類型變量之間的計算

  • 數(shù)字型變量之間可以直接計算;

  • 如果變量是 bool 型,在計算時,true 對應的是1,false 對應的是0;

  • 字符串變量之間使用 + 拼接字符串。

獲取輸入的信息-input

  • 字符串變量 = input('提示信息')

input 輸入的數(shù)據(jù)類型都是字符串類型

格式化輸出

  • %s --字符串

  • %d --有符號十進制整數(shù),%06d 表示輸出的整數(shù)顯示位數(shù),不足的地方使用 0 補全

  • %f --浮點數(shù),%.2f 表示小數(shù)點后只顯示兩位,會四舍五入

  • %% --輸出%

vb1 = 'Tom'print('hello %s' % vb1)vb2 = 5print('有符號十進制整數(shù):%d' % vb2)print('輸出顯示位數(shù)的整數(shù):%06d' % vb2)vb3 = 3.1415926print('保留兩位小數(shù):%.2f' % vb3)print('保留三位小數(shù):%.3f' % vb3)vb4 = 80print('正確率為:%d%%' % vb4)--------------------------------------------------------------------hello Tom有符號十進制整數(shù):5輸出顯示位數(shù)的整數(shù):000005保留兩位小數(shù):3.14保留三位小數(shù):3.142正確率為:80%

邏輯運算

  • 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è)置 -- 通常是重復執(zhí)行的 計數(shù)器
while 條件 1:
條件滿足時,做的事情 1
條件滿足時,做的事情 2
條件滿足時,做的事情 3
……
while 條件 2:
條件滿足時,做的事情 1
條件滿足時,做的事情 2
條件滿足時,做的事情 3
……
處理條件 2
處理條件 1

print 函數(shù)增強

在默認情況下,print 函數(shù)輸出內(nèi)容之后,會自動在內(nèi)容末尾增加換行;
如果不希望末尾增加換行,可以在 peint 函數(shù)輸出內(nèi)容的后面增加,end=''
其中''中間可以指定 print 函數(shù)輸出內(nèi)容之后,繼續(xù)希望現(xiàn)實的內(nèi)容;
語法格式如下:
print('*',end='')

轉(zhuǎn)義字符

  • \t--在控制臺輸出一個制表符,協(xié)助在輸出文本時,垂直方向,保持對齊

  • \n--在控制臺輸出一個換行符

  • \r--回車

  • \--反斜杠符號

  • \'--單引號

  • \'--雙引號

列表

  • 列表通過索引取值,列表索引從0開始,且不能超過范圍;

  • len(列表)--獲取列表的長度

  • 列表.count(數(shù)據(jù))--數(shù)據(jù)在列表中出現(xiàn)的次數(shù)

  • 列表.index(數(shù)據(jù))--獲取數(shù)據(jù)第一次出現(xiàn)的索引

  • del 列表 [索引]--刪除指定索引的數(shù)據(jù)

  • 列表.remove[數(shù)據(jù)]--刪除第一個出現(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 = ()

  • 元組中只包含一個元素時,需要在元素后面添加逗號:info_tuple = (50, )

  • len(元組)--獲取元組的長度 n+1;

  • 元組.count(數(shù)據(jù))--數(shù)據(jù)在元組中出現(xiàn)的次數(shù);

  • 元組 [索引]--從元祖中取值;

  • 元組.index(數(shù)據(jù))--獲取數(shù)據(jù)第一次出現(xiàn)的索引。

元組和列表之間的轉(zhuǎn)換

  • 使用 list 函數(shù)可以把元組轉(zhuǎn)換成列表
    list(元組)

  • 使用 tuple 函數(shù)可以把列表轉(zhuǎn)換成元組
    tuple(列表)

字典

  • Python 里的字典在底層使用了哈希表 (hash table) 數(shù)據(jù)結(jié)構(gòu)

  • 和列表的區(qū)別:列表 是 有序 的對象集合 字典 是 無序 的對象集合

Python3.6 之后的字典是有序的,如果解釋器版本沒有那么新,也可以使用 collections 模塊里的 OrderedDict 方法保證字典的有序性。
OrderedDict 與新版字典在比較上面的區(qū)別:在對比兩個內(nèi)容相同但順序不同的字典時,新版字典會返回 True,OrderedDict 則會返回 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 不存在會報錯;
    1.返回的數(shù)據(jù)類型類似列表,但不是真正意義的列表,沒有 append() 方法;
    2.但是可以用于 for 循環(huán);
    3.可以用 list() 方轉(zhuǎn)換成真正的列表;

  • 字典.get(key)--可以從字典中取值,key 不存在不會報錯;

  • del 字典 [key]--刪除指定鍵值對,key 不存在會報錯;

  • 字典.pop(key)--刪除指定鍵值對,并且返回刪除鍵對應的值,key 不存在會報錯;

  • 字典.pop(key, default=msg)--刪除指定鍵值對,并且返回刪除鍵對應的值,key 不存在不會報錯,會返回 msg;

  • 字典 popitem() 方法返回并刪除字典中的最后一對鍵和值。

  • 字典.clear()--清空字典;

  • 字典 [key] = value
    如果 key 存在,修改數(shù)據(jù)
    如果 key 不存在,新建鍵值對

  • 字典.setdefault(key,value)
    如果 key 存在,不會修改數(shù)據(jù)
    如果 key 不存在,新建鍵值對

  • 字典.update(字典2)--將字典2的數(shù)據(jù)合并到字典1,如果字典2中有和字典 1 重復的鍵值對,則替換字典 1 中的鍵值對;

  • 生成字典的方法:d = dict.fromkeys(['name','age','code'],0) #0 為默認值

字符串

  • 拼接多個字符串,使用 str.join 和 +=同樣好用;

  • len(字符串)--獲取字符串的長度;

  • 字符串.count(字符串)--小字符串在大字符串中出現(xiàn)的次數(shù);

  • 字符串 [索引]--從字符串中取出單個字符;

  • 字符串.index(字符串)--獲得小字符串第一次出現(xiàn)的索引;

  • string.istitle() | 如果 string 是標題化的 (每個單詞的首字母大寫) 則返回 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 會報錯;

  • string.replace(old_str, new_str, num=string.count(old)) | 把 string 中的 old_str 替換成 new_str,如果 num 指定,則替換不超過 num 次;

  • string.capitalize() | 把字符串的第一個字符大寫;

  • string.title() | 把字符串的每個單詞首字母大寫;

  • string.lower() | 轉(zhuǎn)換 string 中所有大寫字符為小寫;

  • string.upper() | 轉(zhuǎn)換 string 中的小寫字母為大寫;

  • string.swapcase() | 翻轉(zhuǎn) string 中的大小寫;

字符串 - 切片

  • 切片方法適用于字符串、列表、元組;

  • 字符串 [開始索引:結(jié)束索引:步長];

  • 切片:正反向索引(正:從 0 開始,反:從-1 開始)

  • 切片索引:[start圖片step]

  • start:開始截取的位置,包含在截取內(nèi)容內(nèi)

  • end:結(jié)束截取的位置,結(jié)束截取的位置并不包含

  • step:截取的步長,默認值為 1

  • step:為正,表示從左到右進行截取,start 必須在 end 之前(從左開始算前,下標必須從左到右)

  • step:為負,表示從右到左進行截取,start 必須在 end 之前(從右開始算前,下標必須從右到左)

  • 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ù)字可以省略,冒號不能省略
到末尾結(jié)束,結(jié)束索引 數(shù)字可以省略,冒號不能省略
步長默認為 1,如果連續(xù)切片,數(shù)字和冒號都可以省略
索引的順序和倒序:
在 Python 中不僅支持 順序索引,同時還支持 倒序索引
所謂倒序索引就是 從右向左 計算索引
最右邊的索引值是 -1,依次遞減

字符串格式化

  • 優(yōu)先使用 f-string 方式

# 將username靠右對齊,左側(cè)補空格一共到20位username = 'Lili'print(f'{username:>20}')-------------------------------------
               Lili
  • 對參數(shù)復用時可以使用 str.format 方式

username = 'Lily'sore = 10print('{0}:{0}的成績是{1}'.format(username, sore))

集合

  • 集合是一個無序的可變?nèi)萜黝愋停畲蟮奶攸c就是成員不能重復

  • 要初始化一個空集合只能調(diào)用 set() 方法,因為{}表示的是一個空字典,而不是一個空集合

  • 集合也有自己的推導式-nums = {n for n in range(10) if n % 2 == 0}

  • 集合是可變類型,可以通過.add() 追加元素

  • 可以使用 update 方法可以將一個可迭代元素更新到集合中

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() 可以刪除集合中的元素,但元素不存在會報錯-KeyError:

  • 使用.discard() 可以刪除集合中的元素,元素不存在也不會報錯

  • 集合的元素不可以修改,只能先刪再加

  • 我們可以使用 in 判斷某個元素是否在某個集合中,不能在集合中取值,只能使用 for 循環(huán)遍歷集合中的元素

  • 集合只能存放可哈希對象

s1 = set([1,2,3])s1.add([1])-----------------------TypeError: unhashable type: 'list'

集合的運算

集合支持集合運算,比如交集、并集、差集。所有的操作都可以用兩種方式:方法和運算符;

  • 交集

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'}
  • symmetric_difference:返回兩個集合中不重復的元素

fruits_1 = {'apple','orange','pineapple'}fruits_2 = {'tomato','orange','grapes','mango'}print(fruits_1.symmetric_difference(fruits_2)){'apple', 'mango', 'tomato', 'pineapple', 'grapes'}
  • issubset:用于判斷集合的所有元素是否都包含在指定集合中

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)

  • 什么時候用 for:當循環(huán)次數(shù)是一定的,或者是循環(huán)對象是一定的,比如說在一個固定的字符串或列表中進行循環(huán),那么最好使用 for

  • 什么時候用 while:當循環(huán)次數(shù)不是一定的,只是滿足某個條件時才進行循環(huán),那么最好使用 while

  • 沒有 do…while…循環(huán)

  • 循環(huán)里面加 else:當循環(huán)執(zhí)行完畢時,else 才會執(zhí)行;如果循環(huán)在中間退出,則 else 不會運行

  • break&continue:不管是 break 還是 continue 都只作用于當前循環(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))

類定義

  • 類名首字母大寫,多個字母連接一起

  • 默認繼承 object 類,若繼承其他類則在類名后加(繼承父類)

類方法

  • 實例方法
    1、只能通過對象 (實例) 調(diào)用的方法
    2、實例方法在定義時總是以 self 作為第一個參數(shù)
    3、實例方法在調(diào)用時不需要傳入 self,這個實例本身會自動傳到方法中作為 self

  • 初始化方法 (init())
    1.不需要顯式調(diào)用,在初始化對象時會有 python 自動調(diào)用
    2.初始化方法一般只在定義對象屬性的時候才會定義

  • 類方法
    1、可以直接通過類名調(diào)用的方法,也可以通過實例調(diào)用
    2、類方法必須通過
    @classmethod裝飾器進行裝飾
    3、所有的類方法第一個參數(shù)必須是 cls
    4、類方法不能訪問實例屬性,只能訪問類屬性

  • 屬性方法
    使用場景:屬性方法對應的屬性的值無法直接確定,要通過一系列的操作才能得到這個值,而且用戶不關(guān)心這個操作過程,只想得到這個值。
    定義:當成屬性使用的方法,調(diào)用屬性方法時不需要加 ()

  • 靜態(tài)方法
    1、通過
    @staticmethod裝飾器來進行裝飾的方法
    2、靜態(tài)方法既不能訪問實例屬性,也不能訪問類屬性
    3、可以通過類名直接調(diào)用,也可以通過對象調(diào)用

類的三大特征

  • 封裝
    暴露接口,隱藏細節(jié)

  • 繼承
    1.子類通過繼承直接獲得父類的全部屬性和方法,實現(xiàn)代碼復用
    2.初始化的幾種情況:
    2.1 當子類中沒有定義init() 方法,則初始化子類時將默認使用父類的初始化方法,并傳入對應的參數(shù)
    2.2 當子類定義了自己的初始化方法,但沒有調(diào)用父類的初始化方法,則父類中的相關(guān)屬性不會被初始化
    2.3 若在子類中重新定義了 init 方法,若仍要繼承父類的屬性,則需要顯示調(diào)用父類的 init 方法:super().init()

  • 多態(tài)

類的反射

  • 反射原理
    通過字符串的形式在運行時動態(tài)修改程序的變量、方法及屬性,所有的修改都在內(nèi)存中進行,所以他并不會實際修改代碼,主要目的就是提高代碼在運行時的靈活性;

  • 反射相關(guān)的方法
    hasattr 輸入一個字符串,判斷對象有沒有這個方法或?qū)傩裕?br>getattr 獲取對象屬性值或方法的引用,如果是方法,則返回方法的引用,如果是屬性,則返回屬性的值,如果該方法或?qū)傩圆淮嬖冢瑒t拋出異常;
    setattr 動態(tài)添加一個方法或?qū)傩裕?br>delattr 動態(tài)刪除一個方法或?qū)傩浴?/span>

異常處理

Python 異常處理依賴的關(guān)鍵字:
try
except
else
finally

  • try
    try 塊里面放置所有可能引起異常的代碼,一個異常處理塊里面只能有一個 try;

  • except
    放置要處理的異常類型和相應語句塊,用于表明該 except 要處理的異常類型;
    一個異常處理塊里面可以跟 1 到 n 個 except 塊;
    每個 except 塊后面可以跟 1 到 n 個異常類型,也可以不跟任何異常類型;

  • else
    如果 try 塊里面的語句沒有引起異常,則會運行 else 里面的語句;

  • finally
    主要用于回收再 try 塊里面打開的物理資源,異常處理機制會保證 finally 塊一定會被執(zhí)行;

  • 異常處理語法結(jié)構(gòu)
    1.只有 try 是必須的
    2.如果沒有 try,就不能有 except 和 finally
    3.except 塊和 finally 塊都是可選的,但 except 和 finally 必須出現(xiàn)其中之一,也可以同時出現(xiàn)
    4.可以有多個 except 塊,但捕獲父類異常的 except 塊要寫在捕獲子類異常的 except 塊的后面
    5.多個 except 塊必須位于 try 塊之后,finally 塊必須位于所有塊的最后

IO 讀寫 - 文本文件

  • open (path,mode)
    默認是 r:只讀模式,文件必須事先存在,不主動生成文件,從文件開頭開始讀;
    r+:讀寫模式,文件也必須事先存在,不主動生成文件,從文件開頭開始讀或?qū)懀?br>w:只寫模式,如果用 w 模式打開,一律會清空之前文件的所有內(nèi)容,如果文件不存在,則自動創(chuàng)建文件,從頭開始寫;
    w+:讀寫模式,也會清空之前文件的所有內(nèi)容,如果文件不存在,則自動創(chuàng)建文件,從頭開始寫;
    a:追加模式,只寫,不會清空以前文件的內(nèi)容,主動生成文件,從文件尾開始寫入;
    a+:追加模式,讀和寫,不會清空以前文件的內(nèi)容,主動生成文件,從文件尾開始寫入或讀??;
    二進制讀寫,一般用于圖片或音視頻:rb+,wb+,ab+;

  • 查看和設(shè)置文件指針位置:

    with open('user.txt', 'a+') as f:
       # 將文件指針重置至開始位置(這樣就不會導致f.readlines()讀不到數(shù)據(jù)了)    f.seek(0)
       # 返回文件指針位置    print(f.tell())
  • with 是 python 中的上下文管理器,它會自動幫你管理文件的句柄

    with open(r'D:\testlog.txt') as f:for line in f.readlines():
       print(line,end='')
  • 文件與文件夾
    windows 文件路徑用反斜線,Linux 文件路徑用正斜線,要想將程序在不同系統(tǒng)上運行,則可用 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)知識點附張圖吧:
圖片

多線程和多進程編程

  • 概念
    程序:指的是一段靜態(tài)的代碼指令;
    進程:正在執(zhí)行的程序,將靜態(tài)的執(zhí)行代碼運行起來,進程內(nèi)擁有該程序執(zhí)行所需的全部資源;
    線程:是指正在執(zhí)行程序的最小單元。一個進程中至少必須有一個線程(主線程),在程序中線程是獨立的可運行的流;
    多線程:在單個程序中同時運行多個不同的線程,完成不同的工作;

  • 進程特征
    獨立性:進程是系統(tǒng)中獨立存在的實體,擁有獨立的資源空間;
    動態(tài)性:進程擁有自己的生命周期;
    并發(fā)性:多個進程可以在單個處理器上并發(fā)執(zhí)行,互不影響;

  • 線程特征
    每個線程都有自己的堆棧,自己的程序計數(shù)器,自己的局部變量,這里體現(xiàn)了程序的獨立性;
    在相同父進程下的所有線程共享進程內(nèi)所有資源,可以實現(xiàn)線程間的消息互通;
    多個線程之間也可以并發(fā)執(zhí)行,互不影響;

  • 創(chuàng)建多線程-threading

    1.使用 threading 模塊的 Thread 類的構(gòu)造器創(chuàng)建線程對象。在創(chuàng)建線程對象時使用 target 參數(shù)指定函數(shù)線程的執(zhí)行體;
    2.調(diào)用線程對象的 start() 方法啟動線程;

  • 通過 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è)置守護線程
    主線程結(jié)束后立即結(jié)束所有設(shè)置為守護線程的子線程;

  • 多線程鎖

    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 的一個重要特性,它是一種機制,用于保護多線程環(huán)境下共享內(nèi)存數(shù)據(jù)的完整性。它鎖定了整個解釋器,只允許一個線程同時執(zhí)行 Python 字節(jié)碼,從而避免多線程下出現(xiàn)數(shù)據(jù)競爭問題。這意味著即使使用多核 CPU,Python 程序也不能充分利用多核優(yōu)勢。GIL 在性能上可能帶來一定的影響,因此不適合處理需要大量的 CPU 運算的任務(wù)。

什么條件下會釋放 GIL:
當前活躍線程遇到 IO 等待,比如要訪問網(wǎng)絡(luò)或建立數(shù)據(jù)庫鏈接等情況;
活躍線程執(zhí)行了 100 個字節(jié)碼的程序后,GIL 也會釋放該線程的鎖,然后與其他線程參與競爭;

python 的多線程適合場景:
python 的多線程只適合于 IO 密集型應用,對于計算密集型的應用最好使用多進程或協(xié)程的方式解決;

可迭代對象

  • 通俗說,可迭代對象就是可以放在 for 循環(huán)內(nèi)進行迭代的對象
    比如列表、字典、元祖、字符串;

  • 判斷一個可迭代對象的依據(jù)是什么:
    必須至少實現(xiàn)getitemiter這兩個方法中的其中一個

迭代器

  • 任何實現(xiàn)了iternext方法的對象都是迭代器(這兩個方法必須同時實現(xiàn));

  • 其中iter會返回迭代器本身;

  • next會返回迭代器中的下一個元素,如果沒有元素了將拋出 stopIteration 異常;

  • 迭代器當然也可以用到 for 循環(huán)中;

  • 迭代器實際上就是一種工廠模式。

迭代器和可迭代對象的區(qū)別

  • 迭代器是迭代對象的一種,迭代器一定是可迭代對象,可迭代對象不一定是迭代器

  • 一個合法的迭代器,必須同時實現(xiàn)iternext兩個魔法方法

  • 可迭代對象只需要實現(xiàn)iter方法即可

  • 判斷對象 obj 可迭代的唯一方法就是調(diào)用 iter(obj),看返回結(jié)果是不是一個迭代器

  • 每個迭代器的被迭代過程是一次性的,可迭代對象則不一定

生成器

  • 特殊的迭代器,只需要使用 yield 關(guān)鍵字,那么就會立即變?yōu)橐粋€生成器,也就是說,只要一個函數(shù)中包含了一個 yield 關(guān)鍵字(不管幾個),那么這個函數(shù)就會自動變成一個生成器函數(shù);

  • 生成器一定是一個迭代器,但反之不一定成立;

  • 特點:
    生成器中每次遇到 yield 關(guān)鍵字之后,會返回相應的結(jié)果;
    保留函數(shù)當前的運行狀態(tài),等待下一次調(diào)用,下次調(diào)用時將從上一次返回 yield 語句處開始執(zhí)行后面的語句;

  • 生成器的 send 方法可以向函數(shù)體內(nèi)去傳遞值;
    對于 next 和 send 方法的異同:
    next 和 send 都可以去調(diào)用一次生成器,從調(diào)用生成器的角度來說,他們的作用完全一樣;
    next 無法像生成器內(nèi)部的變量賦值,但 send 可以;
    next(gen) 等同于 send(None),可以互換;

  • 在生成器中使用 for 循環(huán)
    每一次 for 循環(huán)相當于調(diào)用一次 next;
    for 循環(huán)會自動幫助我們處理 stopIteration 異常。

裝飾器

  • 定義
    裝飾器本質(zhì)是函數(shù),只是它的作用是為其他函數(shù)添加特定的附加功能;

  • 編寫裝飾器的原則
    裝飾器一定不能修改被裝飾器的函數(shù)的源碼;
    裝飾器一定不能修改被裝飾的函數(shù)的調(diào)用方式;

  • 實現(xiàn)裝飾器的前置知識條件
    1.函數(shù)即變量
    函數(shù)和普通變量的存儲原理是一樣的,函數(shù)名可以像變量名那樣去使用,比如可以進行賦值;
    2.掌握高階函數(shù)相關(guān)知識
    符合下面任意條件之一即為高階函數(shù)
    條件一:接收函數(shù)名作為參數(shù)
    條件二:返回值中包含函數(shù)名
    3.掌握函數(shù)嵌套相關(guān)知識
    通過 def 關(guān)鍵字在一個函數(shù) A 中去定義另外一個函數(shù) B,則函數(shù) B 稱為嵌套函數(shù);
    4.裝飾器=高階函數(shù) + 嵌套函數(shù)

  • 了解裝飾器的本質(zhì)優(yōu)勢
    1.運行時校驗:在執(zhí)行階段進行特定校驗,當校驗不通過時終止執(zhí)行:
    Django 框架中的用戶登錄態(tài)校驗裝飾器
    @login_required
    2.注入額外參數(shù):在函數(shù)被調(diào)用時自動注入額外的調(diào)用參數(shù):
    unittest.mock 模塊的裝飾器
    @patch;
    3.緩存執(zhí)行結(jié)果:通過調(diào)用參數(shù)等輸入信息,直接緩存函數(shù)執(zhí)行結(jié)果:
    functools 模塊的緩存裝飾器
    @lru_cache;
    4.注冊函數(shù):將被裝飾函數(shù)注冊為某個外部流程的一部分:
    Flask 框架的路由注冊裝飾器
    @app.route
    5.替換為復雜對象:將原函數(shù) (方法) 替換為更復雜的對象,比如類實例或特殊的描述符對象:
    靜態(tài)方法的裝飾器
    @staticmethod。

正則表達式

正則表達式匹配步驟:
1.import re
2.用 re.compile() 函數(shù)創(chuàng)建一個 Regex 對象(記得使用原始字符串)
3.向 Regex 對象的 search() 方法傳入想查找的字符串。它返回一個 Match 對象(一般用 mo 接收)
4.調(diào)用 Match 對象的 group() 方法,返回實際匹配的字符串
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:

我在學習中,發(fā)現(xiàn)正則表達式在任何語言中都占有很大部分的占比,但正則表達式相關(guān)的知識點又過于零碎,對于榆木腦袋的我真是學一遍忘一遍。在實際工作中,我自己真正用到正則的地方并不多,再看同事,目前就發(fā)現(xiàn)前端同學有可能會用到正則去做一些事情,并且用到的時候都是度娘,一是自己真記不住,二是度娘 copy 過來的多數(shù)情況是比自己寫要嚴謹?shù)亩嗟摹?/span>

基于此,我把正則視為投入產(chǎn)出比太低的事情,僅需要記住個大概印象,真到用時能分清度娘上哪個輪子能用哪個輪子用不了就可以了。

測試基礎(chǔ)-Python篇 基礎(chǔ)②

常用模塊-math

import math

  • print(math.ceil(3.14)) # 取大于等于 x 的最小整數(shù)

  • print(math.fabs(-3)) # 取絕對值

  • print(math.floor(3.14)) # 取小于等于 x 的最大整數(shù)

  • print(math.fsum([1,2,3])) # 求和

  • print(math.pow(3,4)) #3 的 4 次方 等價于 3**4

  • print(math.sqrt(3)) # 開平方,3 的平方根

常用模塊-random

import random

  • print(random.random()) # 返回 [0.0,1.0) 之間的浮點數(shù)

  • print(random.randint(10,20)) # 生成 10 到 20 之間的一個隨機整數(shù),也就是 [10,20]

  • print(random.randrange(10,20)) # 生成 10 到 20 之間的一個隨機整數(shù),也就是 [10,20)

  • print(random.uniform(10,20)) # 生成 10 到 20 之間的一個隨機浮點數(shù),也就是 [10,20]

  • print(random.choice([10,20,30])) # 隨機從列表選擇一個數(shù)

  • print(random.choices([10,20,30],k=2)) # 隨機從列表選擇 k 個數(shù),返回列表形式,取出放回方式,意思是取出的數(shù)可以重復

  • print(random.sample(a1,3)) # 隨機從列表選 k 個數(shù),返回列表形式,取出不放回方式,意思是取出的數(shù)不會重復

  • random.shuffle(a1) # 洗牌,隨機變換列表順序

常用模塊-json

  • 用 loads() 函數(shù)讀取 JSON
    要將包含 JSON 數(shù)據(jù)的字符串轉(zhuǎn)換為 Python 的值,就將它傳遞給 json.loads() 函數(shù);

  • 用 dumps() 函數(shù)寫出 JSON
    將一個 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

  • round() 第一個參數(shù)是要處理的數(shù)字,第二個可選參數(shù)為四舍五入保留的位數(shù),若不傳如第二個參數(shù),則默認四舍五入到最近的整數(shù)

import timen = time.time()print(n)n1 = round(n,3)print(n1)------------------------1675392067.29749661675392067.297
  • time.time() ---獲取當前時間戳:1675392067.2974966

  • time.sleep(sec) ---睡眠 sec 秒

常用模塊-datetime()

  • datetime 模塊有自己的 datetime 數(shù)據(jù)類型:

  • 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'>
  • Unix 時間戳可以通過 datetime.datetime.fromtimestamp() 轉(zhuǎn)換為 datetime 對象

import datetimeimport timenow = time.time()date = datetime.datetime.fromtimestamp(now)print(now)print(date)----------------------------------------------------------------------------1675393953.08603122023-02-03 11:12:33.086031
  • datetime對象可以用比較操作符進行比較,后面的datetime對象時'更大'的值

import datetimeimport timed1 = datetime.datetime.now()time.sleep(1)d2 = datetime.datetime.now()print(d2>d1)-----------------------------------------------True
  • datetime 對象的差的數(shù)據(jù)類型是'timedelta'

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'>
  • 要創(chuàng)建 timedelta 對象,就用 datetime.timedelta() 函數(shù)

import datetimedt = datetime.timedelta(days=11,hours=10,minutes=9,seconds=8)print(dt)print(type(dt))print(dt.days)print(dt.seconds) # 天不參與計算,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
  • 算數(shù)運算符可以用于對 datetime 值進行日期運算,例如,要計算今天之后 1000天的日期;

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 模塊存儲各種格式的日志,主要用于輸出運行日志,可以設(shè)置輸出日志的等級、日志保存路徑、日志文件回滾等;

  • 日志級別
    DEBUG --logging.debug()
    INFO --logging.info()
    WARNING --logging.warning()
    ERROR --logging.error()
    CRITICAL --logging.critical()

  • 使用日志模塊

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
  • 將日志記錄到文件-logging.basicConfig() 函數(shù)接受 filename 關(guān)鍵字。

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')
  • 禁用日志 只要向 logging.disable() 傳入一個日志級別,他就會禁止該級別和更低級別的所有日志消息; logging.disable(logging.CRITICAL) 加在代碼前面即可隱藏日志信息(接近 import.logging 的位置更容易找到和管理);

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

  • 要得到單獨的線程,首先要調(diào)用 threading.Thread() 函數(shù),生成一個 Thread 對象。

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ù)名后傳的是方法名,不加 (),因為此處并不是調(diào)用。

  • 向線程的目標函數(shù)傳遞參數(shù) 常規(guī)參數(shù)可以作為一個列表,傳遞給 threading.Thread() 中的 args 關(guān)鍵字參數(shù)。關(guān)鍵字參數(shù)可以作為一個字典,傳遞給 threading.Thread() 中的 kwargs 關(guān)鍵字參數(shù):

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ā)問題,絕不讓多個線程讀取或?qū)懭胂嗤兞?。當?chuàng)建一個新的 Thread 對象時,要確保其目標函數(shù)只使用該函數(shù)中的局部變量。

  • 線程阻塞-thread.join()
    thread.join() 方法的作用是阻塞當前線程,直到調(diào)用 join() 方法的線程結(jié)束。也就是說,如果你有多個線程并希望在其中一個線程結(jié)束之后再繼續(xù)執(zhí)行,則可以使用 join() 方法。

# 不使用join,兩個線程并行運行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運行完后再運行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è)置的話就永遠等待;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í)行淺拷貝時實際上是創(chuàng)建了一個新的副本,而不是拷貝引用。因此,對原數(shù)據(jù)的更改不會影響到拷貝后的數(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

對于可變數(shù)據(jù)類型,淺拷貝只拷貝第一層中的引用,深拷貝在拷貝時,會逐層進行拷貝,直到所有的引用都是不可變對象為止。

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 有多種方式實現(xiàn)淺拷貝,copy 模塊的 copy 函數(shù) ,對象的 copy 函數(shù) ,工廠方法,切片等。

  • 賦值符號'=':如果是可變類型,就是引用傳遞;如果是不可變類型,就是值傳遞。

  • 淺拷貝的優(yōu)點:拷貝速度快,占用空間少,拷貝效率高。

  • 因為淺拷貝不能解決嵌套問題,所以引出了深拷貝,深拷貝會遍歷并拷貝 items 里所有的內(nèi)容 - 包括他嵌套的子列表;

對象的可哈希性

  • 不可變的內(nèi)置類型都是可哈希的,比如 str、int、float、frozenset

  • 可變的內(nèi)置類型都是不可以哈希的,比如 list、dict

  • 對于不可變?nèi)萜黝愋停╰uple、frozenset),僅當他的所有成員都不可變時,他自身才是可哈希的

  • 用戶定義的類型默認都是可哈希的

注意:只有可哈希對象才能被放進集合或者作為字典的鍵

sorted() 函數(shù)

sorted 函數(shù)是 Python 內(nèi)置函數(shù),用于對可迭代對象進行排序,并返回一個新的列表。
注意:sorted 函數(shù)不會改變原來的可迭代對象,而是返回一個新的列表。如果需要改變原來的可迭代對象,可以使用 sort 方法,但它只能用于列表。
參數(shù):

  • iterable:可以是列表、元組、字典等任意可迭代對象。

  • key:一個函數(shù),用于提取每個元素的排序關(guān)鍵字。默認為 None,表示按元素本身的順序進行排序。

  • reverse:是否按降序排列,默認為 False,表示按升序排列。

enumerate() 函數(shù)

enumerate() 適用于任何'可迭代對象',可以用于列表、元祖、字典、字符串等。

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ǔ)③

浮點數(shù)精度問題

print(0.1+0.2)----------------------0.30000000000000004

可以使用 decimal 模塊解決浮點數(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ù)字

  • 布爾類型其實是整型的子類型

  • True 和 False 這兩個布爾值可以直接當做 1 和 0 來使用

  • 通過這個特點,最常用于統(tǒng)計總數(shù)

def sum_even(numbers: list[int]):
   '''
   返回numbers中偶數(shù)的個數(shù)
   :param numbers: 整數(shù)列表
   '''

   return sum(i % 2 == 0 for i in numbers)

不常用但特別好用的字符串方法

  • str.partition(sep) 按照切分符 sep 切分字符串,返回一個包含三個成員的元祖 (part_before, sep, part_after);若 s 不包括分隔符,則最后一個成員默認是空字符串'';

s = 'TomAndMarry's2 = s.partition('And')print(s2)--------------------------------('Tom ', 'And', ' Marry')
  • 2.str.translate(table) 他可以按規(guī)則一次性替換多個字符,使用它比調(diào)用多次 replace 方法更快也更簡單;

s = '明明是中文,卻使用了英文標點.'table = s.maketrans(',.', ',。')s2 = s.translate(table)print(s2)-----------------------------------------------明明是中文,卻使用了英文標點。

使用枚舉類型來替代字面量

  • 更易讀:所有人都不需要記憶某個數(shù)字代表什么;

  • 更健壯:降低輸錯數(shù)字或字母產(chǎn)生 bug 的可能性;

# 用戶每日獎勵積分數(shù)量DAILY_POINTS_REWARDS = 100# VIP用戶額外獎勵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

生成器

  • 定義一個生成器需要生成器函數(shù)和 yield 關(guān)鍵字

  • yield 和 return 最大的區(qū)別在于,return 會一次性返回結(jié)果,使用它會直接中斷函數(shù)執(zhí)行,而 yield 可以逐步給調(diào)用方生成結(jié)果

  • 使用生成器的優(yōu)點是它們占用的內(nèi)存比列表要少,因為它們只生成一個元素并在需要時生成下一個元素。這使得生成器特別適合于處理大量數(shù)據(jù)

  • 每次調(diào)用生成器函數(shù)都會生成一個新的生成器對象

fruits = {'apple','orange','pineapple'}def batch(item):
   for _ in item:
       yield _print(next(batch(fruits)))print(next(batch(fruits)))print(next(batch(fruits)))---------------------------------------appleappleapple

因為每次調(diào)用生成器函數(shù)都會生成一個新的生成器對象,所以以上程序運行結(jié)果會輸出三個 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

以上代碼再次驗證了'每次調(diào)用生成器函數(shù)都會生成一個新的生成器對象'結(jié)論

  • 使用生成器的 next() 函數(shù)可以在需要時單獨生成生成器中的元素,而不是一次性生成整個列表。如果生成器中沒有元素,則會引發(fā) StopIteration 異常

  • 用生成器替代列表

def batch_process(item):
   result = []
   for i in item:
       # process_item = ..處理item        result.append(process_item)
   return result# 以上方法會有一個問題,當item過大時,會導致函數(shù)執(zhí)行很耗時,并且若調(diào)用方想在某個process_item達到條件時中斷,以上方法也是做不到的。所以可以使用生成器函數(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):
   # 如果某個處理對象過期了,就中斷當前的所有處理    if processed_item.has_expired():
       break

面向?qū)ο缶幊?/strong>

內(nèi)置類方法裝飾器

  • 類方法
    1.用 def 在類里定義一個函數(shù)時,這個函數(shù)通常被稱作方法。調(diào)用這個方法需要先創(chuàng)建一個類實例;
    2.可以使用
    @classmethod裝飾器定義類方法,它屬于類,無需實例化也能調(diào)用;
    3.作為一種特殊方法,類方法最常見的使用場景,就是定義工廠方法來生成新實例,類方法的主角是類型本身,當發(fā)現(xiàn)某個行為不屬于實例,而是屬于整個類型是,可以考慮使用類方法;

  • 靜態(tài)方法
    1.如果發(fā)現(xiàn)某個方法不需要使用當前實例里的任何內(nèi)容,那可以使用
    @staticmethod來定義一個靜態(tài)方法;
    2.和普通方法相比,靜態(tài)方法不需要訪問實例的任何狀態(tài),是一種與狀態(tài)無關(guān)的方法,因此靜態(tài)方法其實可以寫成脫離于類的外部普通函數(shù);
    2.1.如果靜態(tài)方法特別通用,與類關(guān)系不大,那么把他改成普通函數(shù)會更好;
    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)從一個普通的方法變成了 property 對象,所以可以使用 basename.setter 和 basename.deleter 方法;
定義 setter 方法,該方法會在對屬性賦值是被調(diào)用;
定義 deleter 方法,該方法會在刪除屬性時被調(diào)用;

鴨子類型及其局限性

  • 在鴨子類型編程風格下,如果想操作某個對象,你不會去判斷他是否屬于某種類型,而會直接判斷他是不是有你需要的方法 (或?qū)傩??;蛘吒みM一些。你甚至會直接嘗試調(diào)用需要的方法,假如失敗了,那就讓她報錯好了;

  • 鴨子類型的優(yōu)點就是編寫簡單,使用靈活;

  • 鴨子類型的缺點就是缺乏標準、過于隱式;

  • 可以使用類型注解、靜態(tài)檢查 (mypy)、抽象類來補充鴨子類型;

抽象類

  • isinstance() 函數(shù)
    利用 isinstance() 函數(shù),我們可以判斷對象是否屬于特定類型;
    isinstance() 函數(shù)能理解類之間的繼承關(guān)系,因此子類的實例同樣可以通過基類的校驗;

  • 校驗對象是否是 Iterable 類型
    在 collections.abc 模塊中,有許多和容器相關(guān)的抽象類,比如代表集合的 Set、代表序列的 Sequence 等,其中有一個最簡單的抽象類:Iterable,他表示的是可迭代類型;

  • 鴨子類型和抽象類總結(jié)
    鴨子類型是一種編碼風格,在這種風格下,代碼只關(guān)心對象的行為,不關(guān)心對象的類型;
    鴨子類型降低了類型校驗的成本,讓代碼變得更靈活;
    傳統(tǒng)的鴨子類型里,各種對象接口和協(xié)議都是隱式的,沒有統(tǒng)一的顯示標準;
    傳統(tǒng)的 isinstance() 類型檢查和鴨子類型的理念是相違背的;
    抽象類是一種特殊的類,他可以通過鉤子方法來定制動態(tài)的子類檢查行為;
    因為抽象類的定制子類化特征,isinstance() 也變得更靈活、更契合鴨子類型了;
    使用
    @abstractmethod裝飾器,抽象類可以強制要求子類在繼承時重寫特定方法;
    除了抽象方法外,抽象類也可以實現(xiàn)普通的基礎(chǔ)方法,供子類繼承使用;
    在 collections.abc 模塊中,有許多與容器相關(guān)的抽象類;

多重繼承于MRO

  • Python 里的一個類可以同時繼承多個父類;

  • 調(diào)用類的 mro() 方法,可以看到按 MRO 算法排好序的基類列表;

  • 在許多人印象中。super() 是一個用來調(diào)用父類方法的工具函數(shù)。但這么說并不準確,super() 使用的其實不是當前類的父類,而是當前類在 MRO 鏈條上的上一個類;

  • 應該避免多重繼承;

學習建議

對于Python入門及進階,我推薦兩本我認為值得多次閱讀的書籍:

  • 《Python編程從入門到實踐(第二版)》- 第一部分為基礎(chǔ)語法部分,建議剛接觸 Python 的同學多次閱讀并實踐,夯實基礎(chǔ)利器!

  • 《Python工匠》- 整本無尿點,強烈建議多次閱讀并實踐,是Python進階的不二之選!

其他瑣碎但十分實用的知識點

  • for......else......的執(zhí)行順序:
    當?shù)鷮ο笸瓿伤械笄掖藭r的迭代對象為空時,如果存在 else 子句則執(zhí)行 else 子句,沒有則繼續(xù)執(zhí)行后續(xù)代碼;如果迭代對象因為某種原因(如帶有 break 關(guān)鍵字)提前退出迭代,則 else 子句不會被執(zhí)行,程序?qū)苯犹^ else 子句繼續(xù)執(zhí)行后續(xù)代碼;

  • 數(shù)值型比較不能使用 not in,因為 not in 本質(zhì)是循環(huán)遍歷右側(cè)數(shù)據(jù),用左側(cè)數(shù)據(jù)進行比對,len() in range(1,5) 可以使用,因為 range 是一個集合,可以遍歷, 'li' in 'lili'不建議使用,因為返回結(jié)果為 True(包含),達不到預期結(jié)果,所以準確比較建議使用'==';

  • 字典取值:有兩種方式,a={'name':'lili'}
    第一種:a['name']
    第二種:a.get('name')
    區(qū)別:a['wenwen'] 報錯-KeyError a.get('wenwen') 不報錯-None

  • 如果在方法中給全局變量賦值,則要在方法中提前聲明全局變量-global;

  • 列表轉(zhuǎn)成字符串''.join(list)
    用''中的字符串作為連接,拼接 list 列表中的每個元素 --- 只能用在每個元素都是字符串的時候可以用,要不然就會報錯;

  • 集合數(shù)據(jù)類型 set 取值
    因為集合(set)是一種無序的不重復的元素的集合。因為集合中的元素沒有特定的順序,所以無法通過下標索引來訪問。
    可以使用循環(huán)遍歷取值,也可使用 in 判斷目標元素是否在集合中。

  • 當遇到復雜計算的數(shù)字字面量時,保留整個數(shù)學公式,提示可讀性也不會降低性能;

  • 要判斷某個容器是否包含特定成員,用集合比用列表更合適,因為集合底層使用了哈希表數(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')
  • 使用集合去重會導致去重后的集合丟失原有的成員順序,若要去重,又要保持原有的成員順序可使用有序字典 OrderedDict

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ù)來說,可以使用 NamedTuple 類型對返回結(jié)果進行建模,可以減少后期代碼變動對已有程序的影響

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
  • 使用 product() 扁平化多層嵌套循環(huán) product() 接收多個可迭代對象作為參數(shù),然后根據(jù)他們的笛卡爾積不斷生成結(jié)果;

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):
   '從這三個數(shù)字列表中,尋找是否存在和為12的3個數(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
  • 使用 islice 實現(xiàn)循環(huán)內(nèi)隔行處理 需求:有一個文件,隔行讀取文件中的內(nèi)容。

# 方法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行讀取,那我們按照以上的寫法應該怎么篩選呢?

# 方法2:使用islicefrom itertools import islicedef parse_titles_v2(filename):
   '''使用slice實現(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就行了

圖片

Python基礎(chǔ)四十問

面對洋洋灑灑的知識點,我往往 “一看就會,一寫就廢”,為了更有針對性的加深知識點的印象,接下來,我將以做題的形式繼續(xù)總結(jié)Python系列如果有不正確的地方,希望各位佬兒哥指正糾偏:

1.列表的增刪查改?


  • l.insert(idx, value) ---指定索引位置增加
    l.append(value) ---在末尾追加
    l.extend(iterable) ---取出可迭代對象的值,追加到列表末尾

    l1 = [1,2,3,3,4,5]l1.extend([1,[2]])print(l1)--------------------------[1, 2, 3, 3, 4, 5, 1, [2]]

  • del l[idx] ---刪除索引處元素,索引超出會報錯:IndexError: list assignment index out of range
    del l ---徹底刪除列表
    l.pop(idx) ---刪除索引處元素,索引超出會報錯:IndexError: pop index out of range
    l.pop() ---刪除列表最后一個元素,列表為空會報錯:IndexError: pop from empty list
    l.remove(value) ---刪除列表中第一個出現(xiàn) value 的元素,值不在會報錯:ValueError: list.remove(x): x not in list
    l.clear() --清除列表中的所有元素


  • l[idx]
    l.count(value) ---統(tǒng)計列表中指定元素出現(xiàn)次數(shù),指定元素不在列表中會返回:0
    l.index(value) ---返回列表中第一個指定元素的索引,指定元素不在列表中會報錯: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)建一個新字典,其中包含指定的鍵,并將所有鍵的值設(shè)置為相同的值
    d.setdefault(key, default_value) ---如果 key 已存在,則返回對應的 value,若 key 不存在,則返回 default_value,并在原字典中新增鍵值對 key: default_value

    # 可用setdefault()統(tǒng)計每個單詞的出現(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 不存在會報錯:KeyError: 'addr'
    d.popitem() ---隨機刪除一個鍵值對,因為字典無序,所以是隨機刪除,字典為空則報錯:KeyError: 'popitem(): dictionary is empty'
    del d[key] ---刪除指定 key,若 key 不存在則報錯:KeyError: 'addr'
    del d ---徹底刪除字典
    d.clear ---清空字典


  • d[key] ---若 key 不存在則報錯:KeyError: 'addr'
    d.get(key) ---若 key 不存在則返回 None
    d.keys() ---以列表形式返回字典的所有 key
    d.values() ---以列表的形式返回字典的所有 value
    d.items() --以列表的形式返回字典的所有鍵值對,每一組鍵值對是一組元祖

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.元祖的增刪查改

因為元祖是不可變數(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],否則報錯:TypeError: 'tuple' object doesn't support item deletion

t[idx] ---idx 不能越界,否則報錯:IndexError: tuple index out of range
可遍歷元祖

for _ in t:
   print(_)

t.count(value) ---返回元祖中 value 的個數(shù),value 不存在返回 0
t.index(value) ---返回元祖中首個 value 的索引,value 不存在則報錯:ValueError: tuple.index(x): x not in tuple

元組是不可變的,因此不能修改元組中的任何元素。

4.例舉Python6種基本的數(shù)據(jù)類型,并標出哪些是不可變數(shù)據(jù)類型?

整形-int-不可變、浮點型-float-不可變、字符型-str-不可變、列表-list-可變、元祖-tuple-不可變、字典-dict-可變

5.請說明循環(huán)結(jié)構(gòu)和異常處理中的 else 在什么情況下會執(zhí)行?

在 for.else 循環(huán)結(jié)構(gòu)中,當循環(huán)提全部循環(huán)完畢后,沒有 break 或者 return 的情況下,會執(zhí)行 else 代碼段;
在異常處理中,try 下的代碼段沒有出現(xiàn)異常的情況下,會執(zhí)行 else 代碼

條件分支語句用 else 來表示'否則執(zhí)行某件事'

6.列舉python函數(shù)定義中有哪些不同的參數(shù)類型?

1.位置參數(shù):根據(jù)參數(shù)在函數(shù)定義中的位置來確定。
2.默認參數(shù):在函數(shù)定義中指定的參數(shù)值。
3.關(guān)鍵字參數(shù):在調(diào)用函數(shù)時指定參數(shù)名稱和對應的值。
4.星號參數(shù):在函數(shù)定義中使用來捕獲剩余的參數(shù)。
5.雙星號參數(shù):在函數(shù)定義中使用
* 來捕獲剩余的關(guān)鍵字參數(shù)。

7.python中==和is的區(qū)別?

==比較的是兩個對象的值,is 比較的是兩個對象的內(nèi)存地址。
不能用 is 替代==,僅當你需要判斷某個對象是否是 None、False、True 時,使用 is,其他情況下請使用==。

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)于賦值或者復制后 id() 是否異同的知識點,結(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.請描述global關(guān)鍵字在什么條件下必須被使用?

在函數(shù)局部要重新賦值全局變量之前,需要使用 global 關(guān)鍵字聲明全局變量。

9.請說明if name == 'main':語句的作用?

在 Python 中,當一個模塊被執(zhí)行時,if name == 'main':語句塊會被執(zhí)行。此語句塊可以用來測試模塊的代碼,而不會影響模塊的其他功能。
如果模塊被其他模塊導入,則name的值為該模塊的名稱,而不是main。如果該模塊是主程序,則name的值為main,此時該語句塊會被執(zhí)行。
這樣的語句使得可以在模塊被其他模塊導入時忽略測試代碼,并且只在模塊被獨立運行時執(zhí)行測試代碼。

10.面向?qū)ο缶幊逃心娜筇匦??請說明各個特性的意義。

封裝:隱藏內(nèi)部狀態(tài)和實現(xiàn)細節(jié),僅提供必要的接口給外部使用。
繼承:允許創(chuàng)建新的對象類型,并基于現(xiàn)有的對象類型派生,從而繼承其行為和狀態(tài)。
多態(tài):允許不同類型的對象對相同消息做出不同的響應。

11.類反射中常用的方法及含義?

常用的類反射方法有:

type(object):獲取對象的類型,返回一個 type 對象。
isinstance(object, classinfo):判斷對象是否是某種類型的實例,返回布爾值。
issubclass(class, classinfo):判斷一個類是否是另一個類的子類,返回布爾值。
getattr(object, name[, default]):獲取對象的屬性或方法,如果不存在,可以返回 default 參數(shù)指定的默認值。
hasattr(object, name):判斷對象是否具有某個屬性或方法,返回布爾值。
setattr(object, name, value):設(shè)置對象的屬性值。
delattr(object, name):刪除對象的屬性。
使用類反射可以動態(tài)地獲取和操作類的信息,是動態(tài)語言的重要特性。

12.python中創(chuàng)建一個新線程有哪幾種方式?

1.使用 threading 模塊:通過定義一個繼承自 Thread 的類并重寫其 run 方法,然后通過該類的實例調(diào)用 start 方法啟動線程。
2.使用 multiprocessing 模塊:通過使用 Process 類創(chuàng)建新的進程。
3.使用協(xié)程:通過使用生成器實現(xiàn)協(xié)程,在協(xié)程內(nèi)部通過 yield 實現(xiàn)非阻塞的多任務(wù)執(zhí)行。
多線程編程是高并發(fā)編程的一種常見形式,可以提高程序的執(zhí)行效率。

13.python中GIL全局解釋器鎖在什么情況下會被釋放?

Python 中的 GIL (Global Interpreter Lock) 是一種機制,它限制任意時刻僅有一個線程可以運行在 Python 解釋器中。GIL 在以下情況下會被釋放:
解釋器在執(zhí)行 CPU 密集型任務(wù)時:例如運算,在這種情況下,GIL 會每隔一定時間被釋放,以便其他線程有機會被調(diào)度執(zhí)行。
解釋器在執(zhí)行 I/O 密集型任務(wù)時:例如讀取文件,在這種情況下,由于 I/O 操作需要等待外部設(shè)備,所以 GIL 會在 I/O 操作期間被釋放。
GIL 可能會影響多線程程序的性能,因此通常不建議在 Python 中開發(fā) CPU 密集型的多線程程序??梢允褂枚噙M程來代替多線程以提高性能。

14.描述編寫裝飾器的原則是什么?

1.不改變原函數(shù)的內(nèi)部邏輯
2.不改變原函數(shù)的調(diào)用方法

15.現(xiàn)在有一個Animal類有初始化方法定義如下:

class Animal:
def init(self, skin, legs):
self.skin = skin
self.legs = legs

如果現(xiàn)在想定義一個Dog類,并繼承于這個Animal類,并想給這個Dog類增加一個nickname對象屬性,Dog類的初始化方法應該怎么定義才能保證 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 中的一種特殊方法,用于引用父類。它常用于多重繼承,當子類需要調(diào)用父類的方法時,就可以使用 super 方法。這個方法可以直接調(diào)用父類的方法,而無需顯式命名父類名稱。

16.文件zen.txt中保存著python之禪,請使用python代碼統(tǒng)計該文件中每個單詞出現(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.編寫一個裝飾器,使用該裝飾器能夠顯示任意函數(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__}運行花費了:{end_time-start_time:.2f} 秒。')
       return result
   return wrapper@running_timedef take_time():
   time.sleep(2)take_time()----------------------------------------------------take_time運行花費了:2.01 秒。

18.用兩種方法合并下面列表

x = ['a', 'b']y = ['c', 'd', 'e']x.extend(y)# 或x += y

19.計算得到列表當中長度最長的字符串words = ['Python', 'is', 'awesome']

words = ['Python', 'is', 'awesome']# 我的笨方法s = ''for _ in words:
   if len(_) > len(s):
       s = _print(s)# 標答給的方法
# 使用內(nèi)置函數(shù) max() 和 len() 計算,在 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()方法(改變原列表)words.reverse()print(words)# 方法2,列表切片(生成新列表,原列表不變)w = words[::-1]print(w)

21.將字典當中的鍵值對位置調(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)# 標答給的方法(字典推導式)inverted_staff = {v: k for k, v in staff.items()}print(inverted_staff)

22.將嵌套列表合并為一個列表

l = [[1, 2, 3], [4, 5], [6], [7, 8], [9]]

答:

# 針對此題目,我想到的是循環(huán)遍歷result = []for i in l:
   for n in i:
       result.append(n)print(result)# 標答給的方法1:
# 在 sum() 函數(shù)中使用的第二個參數(shù)是空列表,表示從空列表開始計算和。
merged_list = sum(l, [])print(merged_list) # 標答給的方法2:列表推導式merged_list = [item for sublist in l for item in sublist]print(merged_list)# 可如上3個方法只能針對此題目,一旦題目列表沒這么規(guī)范,比如下面的列表,那么如上3個方法就無法實現(xiàn)l = [0, [1, 2, [3]], [4, 5], [6], [7, 8], [9]]# 能夠同時解決如上問題的方法是使用遞歸函數(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.列表當中數(shù)據(jù)類型的轉(zhuǎn)換

  • 我們要將其轉(zhuǎn)換成整數(shù)類型====>['1', '2', '3']

  • 我們要將其轉(zhuǎ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.將列表當中的重復元素去除

['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']# 我想到的是列表推導式l = [i for i in cars if i == 'Volvo']print(l)# 標答使用filterl2 = filter(lambda car: car == 'Volvo', cars)print(list(l2))# filter 函數(shù)在 Python 中返回一個過濾器對象,它是一個迭代器,所以想打印值需要使用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ù)鍵來對字典進行排序

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ù)鍵值來對字典進行排序

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()方法不會改變原字符串,會生成新值ss = s.replace('P','p')print(ss)

32.計算指定字符串出現(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'])# 標答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ù)列是一個數(shù)列,其中的每個數(shù)都是前兩個數(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 里的一種特殊賦值語句,可以把可迭代對象 (列表,元祖,字典,字符串) 一次性賦給多個值。

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ù)量和列表中元素數(shù)量應保持一致,否則報'SyntaxError: cannot assign to literal';

  • 如果可迭代對象是字典,則變量個數(shù)要等于字典中的鍵值對個數(shù),若不指定字典的取值,則默認取字典的 key 值,若指定字典的值為 items(),則變量為字典鍵值對的元組形式;

37.有一個key為姓名,value為年齡的字典,根據(jù)年齡正序排列姓名,并輸出姓名列表,若沒有年齡,則放在最后;

users = {'tom': 19, 'jerry': 13, 'jack': None, 'andrew': 43}

答:
知識點:在排序前將年齡為 None 的值變更為正無窮大;

  • 正無窮:float('inf')

  • 負無窮:float('-inf')

# 我想到的方法:
# 先將字典中年齡為None的值變更成正無窮大
def key_func(users):
   for key in users.keys():
       if users[key] is None:
           users[key] = float('inf')# 根據(jù)年齡進行正序排序,最后以列表形式輸入排序好的姓名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):
   '''
   接收一個key為姓名,value為年齡的字典,根據(jù)年齡正序排列姓名,若沒有年齡,則放在最后
   :param users: 用戶名:年齡字典
   :return: 返回姓名列表
   '''

   def key_func(username):
       age = users[username]
       # 當年齡為空時,返回正無窮大作為key,因此就會被排到最后        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.合并字典的多種方式?

  • 方式 1:update

d1 = {'name': 'Lili', 'score': 90}d2 = {'name': 'Tom', 'hobby': 'run'}d1.update(d2)print(d1)-----------------------------{'name': 'Tom', 'score': 90, 'hobby': 'run'}# 這種方法會改變d1的原始值
  • 方式 2:編寫一個函數(shù) (不改變 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'}
  • 方式 3:解包

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'}
  • 方式 4:Python3.9 版本后可用'|'合并字典

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 對象,如:字符串,數(shù)字,元祖;

  • 3.JSON 的 key 是有序的,可以重復的;字典的 key 不能重復;

  • 4.JSON 的 key 有默認值 undefined,字典的 key 默認沒有默認值;

  • 5.JSON 的 value 可以是字符串、浮點數(shù)、布爾值、null 或者他們組成的數(shù)組或?qū)ο螅值涞?value 可以是任意類型的對象;

  • 6.JSON 的 value 訪問方式可以是 [] 或者.,字典的 value 訪問方式只能是 key 值;

  • 7.JSON 的字符串強制使用雙引號,字典的字符串可以是單引號也可以是雙引號;

  • 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

作者以往文章:

接口測試 - 從0不到1的心路歷程
接口測試 - 從0不到1的心路歷程 (二)
如何在Linux上搭建Jenkins?自動構(gòu)建接口測試實踐

TesterHome公眾號投稿指南

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多