Python 3.8.0 正式版發布,新特性初體驗


北京時間 10 月 15 日,Python 官方發布了 3.8.0 正式版,該版本較 3.7 版本再次帶來了多個非常實用的新特性。

賦值表達式

PEP 572: Assignment Expressions

新增一種新語法形式::=,又稱為“海象運算符”(為什么叫海象,看看這兩個符號像不像顏表情),如果你用過 Go 語言,應該對這個語法非常熟悉。

具體作用我們直接用實例來展示,比如在使用正則匹配時,以往版本中我們會如下寫:

import re

pattern = re.compile('a')
data = 'abc'
match = pattern.search(data)
if match is not None:
    print(match.group(0))

而使用賦值表達式時,我們可以改寫為:

if (match := pattern.search(data)) is not None:
    print(match.group(0))

在 if 語句中同時完成了求值、賦值變量、變量判斷三步操作,再次簡化了代碼。

下面是在列表表達式中的用法:

filtered_data = [y for x in data if (y := func(x)) is not None]

強制位置參數

PEP 570: Python Positional-Only parameters

新增一個函數形參標記:/,用來表示標記左側的參數,都只接受位置參數,不能使用關鍵字參數形式。

>>> def pow(x, y, z=None, /):
...     r = x ** y
...     return r if z is None else r%z
...
>>> pow(5, 3)
125
>>> pow(x=5, y=3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: pow() takes no keyword arguments

這實際上是用純 Python 代碼來模擬現有 C 代碼實現的內置函數中類似功能,比如內置函數 len('string') 傳參是不能使用關鍵字參數的。

Runtime 審計鈎子

PEP 578: Python Runtime Audit Hooks

這讓我們可以對某些事件和 API 添加一些鈎子,用於在運行時監聽事件相關的參數。

比如這里監聽 urllib 請求:

>>> import sys
>>> import urllib.request
>>> def audit_hook(event, args):
...     if event in ['urllib.Request']:
...         print(f'{event=} {args=}')
...
>>> sys.addaudithook(audit_hook)
>>> urllib.request.urlopen('https://httpbin.org/get?a=1')
event = 'urllib.Request' args =( 'https://httpbin.org/get?a=1' , None , {}, 'GET' )
<http.client.HTTPResponse object at 0x108f09b38>

官方內置了一些 API,具體可查看 PEP-578 規范文檔,也可以自定義。

f-strings 支持等號

在 Python 3.6 版本中增加了 f-strings,可以使用 f 前綴更方便地格式化字符串,同時還能進行計算,比如:

>>> x = 10
>>> print(f'{x+1}')
11

在 3.8 中只需要增加一個 = 符號,即可拼接運算表達式與結果:

>>> x = 10
>>> print(f'{x+1=}')
'x+1=11'

這個特性官方指明了適用於 Debug。

Asyncio 異步交互模式

在之前版本的 Python 交互模式中(REPL),涉及到 Asyncio 異步函數,通常需要使用 asyncio.run(func()) 才能執行。

而在 3.8 版本中,當使用 python -m asyncio 進入交互模式,則不再需要 asyncio.run

>>> import asyncio
>>> async def test():
...     await asyncio.sleep(1)
...     return 'test'
...
>>> await test()
'test'

跨進程共享內存

在 Python 多進程中,不同進程之間的通信是常見的問題,通常的方式是使用 multiprocessing.Queue 或者 multiprocessing.Pipe,在 3.8 版本中加入了 multiprocessing.shared_memory,利用專用於共享 Python 基礎對象的內存區域,為進程通信提供一個新的選擇。

from multiprocessing import Process
from multiprocessing import shared_memory

share_nums = shared_memory.ShareableList(range(5))

def work1(nums):
    for i in range(5):
        nums[i] += 10
    print('work1 nums = %s'% nums)

def work2(nums):
    print('work2 nums = %s'% nums)

if __name__ == '__main__':
    p1 = Process(target=work1, args=(share_nums, ))
    p1.start()
    p1.join()
    p2 = Process(target=work2, args=(share_nums, ))
    p2.start()

# 輸出結果:
# work1 nums = [10, 11, 12, 13, 14]
# work2 nums = [10, 11, 12, 13, 14]

以上代碼中 work1 與 work2 雖然運行在兩個進程中,但都可以訪問和修改同一個 ShareableList 對象。

@cached_property

熟悉 Python Web 開發的同學,對 werkzeug.utils.cached_propertydjango.utils.functional.cached_property 這兩個裝飾器一定非常熟悉,它們是內置 @property 裝飾器的加強版,被裝飾的實例方法不僅變成了屬性調用,還會自動緩存方法的返回值。

現在官方終於加入了自己的實現:

>>> import time
>>> from functools import cached_property
>>> class Example:
...     @cached_property
...     def result(self):
...         time.sleep(1) # 模擬計算耗時
...         print('work 1 sec...')
...         return 10
...
>>> e = Example()
>>> e.result
work 1 sec...
10
>>> e.result # 第二次調用直接使用緩存,不會耗時
10

其他改進

  • PEP 587: Python 初始化配置
  • PEP 590: Vectorcall,用於 CPython 的快速調用協議
  • finally: 中現在允許使用 continue
  • typed_ast 被合並回 CPython
  • pickle 現在默認使用協議4,提高了性能
  • LOAD_GLOBAL 速度加快了 40%
  • unittest 加入了異步支持
  • 在 Windows 上,默認 asyncio 事件循環現在是 ProactorEventLoop
  • 在 macOS 上,multiprocessing 啟動方法默認使用 spawn

更多具體變化,可查看 What’s New In Python 3.8


本文屬於原創內容,首發於微信公眾號「面向人生編程」,如需轉載請在公眾號后台留言。

關注后回復以下信息獲取更多資源
回復【資料】獲取 Python / Java 等學習資源
回復【插件】獲取爬蟲常用的 Chrome 插件
回復【知乎】獲取最新知乎模擬登錄


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM