作者 | 小劉
來源 | 菜鳥學Python
繼3.7版本之后Python再次發布了新版本,雖然新版本帶來了不少調整,但是其中很大一部分都是對代碼底層設計的修改,又或是typing、pickle等不常用的功能,對多數用戶而言影響不大, 今天我想重點聊一聊那些將對我們的代碼編寫產生較大影響的新功能。
在體驗開始前先說下準備工作,由于Python3.8還沒有正式發布,因此通過Anaconda的多版本管理搭建Python3.8新環境的方法是行不通的,我的做法是到官網下載對應的最新版本后單獨安裝。
為了避免與現有環境沖突,將其更名為Python38(下圖),
下文中的Python如無特殊說明均為Python3.6, Python38為Python3.8
。
接下來就正式開始新特性體驗。
1.字典逆序
我們都知道Python中的字典是無序的,Python3.6對這一問題進行了修訂,默認情況下會按照鍵的創建順序進行排序,但也僅限于此,你無法像列表那樣對字典直接進行排序操作。
這一情況在Python3.8中進一步得到改善,Python3.8中reversed()方法增加了對字典對象的支持,可以對字典進行逆序操作 。
在下面這段代碼中,對字典進行簡單的迭代,將會按照順序輸出字典的鍵。
現在改變一下代碼,加入reversed()方法:
先來看使用Python3.6的運行結果(下圖),可以看到在Python3.6中,字典是不支持recersed()方法的。
然后用Python3.8運行結果如下可以看到,字典按照鍵創建順序的逆序進行了輸出。雖然只是非常小的一點功能提升,但是在某些場景下對于字典對象的應用可能會起到非常關鍵的作用。
2.位置參數
在Python3.8中的參數傳遞方面引入了一個新的特性:PEP 570 Positional-Only Argument——限定位置參數,下面就詳細聊聊這究竟是怎么回事。
一般來說,Python中的參數傳遞有三種形式:位置參數、關鍵字參數和可變參數,為了避免不必要的麻煩,規定在可變參數之后只允許使用關鍵字參數。可是即便如此 還是給程序員們留下了很大的自由空間,比如在可變參數之前,位置參數和關鍵字參數的使用幾乎不受限制。 這樣就出現了一個問題,假如一個團隊中很多人進行合作開發,函數的定義形式和調用模式是很難規范和統一的 。
因此Python3.8就引入了一個“Positional-Only Argument”的概念和分隔符“/”,在分隔符“/”左側的參數,只允許使用位置參數的形式進行傳遞。
舉個例子來進行說明,首先建立下面這樣一個函數,由于函數中使用了分隔符“/”,因此只能使用Python3.8運行。
def add_num(x, y, z=100, /, a=100): ????print(x + y + z + a)
????print(x + y + z + a)
嘗試以下面這種方式調用函數:
add_num(1, 2, z=4, a=5)
結果在運行的時候發生了報錯:
接著嘗試全部以位置參數的形式調用函數(如下),結果順利執行。可見 “Positional-Only Argument”對分隔符“/”右側的參數形式并沒有限制 。
# 輸入add_num(1, 2, 4, 5)# 輸出12
add_num(1, 2, 4, 5)
#
輸出
12
那么如果只給定前兩個參數,后面兩個參數使用默認值又如何呢?通過下面的調用可以發現,也是可以正常運行的。
# 輸入add_num(1, 2)# 輸出203
add_num(1, 2)
#
輸出
203
通過上面這個例子我們發現Python3.8對于參數傳遞的限制僅僅作用于分隔符“/”的左側,而且只是在函數調用時發生作用。
3.賦值表達式
Python3.8中新增了賦值表達式“:=”操作符,簡單來說就是把運算操作和賦值操作放在了一起,有點類似于“a+=b”這種表達方式,我想賦值表達式的出現應該是python追求簡潔的傳統理念所致。
來看下面這段代碼,在func函數的if語句中,運算、賦值、判斷操作在同一條語句中完成,即使變量a原本不存在也沒關系。
# 輸入def func(x, y, z): ????if (a := x + y) != z: ????????print(a) ????else: ????????print(z)func(1, 2, 5)# 輸出3
def
func
(x, y, z)
:
????if
(a := x + y) != z:
????????print(a)
????else
:
????????print(z)
func(
1
,
2
,
5
)
# 輸出
3
當然,就上面這段代碼本身來看,將 x+y 的結果進行賦值似乎意義不大,但是如果運算表達式的計算量非常大或者要進行大規模獨寫等操作的話,重復執行對代碼的效率將造成大的影響;而如果事先對運算表達式賦值則需要多寫一行代碼。
目前來看,賦值表達式最重要的作用就是使代碼變得更加簡潔,至于運行效率的差異,目前還沒有驗證。
4.快速調試
在之前的Python版本中,“f表達式”——f'{expr}'的作用與eval()函數基本相同,例如:
-
f'{[1, 2, 3, 4, 5, 6]}'的結果是列表[1, 2, 3, 4, 5, 6];
-
f'{3 + 2}'的結果是運算后的值5。
Python3.8中對該功能進行了優化,f'{expr}'語句中增加了對等號“=”的支持,在保留原來功能的基礎上,還能夠同時輸出運算表達式本身。
例如執行先面這段代碼,除了計算并輸出運算結果外,還會將“=”和其左側的算式一并輸出:
x = 3print(f'{x * 2 = }')
print(
f'
{x *
2
= }
'
)
執行結果:
f'{expr}'不僅適用于基本的算術運算,還能夠進行其他對象的操作,以列表為例,令lst=[1, 2, 3, 4, 5, 6],現在對其進行擴展操作:
lst = eval('[1, 2, 3, 4, 5, 6]')print(f'{lst = }')print(f'{lst + [7] = }')
print(
f'
{lst = }
'
)
print(
f'
{lst + [
7
] = }
'
)
運行結果如下:
函數運算同樣適用,例如對兩個列表求交集,執行下面這段代碼:
lst1 = [1, 2, 3, 4, 5]lst2 = [3, 5, 7]print(f'{list(set(lst1).intersection(set(lst2))) = }')
lst2 = [
3
,
5
,
7
]
print(
f'
{list(set(lst1).intersection(set(lst2))) = }
'
)
運行結果:
相比僅輸出結果,連帶運算表達式一起輸出有助于定位檢查,在調試代碼的時候使用真的是快捷又方便 。
5.共享內存
進程是系統進行資源分配的獨立單位,在以前的python版本中,進程間的數據交互只能通過Queue、Pipes等方式來實現,數據無法直接共享。
在Python 3.8中,multiprocessing模塊提供了SharedMemory類,可以在不同的Python進程之間創建共享的內存block 。目前支持int、float、str、bytes、bool、None、numpy.ndarray等一部分Python對象。
還是舉個例子來進行說明,在下面這段代碼中建立了2個進程,在進程1中對列表中的每個元素執行+10操作,進程1結束后執行進程2,輸出列表內容。
由于進程之間數據無法共享,因此進程2中輸出的列表是沒有進行過+10操作的內容:
現在我們對代碼進行一下小小的修改,nums不是作為一個普通的list,而是作為一個共享內存對象來創建,代碼如下:
由于shared_memory是Python3.8中的新增內容,因此在Python3.6下運行會出錯,我們還是用Python3.8來運行這段代碼(結果如下)可以看到,進程2中輸出的結果與進程1中是一樣的,兩個進程之間通過shared_memory實現了數據共享。
當然,shared_memory在實際應用中肯定不會如此簡單,
-
比如SharedMemory.ShareableList和SharedMemory.SharedMemory的使用本身有很多規則和限制、
-
比如需要考慮數據鎖的問題等等,
-
但是共享內存確實為進程間通訊提供了一個新的解決方案,而且據說其通訊效率也是非常之高的。
Python3.8發布的新特性和新功能還有很多,對一些內置模塊的改進和優化則更多, 想嘗鮮 的同學可以 點擊閱讀原文,了解Python3.8詳情! 你對Python3.8新特性怎么看,歡迎吱一聲留言!
—————————————
往期精彩:
-
人民日報終發文:國航“避重就輕、不作為、護犢子、體驗差、聽不進批評”
-
華為延期,三星下架,講講折疊屏為什么這么難
-
遇事不決賴毛子,美國這次打算封殺變臉APP
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
