Python 3.8 新特性全面解讀

pythontab發表於2019-04-03

新功能

編譯的位元組碼檔案的並行檔案系統快取

新的 PYTHONPYCACHEPREFIX設定(也可用 )將隱式位元組碼快取配置為使用單獨的並行檔案系統樹,而不是每個源目錄中的預設子目錄。-X pycache_prefix__pycache__

報告快取的位置sys.pycache_prefix(None表示pycache子目錄中的預設位置)。

其他語言變更

一個continue說法是非法finally條款因與實施問題。在Python 3.8中,這一限制被取消了。

該int型別現在具有as_integer_ratio()與現有float.as_integer_ratio()方法相容的新方法.

增加了對\N{name}的支援。

Dict和dictviews現在可以使用反向插入順序進行迭代 reversed()。

函式呼叫中允許關鍵字名稱的語法進一步受到限制。特別是,f((keyword)=arg)不再允許。它從來沒有打算在關鍵字引數賦值術語的左側允許多於一個裸名稱。見bpo-34641。

現在允許Iterable解包,而不使用括號yield 和return語句。(由David Cuthbert和Jordan Chapman在bpo-32117中提供。)

不是有效轉義序列的反斜槓字元對DeprecationWarning從Python 3.6開始生成。在Python 3.8中它生成了一個SyntaxWarning代替。(由Serhiy Storchaka供稿於bpo-32912。)

SyntaxWarning在某些情況下,編譯器會在元組或列表之前錯過逗號時生成。例如:

data = [

    (1, 2, 3) # oops, missing comma!

    (4, 5, 6)

]

子類之間的算術運算datetime.date或 datetime.datetime與datetime.timedelta物件現在返回子類的例項,而不是基類。這也會影響其實現(直接或間接)使用datetime.timedelta算術的操作的返回型別,例如 datetime.datetime.astimezone()。

當Python直譯器被Ctrl-C(SIGINT)中斷並且KeyboardInterrupt未捕獲到的結果異常時,Python程式現在透過SIGINT訊號或正確的退出程式碼退出,以便呼叫程式可以檢測到它因Ctrl而死亡-C。POSIX和Windows上的shell使用它來正確終止互動式會話中的指令碼。

改進的模組

現在的_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 Teo在bpo-34898供稿。)

idlelib和IDLE

超過N行的輸出(預設為50)被壓縮到一個按鈕。可以在“設定”對話方塊的“常規”頁面的PyShell部分中更改N. 右鍵單擊輸出可以擠壓更少但可能超長的線條。透過雙擊按鈕或透過右鍵單擊按鈕進入剪貼簿或單獨的視窗,可以擴充套件壓縮輸出。(由Tal Einat在bpo-1529353供稿。)

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

json.tool

