Python3.8的新功能


 

下面就一些明顯的新功能,進行說明。

Assignment Expressions

又叫做「海象運算符」(The Walrus Operator)。因為:=很像海象「眼睛小,長着兩枚長長的牙」。

 

Python Positional-Only parameters

說白了就是強制使用者用位置參數

具體的可以看我之前寫的文章: PEP570新語法: 只接受位置參數

Python Runtime Audit Hooks

現在可以給Python運行時添加審計鈎子:

In : import sys
...: import urllib.request
...:
...:
...: def audit_hook(event, args):
...:     if event in ['urllib.Request']:
...:         print(f'Network {event=} {args=}')
...:
...: sys.addaudithook(audit_hook)

In : urllib.request.urlopen('https://httpbin.org/get?a=1')
Network event='urllib.Request' args=('https://httpbin.org/get?a=1', None, {}, 'GET')
Out: <http.client.HTTPResponse at 0x10e394310>

目前支持審計的事件名字和API可以看PEP文檔(延伸閱讀鏈接2),urllib.Request是其中之一。另外還可以自定義事件:

In : def audit_hook(event, args):
...:     if event in ['make_request']:
...:         print(f'Network {event=} {args=}')
...:

In : sys.addaudithook(audit_hook)

In : sys.audit('make_request', 'https://baidu.com')
Network event='make_request' args=('https://baidu.com',)

In : sys.audit('make_request', 'https://douban.com')
Network event='make_request' args=('https://douban.com',)

Multiprocessing shared memory

可以跨進程直接訪問同一內存(共享):

# IPython進程A
In : from multiprocessing import shared_memory

In : a = shared_memory.ShareableList([1, 'a', 0.1])

In : a
Out: ShareableList([1, 'a', 0.1], name='psm_d5d6ba1b') # 注意name
# IPython進程B(另外一個終端進入IPython)
In : from multiprocessing import shared_memory

In : b = shared_memory.ShareableList(name='psm_d5d6ba1b')  # 使用name就可以共享內存

In : b
Out: ShareableList([1, 'a', 0.1], name='psm_d5d6ba1b')

New importlib.metadata module

使用新的importlib.metadata模塊可以直接讀取第三方包的元數據:

In : from importlib.metadata import version, files, requires, distribution

In : version('flask')
Out: '1.1.1'

In : requires('requests')
Out:
['chardet (<3.1.0,>=3.0.2)',
 'idna (<2.9,>=2.5)',
 'urllib3 (!=1.25.0,!=1.25.1,<1.26,>=1.21.1)',
 'certifi (>=2017.4.17)',
 "pyOpenSSL (>=0.14) ; extra == 'security'",
 "cryptography (>=1.3.4) ; extra == 'security'",
 "idna (>=2.0.0) ; extra == 'security'",
 "PySocks (!=1.5.7,>=1.5.6) ; extra == 'socks'",
 'win-inet-pton ; (sys_platform == "win32" and python_version == "2.7") and extra == \'socks\'']

In : dist = distribution('celery')

In : dist.version
Out: '4.3.0'

In : dist.metadata['Requires-Python']
Out: '>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'

In : dist.metadata['License']

In : dist.entry_points
Out:
[EntryPoint(name='celery', value='celery.__main__:main', group='console_scripts'),
 EntryPoint(name='celery', value='celery.contrib.pytest', group='pytest11')]

In : files('celery')[8]
Out: PackagePath('celery/__init__.py')

In : dist.locate_file(files('celery')[8])
Out: PosixPath('/Users/dongweiming/test/venv/lib/python3.8/site-packages/celery/__init__.py')

 

functools.cached_property

緩存屬性 (cached_property) 是一個非常常用的功能,很多知名 Python 項目都自己實現過它,現在終於進入版本庫了。

具體的可以看我之前寫的文章: functools.cached_property(Python 3.8)

functools.lru_cache作為裝飾器時可以不加參數

lru_cache裝飾器支持max_sizetyped2個參數,如果對默認參數不敏感,過去只能這么用(需要空括號):

In : @lru_cache() ...: def add(a, b): ...: return a + b ...:

從3.8開始可以直接作為裝飾器,而不是作為返回裝飾器的函數(不加括號):

In : @lru_cache ...: def add(a, b): ...: return a + b ...:

就像dataclasses.dataclass,絕大部分場景都是這么用:

@dataclass class InventoryItem: ...

其實dataclass支持多個參數:

def dataclass(cls=None, /, *, init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False):

所以這種使用全部缺省值的裝飾器工廠用法中,括號反而顯得多余了。

Asyncio REPL

具體的可以看我之前寫的文章: asyncio REPL(Python 3.8)

