您好,登錄后才能下訂單哦!
這篇文章主要為大家展示了“Python3.8新功能有哪些”,內(nèi)容簡(jiǎn)而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“Python3.8新功能有哪些”這篇文章吧。
Python3.8有哪些你要關(guān)注的新內(nèi)容?
Python3.8 都有哪些新功能,在文檔手冊(cè)中,大家可以有一個(gè)概覽。這么多新內(nèi)容,哪些是大家最先要關(guān)注一下的呢?下面,營(yíng)長(zhǎng)就帶大家從深度和廣度兩方面,了解那些最大的變化,幫助大家快速上手 Python3.8.
新功能手冊(cè):
https://docs.python.org/3.8/whatsnew/3.8.html
在本文中,你將了解到Python 3.8如何:
使用賦值表達(dá)式簡(jiǎn)化一些代碼結(jié)構(gòu)
在你自己的函數(shù)中強(qiáng)制執(zhí)行僅位置參數(shù)
指定更精確的類型提示
使用f字符串進(jìn)行更簡(jiǎn)單的調(diào)試
除了少數(shù)例外,Python 3.8對(duì)早期版本進(jìn)行了許多小的改進(jìn)。在本文結(jié)尾處,你將看到許多這些不太引人注意的更改,并討論了一些使Python 3.8比其先前版本更快的優(yōu)化。最后,你還會(huì)獲得一些有關(guān)升級(jí)到新版本的建議。
一、賦值表達(dá)式(Assignment expressions)
引入賦值表達(dá)式,可以說(shuō)是Python3.8 中最大的一個(gè)變化了。注意,現(xiàn)在已經(jīng)用新的符號(hào)了(:=),形似海象側(cè)牙,也被稱為“海象運(yùn)算符”。賦值表達(dá)式可以在統(tǒng)一表達(dá)式中賦值并返回值,比如下面的代碼,執(zhí)行給變量分配值,并打印這個(gè)值
>>> walrus = False >>> print(walrus) False Python3.8中,可以使用 walrus 運(yùn)算符將上面兩個(gè)語(yǔ)句合并為一句 >>> print(walrus := True) True
賦值表達(dá)式可以把 True 分配給 walrus,并直接 print 這個(gè)值。一定要有(:= ),不然表達(dá)式也是無(wú)法正常執(zhí)行的,有了新的賦值表達(dá)式符號(hào),不僅在構(gòu)造上更簡(jiǎn)便,有時(shí)也可以更清楚的傳達(dá)代碼意圖。
比如,在while循環(huán)中,就體現(xiàn)了(:= )的優(yōu)勢(shì)
inputs = list() current = input("Write something: ") while current != "quit": inputs.append(current) current = input("Write something: ")
上面的這段代碼并不夠優(yōu)秀,需要不斷重復(fù) input 語(yǔ)句,并且需要以某種方式加到 current 列表中,然后在執(zhí)行后面的代碼,更好的解決方案是設(shè)置一個(gè)無(wú)限 while 循環(huán),然后用 break停止循環(huán)
inputs = list() while True: current = input("Write something: ") if current == "quit": break inputs.append(current)
這段代碼與上面的代碼是等效的,不過(guò),如果使用賦值表達(dá)式,還可以再進(jìn)一步簡(jiǎn)化這段循環(huán):
inputs = list() while (current := input("Write something: ")) != "quit": inputs.append(current)
現(xiàn)在的代碼雖然更簡(jiǎn)化了,但是可讀性就變差了,所以,大家要使用賦值表達(dá)式的方法還需要結(jié)合自身進(jìn)行判斷。
PEP572中描述了復(fù)制表達(dá)式的所有細(xì)節(jié),大家可以深入閱讀。
https://www.python.org/dev/peps/pep-0572/ https://www.python.org/dev/peps/pep-0572/#examples
僅位置參數(shù)(Positional-Only Arguments)
內(nèi)置函數(shù) float()可用于將文本字符串和數(shù)字類型轉(zhuǎn)換成 float 對(duì)象,如下面的代碼
>>> float("3.8") 3.8 >>> help(float) class float(object) | float(x=0, /) | | Convert a string or number to a floating point number, if possible. [...] float (/) 中 (/) 是什么意思?有關(guān)這部分內(nèi)容的討論可以參考下面的文檔,今天的內(nèi)容中不做為我們的重點(diǎn)內(nèi)容 PEP 457 -- Notation For Positional-Only Parameters https://www.python.org/dev/peps/pep-0457/
事實(shí)證明,雖然float() 調(diào)用了參數(shù) x,但并不允許使用其名稱
>>> float(x="3.8") Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: float() takes no keyword arguments
使用 float() 時(shí),只允許按位置指定參數(shù),而不能使用關(guān)鍵字參數(shù)。Python3.8 之前,這類僅位置參數(shù)只適用于內(nèi)置參數(shù),在我們自己定義的函數(shù)中,沒(méi)有簡(jiǎn)單的方法指定參數(shù)為僅位置參數(shù)。
>>> def incr(x): ... return x + 1 ... >>> incr(3.8) 4.8 >>> incr(x=3.8) 4.8
上面這段代碼使用了 *args,模擬了僅位置參數(shù),但是不夠靈活,不易讀,而在 Python3.8 中,可以用 / 來(lái)表示必須通過(guò)僅位置參數(shù)之前的參數(shù),可以重寫(xiě)incr()接收位置參數(shù):
>>> def incr(x, /): ... return x + 1 ... >>> incr(3.8) 4.8 >>> incr(x=3.8) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: incr() got some positional-only arguments passed as keyword arguments: 'x'
通過(guò)在 x 之后加入 /,就可以指定 x 為 僅位置參數(shù)。常規(guī)參數(shù)與僅位置參數(shù)結(jié)合使用,可將常規(guī)參數(shù)放在 / 之后:
>>> def greet(name, /, greeting="Hello"): ... return f"{greeting}, {name}" ... >>> greet("?ukasz") 'Hello, ?ukasz' >>> greet("?ukasz", greeting="Awesome job") 'Awesome job, ?ukasz' >>> greet(name="?ukasz", greeting="Awesome job") Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: greet() got some positional-only arguments passed as keyword arguments: 'name'
greet() 中,/ 放在 name 和 greeting 之間,表示 name 是僅位置參數(shù),greeting 是可以通過(guò)位置或關(guān)鍵字傳遞的常規(guī)參數(shù)。
大家可能覺(jué)得僅位置參數(shù)的可讀性似乎并不好,但是使用后會(huì)發(fā)現(xiàn),很多情況下,只有僅位置參數(shù)可以優(yōu)化我們的代碼。此外,使用僅位置函數(shù)還有一個(gè)好處,可以更輕松地重構(gòu)函數(shù),更改函數(shù)的名稱時(shí),不必?fù)?dān)心給其他代碼帶來(lái)的影響。僅位置函數(shù)還很好的補(bǔ)充了僅關(guān)鍵字參數(shù),可以使用 * 指定僅關(guān)鍵字參數(shù):
>>> def to_fahrenheit(*, celsius): ... return 32 + celsius * 9 / 5 ... >>> to_fahrenheit(40) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: to_fahrenheit() takes 0 positional arguments but 1 was given >>> to_fahrenheit(celsius=40) 104.0
上段代碼中,celsius 是僅關(guān)鍵字參數(shù)。
還可以通過(guò)按 / 和分隔的順序組合僅位置、常規(guī)和僅關(guān)鍵字參數(shù) *,例如下段代碼中,text 是僅位置參數(shù),border 是常規(guī)參數(shù)(值為默認(rèn)值),并且 width 是僅關(guān)鍵字參數(shù)(值為默認(rèn)值):
>>> def headline(text, /, border="?", *, width=50): ... return f" {text} ".center(width, border) ...text 是僅位置參數(shù),因此不能使用關(guān)鍵字 text: >>> headline("Positional-only Arguments") '??????????? Positional-only Arguments ????????????' >>> headline(text="This doesn't work!") Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: headline() got some positional-only arguments passed as keyword arguments: 'text' border 既可以使用關(guān)鍵字,也可以不使用關(guān)鍵字指定: >>> headline("Python 3.8", "=") '=================== Python 3.8 ===================' >>> headline("Real Python", border=":") ':::::::::::::::::: Real Python :::::::::::::::::::'
最后,width 必須用關(guān)鍵字指定:
>>> >>> headline("Python", "?", width=38) '??????????????? Python ???????????????' >>> headline("Python", "?", 38) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: headline() takes from 1 to 2 positional arguments but 3 were given
更多詳細(xì)類型
此時(shí),Python的類型系統(tǒng)已經(jīng)相當(dāng)成熟。但是,在Python 3.8中,鍵入中添加了一些新功能,以允許進(jìn)行更精確的鍵入:
文字類型
打字字典
最終對(duì)象
協(xié)定
Python支持可選的類型提示,通常作為代碼上的注釋:
def double(number: float) -> float: return 2 * number
在此示例中,數(shù)字應(yīng)該是浮點(diǎn)數(shù),并且double()函數(shù)也應(yīng)該返回浮點(diǎn)數(shù)。但是,Python將這些注釋視為提示。它們不會(huì)在運(yùn)行時(shí)強(qiáng)制執(zhí)行:
>>> double(3.14) 6.28 >>> double("I'm not a float") "I'm not a floatI'm not a float"
double()將“我不是浮點(diǎn)數(shù)”作為參數(shù),即使那不是浮點(diǎn)數(shù)。有些庫(kù)可以在運(yùn)行時(shí)使用類型,但這并不是Python類型系統(tǒng)的主要用例。
相反,類型提示允許靜態(tài)類型檢查器對(duì)Python代碼進(jìn)行類型檢查,而無(wú)需實(shí)際運(yùn)行腳本。這讓人想起Java,Rust和Crystal等其他語(yǔ)言會(huì)出現(xiàn)的編譯器捕獲類型錯(cuò)誤。此外,類型提示可作為代碼的文檔,使其更易于閱讀,并改善了IDE中的自動(dòng)完成功能。
注意:有幾種可用的靜態(tài)類型檢查器,包括Pyright,Pytype和Pyre。本文中使用Mypy。你可以使用pip從PyPI安裝Mypy:
從某種意義上說(shuō),Mypy是Python類型檢查器的參考實(shí)現(xiàn),并在Jukka Lehtasalo的領(lǐng)導(dǎo)下由Dropbox開(kāi)發(fā)。Python的創(chuàng)建者Guido van Rossum是Mypy團(tuán)隊(duì)的成員。
你可以在原始PEP 484和Python類型檢查(指南)中找到有關(guān)類型提示的更多信息。
PEP 484
https://www.python.org/dev/peps/pep-0484/
Python 3.8已接受并包含四個(gè)有關(guān)類型檢查的新PEP,每個(gè)都有簡(jiǎn)短示例。
PEP 586引入了文字類型。文字類型有點(diǎn)特殊,它代表一個(gè)或多個(gè)特定值。文字類型的一種用例是,當(dāng)使用字符串參數(shù)描述特定行為時(shí),能夠精確地添加類型。以下為示例:
# draw_line.py def draw_line(direction: str) -> None: if direction == "horizontal": ... # Draw horizontal line elif direction == "vertical": ... # Draw vertical line else: raise ValueError(f"invalid direction {direction!r}") draw_line("up")
該程序?qū)⑼ㄟ^(guò)靜態(tài)類型檢查器,即使“向上”是無(wú)效方向。類型檢查器僅檢查“ up”是否為字符串。在這種情況下,更準(zhǔn)確地說(shuō)方向必須是文字字符串“水平”或文字字符串“垂直”。使用文字類型,你可以完全做到這一點(diǎn):
因?yàn)榭梢詫⒎较虻脑试S值暴露給類型檢查器,你現(xiàn)在可以得到有關(guān)錯(cuò)誤的警告:
$ mypy draw_line.py draw_line.py:15: error: Argument 1 to "draw_line" has incompatible type "Literal['up']"; expected "Union[Literal['horizontal'], Literal['vertical']]" Found 1 error in 1 file (checked 1 source file)
基本語(yǔ)法是Literal [<literal>]。例如,Literal [38]代表文字值38。你可以使用Union表示多個(gè)文字值之一:
由于這是一個(gè)相當(dāng)普遍的用例,因此你可以(并且應(yīng)該)使用更簡(jiǎn)單的表示法Literal [“ horizontal”,“ vertical”]]。將類型添加到draw_line()時(shí),你已經(jīng)使用了后者。如果仔細(xì)查看上面Mypy的輸出,你會(huì)發(fā)現(xiàn)它在內(nèi)部將較簡(jiǎn)單的表示法轉(zhuǎn)換為Union表示法。
在某些情況下,函數(shù)的返回值的類型取決于輸入?yún)?shù)。一個(gè)示例是open(),它可以根據(jù)mode的值返回文本字符串或字節(jié)數(shù)組。這可以通過(guò)重載來(lái)處理。
以下示例表示計(jì)算器的流程,該計(jì)算器可以將答案返回為正數(shù)(38)或羅馬數(shù)字(XXXVIII):
# calculator.py from typing import Union ARABIC_TO_ROMAN = [(1000, "M"), (900, "CM"), (500, "D"), (400, "CD"), (100, "C"), (90, "XC"), (50, "L"), (40, "XL"), (10, "X"), (9, "IX"), (5, "V"), (4, "IV"), (1, "I")] def _convert_to_roman_numeral(number: int) -> str: """Convert number to a roman numeral string""" result = list() for arabic, roman in ARABIC_TO_ROMAN: count, number = divmod(number, arabic) result.append(roman * count) return "".join(result) def add(num_1: int, num_2: int, to_roman: bool = True) -> Union[str, int]: """Add two numbers""" result = num_1 + num_2 if to_roman: return _convert_to_roman_numeral(result) else: return result
該代碼具有正確的類型提示:add()的結(jié)果將為str或int。但是,通常會(huì)以true或False作為to_roman的值來(lái)調(diào)用此代碼,在這種情況下,你會(huì)希望類型檢查器準(zhǔn)確推斷出是否返回str或int。這可以通過(guò)使用Literal和@overload來(lái)完成:
# calculator.py from typing import Literal, overload, Union ARABIC_TO_ROMAN = [(1000, "M"), (900, "CM"), (500, "D"), (400, "CD"), (100, "C"), (90, "XC"), (50, "L"), (40, "XL"), (10, "X"), (9, "IX"), (5, "V"), (4, "IV"), (1, "I")] def _convert_to_roman_numeral(number: int) -> str: """Convert number to a roman numeral string""" result = list() for arabic, roman in ARABIC_TO_ROMAN: count, number = divmod(number, arabic) result.append(roman * count) return "".join(result) @overload def add(num_1: int, num_2: int, to_roman: Literal[True]) -> str: ... @overload def add(num_1: int, num_2: int, to_roman: Literal[False]) -> int: ... def add(num_1: int, num_2: int, to_roman: bool = True) -> Union[str, int]: """Add two numbers""" result = num_1 + num_2 if to_roman: return _convert_to_roman_numeral(result) else: return result
添加的@overload簽名將幫助你的類型檢查器根據(jù)to_roman的文字值來(lái)推斷str或int。請(qǐng)注意,省略號(hào)(...)是代碼的文字部分。它們?cè)谥剌d簽名中代表功能主體。
作為對(duì)Literal的補(bǔ)充,PEP 591引入了Final。該限定符規(guī)定不應(yīng)重新分配、重新定義或覆蓋變量或?qū)傩?。以下是輸入錯(cuò)誤:
from typing import Final ID: Final = 1 ... ID += 1
Mypy將突出顯示行ID + = 1,并請(qǐng)注意你無(wú)法將其分配給最終名稱“ ID”。這可以確保代碼中的常量值永遠(yuǎn)不變。
此外,還有一個(gè)@final裝飾器,可以將其應(yīng)用于類和方法。用@final裝飾的類不能被子類化,而@final方法不能被子類覆蓋:
from typing import final @final class Base: ... class Sub(Base): ..
Mypy將使用無(wú)法從最終類“ Base”繼承”來(lái)的錯(cuò)誤消息標(biāo)記此示例。要了解有關(guān)Final和@final的更多信息,請(qǐng)參閱PEP 591。
支持更具體類型提示的第三個(gè)PEP是PEP 589,它引入了TypedDict??梢允褂妙愃朴陬愋突疦amedTuple的符號(hào)來(lái)指定dictionaries 中鍵和值的類型。
傳統(tǒng)上,dictionaries 是使用Dict注釋的。問(wèn)題在于,這僅允許一種類型鍵和一種類型值,通常導(dǎo)致諸如Dict [str,Any]這樣的注釋。例如,一個(gè)注冊(cè)Python版本信息的dictionaries :
與version對(duì)應(yīng)的值是一個(gè)字符串,而release_year是一個(gè)整數(shù)。這無(wú)法使用Dict精確表示。使用新的TypedDict,你可以執(zhí)行以下操作:
from typing import TypedDict class PythonVersion(TypedDict): version: str release_year: int py38 = PythonVersion(version="3.8", release_year=2019
然后,類型檢查器將能夠推斷出py38 [“ version”]的類型為str,而py38 [“ release_year”]是一個(gè)int值。在運(yùn)行時(shí),TypedDict是常規(guī)dict,并且照常忽略類型提示。你也可以將TypedDict純粹用作注釋:
Mypy會(huì)告知你任何值的類型錯(cuò)誤,或者你使用的是尚未聲明的鍵。更多示例請(qǐng)參見(jiàn)PEP 589。
Mypy已經(jīng)支持協(xié)議已有一段時(shí)間了。但是,2019年5月才正式官方支持。
協(xié)議是一種規(guī)范Python對(duì)鴨子類型支持的方式:
當(dāng)我看到一只鳥(niǎo)走路像鴨子,游泳像鴨子,像鴨子一樣嘎嘎叫時(shí),我把它稱為鴨子。
鴨式類型讓你可以,比如在具有.name屬性的任何對(duì)象上讀取.name,而無(wú)需真正關(guān)心對(duì)象的類型。支持類型系統(tǒng)似乎違反直覺(jué)。通過(guò)結(jié)構(gòu)子類型轉(zhuǎn)化,仍然有可能了解鴨子的類型。
例如,你可以定義一個(gè)名為Named的協(xié)議,該協(xié)議可以標(biāo)識(shí)具有.name屬性的所有對(duì)象:
from typing import Protocol class Named(Protocol): name: str def greet(obj: Named) -> None: print(f"Hi {obj.name}"
這里,greet()可以接受任何對(duì)象,只要它定義了.name屬性即可。有關(guān)協(xié)議的更多信息,請(qǐng)參見(jiàn)PEP 544和Mypy文檔。
使用f字符串進(jìn)行更簡(jiǎn)單的調(diào)試
f字符串是在Python 3.6中引入的,已經(jīng)非常流行。它們可能是Python庫(kù)僅在3.6版及更高版本上受支持的最常見(jiàn)原因。f字符串是格式化的字符串文字。你可以通過(guò)前導(dǎo)f識(shí)別它:
>>> >>> style = "formatted" >>> f"This is a {style} string" 'This is a formatted string'
使用f字符串時(shí),可以將變量甚至表達(dá)式括在花括號(hào)內(nèi)。然后在運(yùn)行時(shí)對(duì)它們進(jìn)行評(píng)估,并將其包含在字符串中。一個(gè)f字符串中可以包含多個(gè)表達(dá)式:
在最后一個(gè)表達(dá)式{math.pi * r * r:.2f}中,還使用了格式說(shuō)明符。格式說(shuō)明符與表達(dá)式之間用冒號(hào)分隔。
.2f表示該區(qū)域被格式化為帶有2個(gè)小數(shù)的浮點(diǎn)數(shù)。格式說(shuō)明符與.format()相同。有關(guān)支持的格式說(shuō)明符完整列表,請(qǐng)參見(jiàn)官方文檔。
官方文檔
https://docs.python.org/3/library/string.html#format-specification-mini-language
在Python 3.8中,可以在f字符串中使用賦值表達(dá)式。只需確保用括號(hào)將賦值表達(dá)式括起來(lái)即可:
>>> import math >>> r = 3.8 >>> f"Diameter {(diam := 2 * r)} gives circumference {math.pi * diam:.2f}" 'Diameter 7.6 gives circumference 23.88'
但是,Python 3.8中真正的f-news是新的調(diào)試說(shuō)明符?,F(xiàn)在,你可以在表達(dá)式的末尾添加=,它將同時(shí)打印表達(dá)式及其值:
>>> python = 3.8 >>> f"{python=}" 'python=3.8'
這是種簡(jiǎn)單的方法,通常在交互式工作或添加打印語(yǔ)句來(lái)調(diào)試腳本時(shí)最為有用。在早期版本的Python中,你需要對(duì)變量或表達(dá)式進(jìn)行兩次拼寫(xiě)才能獲得相同的信息:
>>> python = 3.7 >>> f"python={python}" 'python=3.7'
你可以在=周圍添加空格,并照常使用格式說(shuō)明符:
> 10的格式說(shuō)明符表示名稱應(yīng)在10個(gè)字符串內(nèi)右對(duì)齊。=也適用于更復(fù)雜的表達(dá)式:
>>> f"{name.upper()[::-1] = }" "name.upper()[::-1] = 'CIRE'"
指導(dǎo)委員會(huì)模式(The Python Steering Council)
從技術(shù)上講,Python的管理并不是一項(xiàng)語(yǔ)言功能。但是,Python 3.8是首個(gè)不是在Guido van Rossum的仁慈獨(dú)裁統(tǒng)治下開(kāi)發(fā)的Python版本。Python語(yǔ)言現(xiàn)在由一個(gè)由五個(gè)核心開(kāi)發(fā)人員組成的指導(dǎo)委員會(huì)管理:
Barry Warsaw
Brett Cannon
Carol Willing
Guido van Rossum
Nick Coghlan
通往Python新治理模型的道路是自組織方面的一次有趣的研究。吉多·范·羅蘇姆(Guido van Rossum)在1990年代初創(chuàng)建了Python,并被親切地稱為Python的仁慈獨(dú)裁者(BDFL)。多年來(lái),Python增強(qiáng)建議書(shū)(PEP)越來(lái)越多地參與了關(guān)于Python語(yǔ)言的決策。盡管如此,Guido仍在所有新語(yǔ)言功能上都擁有最終決定權(quán)。
在對(duì)賦值表達(dá)式進(jìn)行了漫長(zhǎng)的討論之后,Guido在2018年7月宣布退出BDFL職位(這次是真的)。他故意沒(méi)有指定繼任者。相反,他要求核心開(kāi)發(fā)人員團(tuán)隊(duì)弄清楚今后應(yīng)該如何管理Python。
幸運(yùn)的是,PEP流程已經(jīng)很完善,因此使用PEP討論并決定新的治理模型順理成章。2018年秋季,PEP提出了幾種模式,包括選舉新的BDFL(更名為GUIDO),或者是放棄集中領(lǐng)導(dǎo),轉(zhuǎn)向基于共識(shí)和投票的社區(qū)模式。2018年12月,核心開(kāi)發(fā)人員投票選擇了指導(dǎo)委員會(huì)的模式。
PyCon 2019上的Python指導(dǎo)委員會(huì)。從左至右:Barry Warsaw,Brett Cannon,Carol Willing,Guido van Rossum和Nick Coghlan(圖片來(lái)源:Geir Arne Hjelle)
指導(dǎo)委員會(huì)由上圖中Python社區(qū)的五名成員組成。在每個(gè)主要的Python版本發(fā)布之后,將選舉一個(gè)新的指導(dǎo)委員會(huì)。換句話說(shuō),Python 3.8發(fā)行后將進(jìn)行一次選舉。
盡管這是一次公開(kāi)選舉,但預(yù)計(jì)大多數(shù)(甚至全部)老一屆指導(dǎo)委員會(huì)的成員將再次當(dāng)選。指導(dǎo)委員會(huì)具有決定寬泛的Python語(yǔ)言決定權(quán)力,但應(yīng)盡可能少地行使這些權(quán)力。
你可以在PEP 13中閱讀有關(guān)新治理模式的全部信息,在PEP 8000中可以看到確定新模式的過(guò)程。有關(guān)更多信息,請(qǐng)參閱PyCon 2019主題演講,并在Brett Cannon和Talk Python To Me和Changelog播客,并在GitHub上關(guān)注指導(dǎo)委員會(huì)更新信息。
其他酷炫的新功能
Python 3.8還有許多其他變化也很酷炫。
importlib.metadata
Python 3.8的標(biāo)準(zhǔn)庫(kù)中提供了一個(gè)新模塊:importlib.metadata。通過(guò)此模塊,你可以訪問(wèn)有關(guān)Python安裝中已安裝軟件包的信息。與其配套的模塊importlib.resources一起,importlib.metadata改進(jìn)了舊pkg_resources的功能。
例如,你可以獲得有關(guān)pip的一些信息:
>>> from importlib import metadata >>> metadata.version("pip") '19.2.3' >>> pip_metadata = metadata.metadata("pip") >>> list(pip_metadata) ['Metadata-Version', 'Name', 'Version', 'Summary', 'Home-page', 'Author', 'Author-email', 'License', 'Keywords', 'Platform', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Requires-Python'] >>> pip_metadata["Home-page"] 'https://pip.pypa.io/' >>> pip_metadata["Requires-Python"] '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*' >>> len(metadata.files("pip")) 668
當(dāng)前安裝的pip版本是19.2.3。metadata()可以讓你可以訪問(wèn)PyPI上看到的大多數(shù)信息。例如,你可以看到此版本的pip需要Python 2.7或Python 3.5或更高版本。使用files(),可以獲得構(gòu)成pip包的所有文件的清單。本例中約有700個(gè)文件。
files()返回Path對(duì)象的列表。你可以使用read_text()方便地查看軟件包的源代碼。以下示例從realpython-reader包中打印出__init__.py:
>>> [p for p in metadata.files("realpython-reader") if p.suffix == ".py"] [PackagePath('reader/__init__.py'), PackagePath('reader/__main__.py'), PackagePath('reader/feed.py'), PackagePath('reader/viewer.py')] >>> init_path = _[0] # Underscore access last returned value in the REPL >>> print(init_path.read_text()) """Real Python feed reader Import the `feed` module to work with the Real Python feed: >>> from reader import feed >>> feed.get_titles() ['Logging in Python', 'The Best Python Books', ...] See https://github.com/realpython/reader/ for more information """ # Version of realpython-reader package __version__ = "1.0.0" ...
您還可以訪問(wèn)包依賴關(guān)系:
>>> metadata.requires("realpython-reader") ['feedparser', 'html2text', 'importlib-resources', 'typing']
require()列出軟件包的依賴關(guān)系??梢钥吹?,例如realpython-reader在后臺(tái)使用feedparser來(lái)閱讀和解析文章提要。
PyPI上有一個(gè)importlib.metadata的反向端口,該端口在Python的早期版本上也可以用??梢允褂胮ip安裝:
try: from importlib import metadata except ImportError: import importlib_metadata as metadata ..
新增和改進(jìn)的數(shù)學(xué)和統(tǒng)計(jì)功能
Python 3.8對(duì)現(xiàn)有的標(biāo)準(zhǔn)庫(kù)軟件包和模塊進(jìn)行了許多改進(jìn)。標(biāo)準(zhǔn)庫(kù)中的數(shù)學(xué)有了一些新功能。math.prod()與內(nèi)置sum()類似,但對(duì)于乘法乘積:
>>> import math >>> math.prod((2, 8, 7, 7)) 784 >>> 2 * 8 * 7 * 7 784
這兩個(gè)語(yǔ)句是等效的。當(dāng)你把因素存儲(chǔ)在可迭代對(duì)象中時(shí),prod()將更易于使用。
另一個(gè)新功能是math.isqrt()??梢允褂胕sqrt()來(lái)找到平方根的整數(shù)部分:
9的平方根是3。你可以看到isqrt()返回整數(shù)結(jié)果,而math.sqrt()始終返回浮點(diǎn)數(shù)。15的平方根約等于3.9。請(qǐng)注意,本例中,isqrt()將答案截?cái)酁橄乱粋€(gè)整數(shù)。
最后,現(xiàn)在你可以更輕松地使用標(biāo)準(zhǔn)庫(kù)中的n維點(diǎn)和向量。使用math.dist()找到兩點(diǎn)之間的距離,并通過(guò)math.hypot()找到向量的長(zhǎng)度:
這使得使用標(biāo)準(zhǔn)庫(kù)更容易處理點(diǎn)和向量。但是,如果要對(duì)點(diǎn)或向量進(jìn)行許多計(jì)算,則應(yīng)簽出NumPy。
統(tǒng)計(jì)模塊還具有幾個(gè)新功能:
statistics.fmean()計(jì)算浮點(diǎn)數(shù)的平均值。
statistics.geometric_mean()計(jì)算浮點(diǎn)數(shù)的幾何平均值。
statistics.multimode()查找序列中最頻繁出現(xiàn)的值。
statistics.quantiles()計(jì)算用于將數(shù)據(jù)等概率分為n個(gè)連續(xù)區(qū)間的切點(diǎn)。
以下為使用這些功能的示例:
>>> import statistics >>> data = [9, 3, 2, 1, 1, 2, 7, 9] >>> statistics.fmean(data) 4.25 >>> statistics.geometric_mean(data) 3.013668912157617 >>> statistics.multimode(data) [9, 2, 1] >>> statistics.quantiles(data, n=4) [1.25, 2.5, 8.5]
在Python 3.8中,有一個(gè)新的statistics.NormalDist類,這使得高斯正態(tài)分布更加方便。
要查看使用NormalDist的示例,可以對(duì)新的statistics.fmean()和傳統(tǒng)的statistics.mean()的速度進(jìn)行比較:
>>> import random >>> import statistics >>> from timeit import timeit >>> # Create 10,000 random numbers >>> data = [random.random() for _ in range(10_000)] >>> # Measure the time it takes to run mean() and fmean() >>> t_mean = [timeit("statistics.mean(data)", number=100, globals=globals()) ... for _ in range(30)] >>> t_fmean = [timeit("statistics.fmean(data)", number=100, globals=globals()) ... for _ in range(30)] >>> # Create NormalDist objects based on the sampled timings >>> n_mean = statistics.NormalDist.from_samples(t_mean) >>> n_fmean = statistics.NormalDist.from_samples(t_fmean) >>> # Look at sample mean and standard deviation >>> n_mean.mean, n_mean.stdev (0.825690647733245, 0.07788573997674526) >>> n_fmean.mean, n_fmean.stdev (0.010488564966666065, 0.0008572332785645231) >>> # Calculate the lower 1 percentile of mean >>> n_mean.quantiles(n=100)[0] 0.64450132212
在此示例中,使用timeit來(lái)衡量mean()和fmean()的執(zhí)行時(shí)間。為了獲得可靠的結(jié)果,你可以讓timeit將每個(gè)函數(shù)執(zhí)行100次,并為每個(gè)函數(shù)收集30個(gè)這樣的時(shí)間樣本?;谶@些示例,你將創(chuàng)建兩個(gè)NormalDist對(duì)象。請(qǐng)注意,如果自行運(yùn)行代碼,則可能需要一分鐘的時(shí)間來(lái)收集不同的時(shí)間樣本。
NormalDist具有許多方便的屬性和方法,請(qǐng)參閱官方文檔查看完整列表。檢查.mean和.stdev,你會(huì)發(fā)現(xiàn)舊的statistics.mean()的運(yùn)行時(shí)間為0.826±0.078秒,而新的statistics.fmean()則為0.0105±0.0009秒。換句話說(shuō),對(duì)于這些數(shù)據(jù),fmean()的速度大約是前者的80倍。
新增危險(xiǎn)語(yǔ)法警告功能
Python有一個(gè)SyntaxWarning功能,可以警告不是SyntaxError的可疑語(yǔ)法。Python 3.8添加了一些新功能,可以在編碼和調(diào)試過(guò)程中為你提供幫助。
is和==之間的區(qū)別可能會(huì)造成混淆。后者用于檢查是否有相等的值,而只有在對(duì)象相同時(shí)才為true。Python 3.8將在應(yīng)該使用==而不是is時(shí)發(fā)出警告:
>>> # Python 3.7 >>> version = "3.7" >>> version is "3.7" False >>> # Python 3.8 >>> version = "3.8" >>> version is "3.8" <stdin>:1: SyntaxWarning: "is" with a literal. Did you mean "=="? False >>> version == "3.8" True
寫(xiě)長(zhǎng)列表時(shí),尤其是垂直格式化時(shí),很容易漏掉逗號(hào)。當(dāng)忘記元組列表中的逗號(hào)時(shí)會(huì)發(fā)出讓你不解的不可調(diào)用元組錯(cuò)誤消息。Python 3.8不僅會(huì)發(fā)出警告,還會(huì)指出實(shí)際問(wèn)題:
>>> [ ... (1, 3) ... (2, 4) ... ] <stdin>:2: SyntaxWarning: 'tuple' object is not callable; perhaps you missed a comma? Traceback (most recent call last): File "<stdin>", line 2, in <module> TypeError: 'tuple' object is not callable
該警告正確地將丟失的逗號(hào)標(biāo)識(shí)為真正的罪魁禍?zhǔn)住?/p>
優(yōu)化
Python 3.8進(jìn)行了一些優(yōu)化,有的讓代碼運(yùn)行得更快,有的優(yōu)化減少了內(nèi)存占用。例如,與Python 3.7相比,在Python 3.8中查找命名元組中的字段要快得多:
>>> >>> import collections >>> from timeit import timeit >>> Person = collections.namedtuple("Person", "name twitter") >>> raymond = Person("Raymond", "@raymondh") >>> # Python 3.7 >>> timeit("raymond.twitter", globals=globals()) 0.05876131607996285 >>> # Python 3.8 >>> timeit("raymond.twitter", globals=globals()) 0.0377705999400132
可以看到,在Python 3.8中在namedtuple上查找.twitter的速度提高了30-40%。從具有已知長(zhǎng)度的可迭代對(duì)象初始化列表時(shí),可以節(jié)省一些空間。這樣可以節(jié)省內(nèi)存:
>>> import sys >>> # Python 3.7 >>> sys.getsizeof(list(range(20191014))) 181719232 >>> # Python 3.8 >>> sys.getsizeof(list(range(20191014))) 161528168
本例中,該列表在Python 3.8中使用的內(nèi)存比Python 3.7少了大約11%。
其他優(yōu)化還包括子流程性能更高,帶有shutil的文件復(fù)制速度更快,pickle中的默認(rèn)性能提高以及operator.itemgetter操作更快。有關(guān)優(yōu)化的完整列表,請(qǐng)參見(jiàn)官方文檔。
所以,我們必須要更新到 Python3.8 嗎?
如果你想嘗鮮新功能,那是肯定要升級(jí)的。
實(shí)際產(chǎn)品的開(kāi)發(fā)環(huán)境需要升級(jí)到 Python3.8 嗎?首先,如果在 Python3.8 中運(yùn)行 3.7 版本代碼,問(wèn)題應(yīng)該不會(huì)很大;Python3.8 的beta版本也試用幾個(gè)月了,也解決了不少問(wèn)題,如果能升級(jí)到Python3.8,肯定也是安全的,還能在新版本中進(jìn)行優(yōu)化。
如果你想嘗試一下Python3.8,可以閱讀下的文檔,以幫助更好的完成移植
https://docs.python.org/3.8/whatsnew/3.8.html#porting-to-python-3-8
還有不能遺漏官方文檔:
https://www.python.org/downloads/release/python-380/
以上是“Python3.8新功能有哪些”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。