新增選項--json-lines以將每個輸入行解析為單獨的JSON物件。(由Weipeng Hong在bpo-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
0.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模組現在預設為新檔案的現代pax(POSIX.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_RAW為macOS 10.12 新增了新時鐘。

unicodedata

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

單元測試

新增addModuleCleanup()並 addClassCleanup()進行unittest以支援setUpModule()和的 清理setUpClass()。

VENV

venv現在,Activate.ps1在PowerShell Core 6.1下,所有平臺上都包含一個用於啟用虛擬環境的指令碼。

XML

作為對DTD和外部實體檢索的緩解,預設情況下, xml.dom.minidom和xml.sax模組不再處理外部實體。

最佳化

subprocess現在,模組可以os.posix_spawn()在某些情況下使用該功能以獲得更好的效能。目前,如果滿足所有這些條件,它僅用於macOS和Linux

-close_fds為false;

未設定preexec_fn,pass_fds,cwd和start_new_session引數;

該可執行檔案路徑中包含一個目錄。

-shutil.copyfile(),shutil.copy(),shutil.copy2(), shutil.copytree()並shutil.move()使用特定於平臺的“快速複製”在Linux,MacOS的和Solaris,以更有效地複製檔案系統呼叫。“快速複製”意味著複製操作發生在核心中,避免在Python中使用使用者空間緩衝區,如“ outfd.write(infd.read())”。在Windows上shutil.copyfile()使用更大的預設緩衝區大小(1 MiB而不是16 KiB),並使用memoryview()基於a 的變體 - shutil.copyfileobj()。在同一分割槽中複製512 MiB檔案的速度在Linux上約為+ 26%,在macOS上為+ 50%,在Windows上為+ 40%。此外,消耗的CPU週期更少。請參閱與平臺相關的高效複製操作部分。

shutil.copytree()使用os.scandir()函式和依賴它的所有複製函式使用快取os.stat()值。複製具有8000個檔案的目錄的速度在Linux上約為+ 9%,在Windows上為+ 20%,在Windows SMB共享上為+ 30%。此外,os.stat() 系統呼叫的數量減少了38%,使shutil.copytree()網路檔案系統的速度更快。

-pickle模組中的預設協議現在是協議4,首先在Python 3.4中引入。與Python 3.0以來提供的Protocol 3相比,它提供了更好的效能和更小的尺寸。

刪除了一個Py_ssize_t成員PyGC_Head。所有GC跟蹤物件(例如元組,列表,字典)的大小減少了4或8個位元組。

uuid.UUID現在用於slots__減少其記憶體佔用。 -效能提升operator.itemgetter()了33%。最佳化引數處理併為單個非負整數索引的常見情況新增快速路徑到元組(這是標準庫中的典型用例)。 -加速欄位查詢collections.namedtuple()。它們現在的速度提高了兩倍以上,使它們成為Python中最快的例項變數查詢形式。 -list如果輸入iterable具有已知長度(輸入實現__len),則建構函式不會全域性定位內部項緩衝區。這使得建立的列表平均減少12%。(由Raymond Hettinger和Pablo Galindo在bpo-33234中提供。)

-將類變數寫入的速度加倍。更新非dunder屬性時,會有不必要的更新插槽呼叫。(由Stefan Behnel,Pablo Galindo Salgado,Raymond Hettinger,Neil Schemenauer和Serhiy Storchaka供稿於bpo-36012。)

-減少轉換傳遞給許多內建函式和方法的引數的開銷。加快呼叫一些簡單的內建函式和方法,最多可達20-50%。(由Serhiy Storchaka在bpo-23867, bpo-35582和bpo-36127供稿。)

構建和C API更改

這些PyByteArray_Init()和PyByteArray_Fini()功能已被刪除。他們沒有做任何事情,因為Python 2.7.4和Python 3.2.0被排除在有限的API(穩定的ABI)之外,並且沒有記錄。

結果PyExceptionClass_Name()現在是型別 而不是。const char *char *

二元性Modules/Setup.dist和 Modules/Setup已被刪除。以前,在更新CPython原始碼樹時,必須手動將Modules/Setup.dist(在原始碼樹內)複製到 Modules/Setup(在構建樹內)以反映上游的任何更改。這對包裝商來說是一個小小的好處,代價是CPython開發後開發人員經常煩惱,因為忘記複製檔案可能會導致構建失敗。

現在構建系統總是從Modules/Setup源樹內部讀取。鼓勵想要自定義該檔案的人將其更改儲存在CPython的git fork中或作為補丁檔案,就像它們對源樹的任何其他更改一樣。

將Python數轉換為C整數的 PyLong_AsLong()函式和引數解析函式(如 PyArg_ParseTuple()整數轉換格式單位)'i' 現在將使用__index__()特殊方法而不是( int__()如果可用)。將使用_int_()方法但沒有 _index_()方法(如Decimal和 Fraction)為物件發出棄用警告。 PyNumber_Check()現在將返回 1實現的物件__index()。

堆分配的型別物件現在將增加它們PyObject_Init()(和它的並行宏PyObject_INIT)中的引用計數而不是in PyType_GenericAlloc()。可能需要調整修改例項分配或釋放的型別。

不支援

不建議使用的方法getchildren(),getiterator()在ElementTree模組現在發出 DeprecationWarning來代替PendingDeprecationWarning。它們將在Python 3.9中刪除。

傳遞一個不是concurrent.futures.ThreadPoolExecutorto的例項的物件已 asyncio.loop.set_default_executor()被棄用,並且將在Python 3.9中被禁止。

該getitem()方法xml.dom.pulldom.DOMEventStream, wsgiref.util.FileWrapper並fileinput.FileInput已被棄用。

這些方法的實現忽略了它們的索引引數,而是返回下一個專案。

該typing.NamedTuple已否決了,_field_types贊成的屬性__annotations__具有相同資訊的屬性。

ast類Num,Str,Bytes,NameConstant和 Ellipsis被標記是過時的,並將在未來的Python版本中刪除。Constant應該用來代替。

下面的函式和方法棄用在gettext 模組:lgettext(),ldgettext(), lngettext()和ldngettext()。它們返回編碼的位元組,如果翻譯的字串存在編碼問題,則可能會出現意外的與Unicode相關的異常。在Python 3中使用返回Unicode字串的替代方法要好得多。這些功能已經被打破了很長時間。

功能bind_textdomain_codeset(),方法 output_charset()和 set_output_charset(),以及程式碼集 的功能引數translation()和install()也不贊成使用,因為它們僅用於為l*gettext()功能。

-該isAlive()方法threading.Thread已被棄用。

許多帶有整數引數的內建函式和擴充套件函式現在將為Decimals,Fractions和任何其他物件發出棄用警告, 這些物件只能在丟失的情況下轉換為整數(例如,具有int__() 方法但沒有__index()方法)。在將來的版本中,它們將是錯誤的。

API和功能刪除

從`Python 3.8`中刪除了以下功能和API:

macpath已刪除在Python 3.7中棄用的模組。

該函式platform.popen()已被刪除,自Python 3.3以來已被棄用:os.popen()改為使用。

該pyvenv指令碼已被刪除, 以幫助消除關於 指令碼繫結的Python直譯器的混淆。python3.8 -m venvpyvenv

parse_qs,parse_qsl和escape從除去cgi 模組。它們已從Python 3.2或更早版本棄用。

filemode功能已從tarfile模組中刪除。自Python 3.3以來,它沒有記錄和棄用。

該XMLParser構造不再接受HTML引數。它從未產生過影響,在Python 3.4中已被棄用。所有其他引數現在都是僅關鍵字。

刪除了doctype()方法XMLParser。

unicode_internal編解碼器被刪除。

移植

本節列出了先前描述的更改以及可能需要更改程式碼的其他錯誤修正。

Python行為的變化

屈服表示式(both yield和子句)現在在理解和生成器表示式中是不允許的(除了最左邊的子句中的可迭代表示式)

編譯器現在生成一個SyntaxWarning何時身份檢查 與某些型別的文字(例如字串,整數)一起使用。這些通常可以在CPython中偶然使用,但不受語言規範的保證。警告建議使用者使用相等測試。

Python API的變化

該函式platform.popen()已被刪除,自Python 3.3以來已被棄用:os.popen()改為使用。

statistics.mode()給定多模態資料時,該函式不再引發異常。相反,它返回輸入資料中遇到的第一個模式。

該類的selection()方法 tkinter.ttk.Treeview不再需要引數。在Python 3.6中不推薦使用帶有引數來更改選擇。使用專門的方法,如selection_set()更改選擇。

writexml(),toxml()並且toprettyxml()所述的方法 xml.dom.minidom模組,和xml.etree現在儲存由使用者指定的屬性順序。(

-dbm.dumb使用flags開啟的資料庫'r'現在是隻讀的。 dbm.dumb.open()帶有標誌'r','w'如果不存在則不再建立資料庫。

將不再呼叫doctype()子類中定義的方法, XMLParser並且將導致發出a RuntimeWarning而不是a DeprecationWarning。doctype()在目標上定義用於處理XML doctype宣告的方法。

一個RuntimeError是現在時引發自定義的元類不提供classcell__傳入的名稱空間項 type.__new。A DeprecationWarning是在Python 3.6-3.7中發出的。

在cProfile.Profile類現在可以作為一個上下文管理器。

shutil.copyfile(),shutil.copy(),shutil.copy2(), shutil.copytree()並shutil.move()使用特定於平臺的“快速複製”的系統呼叫

shutil.copyfile()Windows上的預設緩衝區大小從16 KiB更改為1 MiB。

PyGC_Head結構完全改變了。觸及struct成員的所有程式碼都應該被重寫。

PyInterpreterState結構已被移入“內部”標頭檔案(特別是Include / internal / pycore_pystate.h)。opaque PyInterpreterState仍然可用作公共API(和穩定的ABI)的一部分。文件表明struct的欄位都不公開,所以我們希望沒有人使用它們。但是,如果您確實依賴於一個或多個私有欄位而沒有其他選擇,那麼請開啟一個BPO問題。我們將努力幫助您進行調整(可能包括向公共API新增訪問器功能)。

ASYNCIO任務現在可以命名,或者透過將name關鍵字引數asyncio.create_task()或create_task()事件迴圈的方法,或者透過呼叫set_name()任務物件的方法。任務名稱在repr()輸出中可見,asyncio.Task也可以使用該get_name()方法檢索。

mmap.flush()方法現在返回None成功並在所有平臺下引發錯誤異常。以前,它的行為是平臺依賴的:成功時返回非零值; 在Windows下錯誤返回零。成功返回零值; 在Unix下出現異常錯誤。

該函式math.factorial()不再接受非int類的引數。

xml.dom.minidom和xml.sax模組預設不再處理外部實體。

從只讀dbm資料庫(dbm.dumb, dbm.gnu或dbm.ndbm)中刪除金鑰會引發error(dbm.dumb.error, dbm.gnu.error或dbm.ndbm.error)而不是KeyError。

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

使用#在分析或建築價值的形式變體(例如 PyArg_ParseTuple(),Py_BuildValue(),PyObject_CallFunction()沒有等)PY_SSIZE_T_CLEAN定義提出了DeprecationWarning現在。它將在3.10或4.0中刪除。閱讀解析引數併為細節構建值。(由Inada Naoki在bpo-36381供稿。)

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位元組碼更改

透過移動將塊堆疊展開到編譯器中的邏輯,簡化了直譯器迴圈。編譯器現在發出顯式指令,用於調整值堆疊並呼叫清理程式碼break,continue和 return。

刪除操作碼BREAK_LOOP,CONTINUE_LOOP, SETUP_LOOP和SETUP_EXCEPT。增加了新的操作碼ROT_FOUR,BEGIN_FINALLY,CALL_FINALLY和 POP_FINALLY。改變了END_FINALLY和WITH_CLEANUP_START。 新增了新的操作碼,END_ASYNC_FOR`用於處理在等待迴圈中的下一個專案時引發的異常。


相關文章