F-strings DEBUG

具體的可以看我之前寫的文章: 使用f-strings調試(Python3.8)

Async Mock

單元測試模塊unittest添加了mock異步代碼的類:

In : import asyncio In : from unittest.mock import AsyncMock, MagicMock In : mock = AsyncMock(return_value={'json': 123}) In : await mock() Out: {'json': 123} In : asyncio.run(mock()) Out: {'json': 123} In : async def main(*args, **kwargs): ...: return await mock(*args, **kwargs) ...: In : asyncio.run(main()) Out: {'json': 123} In : mock = MagicMock() # AsyncMock也可以 In : mock.__aiter__.return_value = [1, 2, 3] In : async def main(): ...: return [i async for i in mock] ...: In : asyncio.run(main()) Out: [1, 2, 3]

Generalized iterable unpacking in yield and return

具體的可以看我之前寫的文章: Python3.8對「可迭代解包」的改進

 

 

改進的模塊

現在的_asdict()方法collections.namedtuple()返回一個dict而不是一個collections.OrderedDict。這是有效的,因為自Python 3.7以來,常規dicts已經保證了排序。如果需要額外的功能OrderedDict,建議的補救措施是將結果轉換為所需的類型:OrderedDict(nt._asdict())。該unicodedata模塊已升級為使用Unicode 12.0.0 版本

ASYNCIO

Windows上,現在是默認的事件循環ProactorEventLoop

gettext

添加pgettext()及其變體。

檢查

如果該屬性是值為docstrings的位置,該inspect.getdoc()函數現在可以找到文檔字符串。這提供了類似於我們已經有文件的選項,以及:__slots__dictproperty()classmethod()staticmethod()

class AudioClip:

    __slots__ = {'bit_rate': 'expressed in kilohertz to one decimal place',

                 'duration': 'in seconds, rounded up to an integer'}

    def __init__(self, bit_rate, duration):

        self.bit_rate = round(bit_rate / 1000.0, 1)

 

       self.duration = ceil(duration)

GC

get_objects()現在可以接收一個可選的生成參數,指示從中獲取對象的生成。由Pablo Galindo 提供的 bpo-36016

gzip

添加了mtime參數以gzip.compress()獲得可重現的輸出。(由Guo Ci Teobpo-34898供稿。)

idlelibIDLE

超過N行的輸出(默認為50)被壓縮到一個按鈕。可以在設置對話框的常規頁面的PyShell部分中更改N. 右鍵單擊輸出可以擠壓更少但可能超長的線條。通過雙擊按鈕或通過右鍵單擊按鈕進入剪貼板或單獨的窗口,可以擴展壓縮輸出。(由Tal Einatbpo-1529353供稿。)

上述更改已被移植到3.7維護版本。

json.tool

添加選項--json-lines以將每個輸入行解析為單獨的JSON對象。(由Weipeng Hongbpo-31553供稿。)

計算

增加math.dist()了計算兩點之間歐氏距離的新函數。

擴展了math.hypot()處理多個維度的功能。以前,它只支持2-D案例。

添加了新函數,math.prod()作為類似函數sum() 返回“start”值(默認值:1)乘以可迭代數字的乘積。

os.path

os.path返回一個布爾值結果類似功能exists()lexists()isdir() isfile()islink(),和ismount()現在回到False代替升高ValueError或它的子類 UnicodeEncodeError,並UnicodeDecodeError為包含字符或字節在OS級不可表示的路徑。

expanduser()Windows上現在更喜歡 USERPROFILE 環境變量,不使用 HOME,通常不為常規用戶帳戶設置。

ncurses

 

添加了一個新變量,其中包含底層ncurses庫的結構化版本信息:ncurses_version

pathlib

pathlib.Path返回布爾結果類似方法 exists()is_dir() is_file()is_mount() is_symlink()is_block_device() is_char_device()is_fifo() is_socket()現在回到False而不是提高 ValueError或它的子類UnicodeEncodeError的包含字符的不可表示在操作系統級別路徑。(由Serhiy Storchaka供稿於bpo-33721。)

shutil

shutil.copytree()現在接受一個新的dirs_exist_ok關鍵字參數。

SSL

添加SSLContext.post_handshake_auth以啟用和 ssl.SSLSocket.verify_client_post_handshake()啟動TLS 1.3握手后身份驗證。

統計

添加statistics.fmean()為更快的浮點變體statistics.mean()

添加statistics.multimode()了返回最常見值的列表。

添加statistics.NormalDist了一個用於創建和操作隨機變量的正態分布的工具.

