溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Python3.8新功能有哪些

發(fā)布時(shí)間:2021-07-10 11:34:19 來(lái)源:億速云 閱讀:205 作者:小新 欄目:開(kāi)發(fā)技術(shù)

這篇文章主要為大家展示了“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ì)的模式。 

Python3.8新功能有哪些

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è)資訊頻道!

向AI問(wèn)一下細(xì)節(jié)

免責(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)容。

AI