>>>
>>> temperature_feb = NormalDist.from_samples([4, 12, -3, 2, 7, 14])
>>> temperature_feb
NormalDist(mu=6.0, sigma=6.356099432828281)
>>> temperature_feb.cdf(3)            # Chance of being under 3 degrees
70.3184678262814532
>>> # Relative chance of being 7 degrees versus 10 degrees
>>> temperature_feb.pdf(7) / temperature_feb.pdf(10)
1.2039930378537762
>>> el_nino = NormalDist(4, 2.5)
>>> temperature_feb += el_nino        # Add in a climate effect
>>> temperature_feb
NormalDist(mu=10.0, sigma=6.830080526611674)
>>> temperature_feb * (9/5) + 32      # Convert to Fahrenheit
NormalDist(mu=50.0, sigma=12.294144947901014)
>>> temperature_feb.samples(3)        # Generate random samples
[7.672102882379219, 12.000027119750287, 4.647488369766392]

tar文件

tarfile模塊現在默認為新檔案的現代paxPOSIX.1-2001)格式,而不是之前的GNU特定格式。這通過標准化和可擴展格式的一致編碼(UTF-8)提高了跨平台的可移植性,並提供了其他一些好處。

令牌化

當提供沒有尾隨新行的輸入時,tokenize模塊現在隱式地發出NEWLINE令牌。此行為現在與C tokenizer在內部執行的操作相匹配。

Tkinter

添加的方法selection_from() selection_present() selection_range() selection_to() tkinter.Spinbox類。

moveto() tkinter.Canvas課堂上添加了方法。

時間

CLOCK_UPTIME_RAWmacOS 10.12 添加了新時鍾。

unicodedata

新函數is_normalized()可用於驗證字符串是否處於特定的正常形式。

單元測試

添加addModuleCleanup() addClassCleanup()進行unittest以支持setUpModule()和的 清理setUpClass()

VENV

venv現在,Activate.ps1PowerShell Core 6.1下,所有平台上都包含一個用於激活虛擬環境的腳本。

XML

作為對DTD和外部實體檢索的緩解,默認情況下, xml.dom.minidomxml.sax模塊不再處理外部實體。

 

C API的變化

-堆分配類型的實例(例如用其創建的實例 PyType_FromSpec())保存對其類型對象的引用。增加這些類型對象的引用計數已從 PyType_GenericAlloc()更低級別的函數移動, PyObject_Init()並且PyObject_INIT()。這使得通過PyType_FromSpec()托管代碼中的其他類行為創建類型。

靜態分配的類型不受影響。

對於絕大多數情況,應該沒有副作用。但是,在分配實例(可能是為了解決bug)之后手動增加引用計數的類型現在可能變得不朽。為避免這種情況,這些類需要在實例釋放期間在類型對象上調用Py_DECREF

要將這些類型正確移植到3.8,請應用以下更改:

Py_INCREF分配實例后刪除類型對象 - 如果有的話。這可能打完電話后發生的PyObject_New() PyObject_NewVar()PyObject_GC_New() PyObject_GC_NewVar(),或使用任何其他自定義分配器 PyObject_Init()PyObject_INIT()

例:

static foo_struct *
foo_new(PyObject *type) {
    foo_struct *foo = PyObject_GC_New(foo_struct, (PyTypeObject *) type);
    if (foo == NULL)
        return NULL;
#if PY_VERSION_HEX < 0x03080000
    	// Workaround for Python issue 35810; no longer necessary in Python 3.8
    	PY_INCREF(type)
#endif
    return foo;
}

確保 tp_dealloc堆分配類型的所有自定義函數都減少了類型的引用計數。

例:

static void
foo_dealloc(foo_struct *instance) {
    PyObject *type = Py_TYPE(instance);
    PyObject_GC_Del(instance);
#if PY_VERSION_HEX >= 0x03080000
    // This was not needed before Python 3.8 (Python issue 35810)
    Py_DECREF(type);
#endif
}

  

CPython字節碼更改

通過移動將塊堆棧展開到編譯器中的邏輯,簡化了解釋器循環。編譯器現在發出顯式指令,用於調整值堆棧並調用清理代碼breakcontinue return

刪除操作碼BREAK_LOOPCONTINUE_LOOP SETUP_LOOPSETUP_EXCEPT。增加了新的操作碼ROT_FOURBEGIN_FINALLYCALL_FINALLY POP_FINALLY。改變了END_FINALLYWITH_CLEANUP_START。 添加了新的操作碼,END_ASYNC_FOR`用於處理在等待循環中的下一個項目時引發的異常。

 

 

參考文章

What’s New In Python 3.8

Python 3.8 新功能都有啥,與 3.7 有哪些不同?,19.4

Python 3.8正式發布,帶來那些新特性?,19.10

 


免責聲明!

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



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