您好,登錄后才能下訂單哦!
這篇文章主要為大家展示了“Python3.8新功能有哪些”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領大家一起研究并學習一下“Python3.8新功能有哪些”這篇文章吧。
Python3.8有哪些你要關注的新內容?
Python3.8 都有哪些新功能,在文檔手冊中,大家可以有一個概覽。這么多新內容,哪些是大家最先要關注一下的呢?下面,營長就帶大家從深度和廣度兩方面,了解那些最大的變化,幫助大家快速上手 Python3.8.
新功能手冊:
https://docs.python.org/3.8/whatsnew/3.8.html
在本文中,你將了解到Python 3.8如何:
使用賦值表達式簡化一些代碼結構
在你自己的函數中強制執行僅位置參數
指定更精確的類型提示
使用f字符串進行更簡單的調試
除了少數例外,Python 3.8對早期版本進行了許多小的改進。在本文結尾處,你將看到許多這些不太引人注意的更改,并討論了一些使Python 3.8比其先前版本更快的優化。最后,你還會獲得一些有關升級到新版本的建議。
一、賦值表達式(Assignment expressions)
引入賦值表達式,可以說是Python3.8 中最大的一個變化了。注意,現在已經用新的符號了(:=),形似海象側牙,也被稱為“海象運算符”。賦值表達式可以在統一表達式中賦值并返回值,比如下面的代碼,執行給變量分配值,并打印這個值
>>> walrus = False >>> print(walrus) False Python3.8中,可以使用 walrus 運算符將上面兩個語句合并為一句 >>> print(walrus := True) True
賦值表達式可以把 True 分配給 walrus,并直接 print 這個值。一定要有(:= ),不然表達式也是無法正常執行的,有了新的賦值表達式符號,不僅在構造上更簡便,有時也可以更清楚的傳達代碼意圖。
比如,在while循環中,就體現了(:= )的優勢
inputs = list() current = input("Write something: ") while current != "quit": inputs.append(current) current = input("Write something: ")
上面的這段代碼并不夠優秀,需要不斷重復 input 語句,并且需要以某種方式加到 current 列表中,然后在執行后面的代碼,更好的解決方案是設置一個無限 while 循環,然后用 break停止循環
inputs = list() while True: current = input("Write something: ") if current == "quit": break inputs.append(current)
這段代碼與上面的代碼是等效的,不過,如果使用賦值表達式,還可以再進一步簡化這段循環:
inputs = list() while (current := input("Write something: ")) != "quit": inputs.append(current)
現在的代碼雖然更簡化了,但是可讀性就變差了,所以,大家要使用賦值表達式的方法還需要結合自身進行判斷。
PEP572中描述了復制表達式的所有細節,大家可以深入閱讀。
https://www.python.org/dev/peps/pep-0572/ https://www.python.org/dev/peps/pep-0572/#examples
僅位置參數(Positional-Only Arguments)
內置函數 float()可用于將文本字符串和數字類型轉換成 float 對象,如下面的代碼
>>> 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 (/) 中 (/) 是什么意思?有關這部分內容的討論可以參考下面的文檔,今天的內容中不做為我們的重點內容 PEP 457 -- Notation For Positional-Only Parameters https://www.python.org/dev/peps/pep-0457/
事實證明,雖然float() 調用了參數 x,但并不允許使用其名稱
>>> float(x="3.8") Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: float() takes no keyword arguments
使用 float() 時,只允許按位置指定參數,而不能使用關鍵字參數。Python3.8 之前,這類僅位置參數只適用于內置參數,在我們自己定義的函數中,沒有簡單的方法指定參數為僅位置參數。
>>> def incr(x): ... return x + 1 ... >>> incr(3.8) 4.8 >>> incr(x=3.8) 4.8
上面這段代碼使用了 *args,模擬了僅位置參數,但是不夠靈活,不易讀,而在 Python3.8 中,可以用 / 來表示必須通過僅位置參數之前的參數,可以重寫incr()接收位置參數:
>>> 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'
通過在 x 之后加入 /,就可以指定 x 為 僅位置參數。常規參數與僅位置參數結合使用,可將常規參數放在 / 之后:
>>> 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 是僅位置參數,greeting 是可以通過位置或關鍵字傳遞的常規參數。
大家可能覺得僅位置參數的可讀性似乎并不好,但是使用后會發現,很多情況下,只有僅位置參數可以優化我們的代碼。此外,使用僅位置函數還有一個好處,可以更輕松地重構函數,更改函數的名稱時,不必擔心給其他代碼帶來的影響。僅位置函數還很好的補充了僅關鍵字參數,可以使用 * 指定僅關鍵字參數:
>>> 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 是僅關鍵字參數。
還可以通過按 / 和分隔的順序組合僅位置、常規和僅關鍵字參數 *,例如下段代碼中,text 是僅位置參數,border 是常規參數(值為默認值),并且 width 是僅關鍵字參數(值為默認值):
>>> def headline(text, /, border="?", *, width=50): ... return f" {text} ".center(width, border) ...text 是僅位置參數,因此不能使用關鍵字 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 既可以使用關鍵字,也可以不使用關鍵字指定: >>> headline("Python 3.8", "=") '=================== Python 3.8 ===================' >>> headline("Real Python", border=":") ':::::::::::::::::: Real Python :::::::::::::::::::'
最后,width 必須用關鍵字指定:
>>> >>> 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
更多詳細類型
此時,Python的類型系統已經相當成熟。但是,在Python 3.8中,鍵入中添加了一些新功能,以允許進行更精確的鍵入:
文字類型
打字字典
最終對象
協定
Python支持可選的類型提示,通常作為代碼上的注釋:
def double(number: float) -> float: return 2 * number
在此示例中,數字應該是浮點數,并且double()函數也應該返回浮點數。但是,Python將這些注釋視為提示。它們不會在運行時強制執行:
>>> double(3.14) 6.28 >>> double("I'm not a float") "I'm not a floatI'm not a float"
double()將“我不是浮點數”作為參數,即使那不是浮點數。有些庫可以在運行時使用類型,但這并不是Python類型系統的主要用例。
相反,類型提示允許靜態類型檢查器對Python代碼進行類型檢查,而無需實際運行腳本。這讓人想起Java,Rust和Crystal等其他語言會出現的編譯器捕獲類型錯誤。此外,類型提示可作為代碼的文檔,使其更易于閱讀,并改善了IDE中的自動完成功能。
注意:有幾種可用的靜態類型檢查器,包括Pyright,Pytype和Pyre。本文中使用Mypy。你可以使用pip從PyPI安裝Mypy:
從某種意義上說,Mypy是Python類型檢查器的參考實現,并在Jukka Lehtasalo的領導下由Dropbox開發。Python的創建者Guido van Rossum是Mypy團隊的成員。
你可以在原始PEP 484和Python類型檢查(指南)中找到有關類型提示的更多信息。
PEP 484
https://www.python.org/dev/peps/pep-0484/
Python 3.8已接受并包含四個有關類型檢查的新PEP,每個都有簡短示例。
PEP 586引入了文字類型。文字類型有點特殊,它代表一個或多個特定值。文字類型的一種用例是,當使用字符串參數描述特定行為時,能夠精確地添加類型。以下為示例:
# 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")
該程序將通過靜態類型檢查器,即使“向上”是無效方向。類型檢查器僅檢查“ up”是否為字符串。在這種情況下,更準確地說方向必須是文字字符串“水平”或文字字符串“垂直”。使用文字類型,你可以完全做到這一點:
因為可以將方向的允許值暴露給類型檢查器,你現在可以得到有關錯誤的警告:
$ 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)
基本語法是Literal [<literal>]。例如,Literal [38]代表文字值38。你可以使用Union表示多個文字值之一:
由于這是一個相當普遍的用例,因此你可以(并且應該)使用更簡單的表示法Literal [“ horizontal”,“ vertical”]]。將類型添加到draw_line()時,你已經使用了后者。如果仔細查看上面Mypy的輸出,你會發現它在內部將較簡單的表示法轉換為Union表示法。
在某些情況下,函數的返回值的類型取決于輸入參數。一個示例是open(),它可以根據mode的值返回文本字符串或字節數組。這可以通過重載來處理。
以下示例表示計算器的流程,該計算器可以將答案返回為正數(38)或羅馬數字(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()的結果將為str或int。但是,通常會以true或False作為to_roman的值來調用此代碼,在這種情況下,你會希望類型檢查器準確推斷出是否返回str或int。這可以通過使用Literal和@overload來完成:
# 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簽名將幫助你的類型檢查器根據to_roman的文字值來推斷str或int。請注意,省略號(...)是代碼的文字部分。它們在重載簽名中代表功能主體。
作為對Literal的補充,PEP 591引入了Final。該限定符規定不應重新分配、重新定義或覆蓋變量或屬性。以下是輸入錯誤:
from typing import Final ID: Final = 1 ... ID += 1
Mypy將突出顯示行ID + = 1,并請注意你無法將其分配給最終名稱“ ID”。這可以確保代碼中的常量值永遠不變。
此外,還有一個@final裝飾器,可以將其應用于類和方法。用@final裝飾的類不能被子類化,而@final方法不能被子類覆蓋:
from typing import final @final class Base: ... class Sub(Base): ..
Mypy將使用無法從最終類“ Base”繼承”來的錯誤消息標記此示例。要了解有關Final和@final的更多信息,請參閱PEP 591。
支持更具體類型提示的第三個PEP是PEP 589,它引入了TypedDict。可以使用類似于類型化NamedTuple的符號來指定dictionaries 中鍵和值的類型。
傳統上,dictionaries 是使用Dict注釋的。問題在于,這僅允許一種類型鍵和一種類型值,通常導致諸如Dict [str,Any]這樣的注釋。例如,一個注冊Python版本信息的dictionaries :
與version對應的值是一個字符串,而release_year是一個整數。這無法使用Dict精確表示。使用新的TypedDict,你可以執行以下操作:
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”]是一個int值。在運行時,TypedDict是常規dict,并且照常忽略類型提示。你也可以將TypedDict純粹用作注釋:
Mypy會告知你任何值的類型錯誤,或者你使用的是尚未聲明的鍵。更多示例請參見PEP 589。
Mypy已經支持協議已有一段時間了。但是,2019年5月才正式官方支持。
協議是一種規范Python對鴨子類型支持的方式:
當我看到一只鳥走路像鴨子,游泳像鴨子,像鴨子一樣嘎嘎叫時,我把它稱為鴨子。
鴨式類型讓你可以,比如在具有.name屬性的任何對象上讀取.name,而無需真正關心對象的類型。支持類型系統似乎違反直覺。通過結構子類型轉化,仍然有可能了解鴨子的類型。
例如,你可以定義一個名為Named的協議,該協議可以標識具有.name屬性的所有對象:
from typing import Protocol class Named(Protocol): name: str def greet(obj: Named) -> None: print(f"Hi {obj.name}"
這里,greet()可以接受任何對象,只要它定義了.name屬性即可。有關協議的更多信息,請參見PEP 544和Mypy文檔。
使用f字符串進行更簡單的調試
f字符串是在Python 3.6中引入的,已經非常流行。它們可能是Python庫僅在3.6版及更高版本上受支持的最常見原因。f字符串是格式化的字符串文字。你可以通過前導f識別它:
>>> >>> style = "formatted" >>> f"This is a {style} string" 'This is a formatted string'
使用f字符串時,可以將變量甚至表達式括在花括號內。然后在運行時對它們進行評估,并將其包含在字符串中。一個f字符串中可以包含多個表達式:
在最后一個表達式{math.pi * r * r:.2f}中,還使用了格式說明符。格式說明符與表達式之間用冒號分隔。
.2f表示該區域被格式化為帶有2個小數的浮點數。格式說明符與.format()相同。有關支持的格式說明符完整列表,請參見官方文檔。
官方文檔
https://docs.python.org/3/library/string.html#format-specification-mini-language
在Python 3.8中,可以在f字符串中使用賦值表達式。只需確保用括號將賦值表達式括起來即可:
>>> 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是新的調試說明符。現在,你可以在表達式的末尾添加=,它將同時打印表達式及其值:
>>> python = 3.8 >>> f"{python=}" 'python=3.8'
這是種簡單的方法,通常在交互式工作或添加打印語句來調試腳本時最為有用。在早期版本的Python中,你需要對變量或表達式進行兩次拼寫才能獲得相同的信息:
>>> python = 3.7 >>> f"python={python}" 'python=3.7'
你可以在=周圍添加空格,并照常使用格式說明符:
> 10的格式說明符表示名稱應在10個字符串內右對齊。=也適用于更復雜的表達式:
>>> f"{name.upper()[::-1] = }" "name.upper()[::-1] = 'CIRE'"
指導委員會模式(The Python Steering Council)
從技術上講,Python的管理并不是一項語言功能。但是,Python 3.8是首個不是在Guido van Rossum的仁慈獨裁統治下開發的Python版本。Python語言現在由一個由五個核心開發人員組成的指導委員會管理:
Barry Warsaw
Brett Cannon
Carol Willing
Guido van Rossum
Nick Coghlan
通往Python新治理模型的道路是自組織方面的一次有趣的研究。吉多·范·羅蘇姆(Guido van Rossum)在1990年代初創建了Python,并被親切地稱為Python的仁慈獨裁者(BDFL)。多年來,Python增強建議書(PEP)越來越多地參與了關于Python語言的決策。盡管如此,Guido仍在所有新語言功能上都擁有最終決定權。
在對賦值表達式進行了漫長的討論之后,Guido在2018年7月宣布退出BDFL職位(這次是真的)。他故意沒有指定繼任者。相反,他要求核心開發人員團隊弄清楚今后應該如何管理Python。
幸運的是,PEP流程已經很完善,因此使用PEP討論并決定新的治理模型順理成章。2018年秋季,PEP提出了幾種模式,包括選舉新的BDFL(更名為GUIDO),或者是放棄集中領導,轉向基于共識和投票的社區模式。2018年12月,核心開發人員投票選擇了指導委員會的模式。
PyCon 2019上的Python指導委員會。從左至右:Barry Warsaw,Brett Cannon,Carol Willing,Guido van Rossum和Nick Coghlan(圖片來源:Geir Arne Hjelle)
指導委員會由上圖中Python社區的五名成員組成。在每個主要的Python版本發布之后,將選舉一個新的指導委員會。換句話說,Python 3.8發行后將進行一次選舉。
盡管這是一次公開選舉,但預計大多數(甚至全部)老一屆指導委員會的成員將再次當選。指導委員會具有決定寬泛的Python語言決定權力,但應盡可能少地行使這些權力。
你可以在PEP 13中閱讀有關新治理模式的全部信息,在PEP 8000中可以看到確定新模式的過程。有關更多信息,請參閱PyCon 2019主題演講,并在Brett Cannon和Talk Python To Me和Changelog播客,并在GitHub上關注指導委員會更新信息。
其他酷炫的新功能
Python 3.8還有許多其他變化也很酷炫。
importlib.metadata
Python 3.8的標準庫中提供了一個新模塊:importlib.metadata。通過此模塊,你可以訪問有關Python安裝中已安裝軟件包的信息。與其配套的模塊importlib.resources一起,importlib.metadata改進了舊pkg_resources的功能。
例如,你可以獲得有關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
當前安裝的pip版本是19.2.3。metadata()可以讓你可以訪問PyPI上看到的大多數信息。例如,你可以看到此版本的pip需要Python 2.7或Python 3.5或更高版本。使用files(),可以獲得構成pip包的所有文件的清單。本例中約有700個文件。
files()返回Path對象的列表。你可以使用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" ...
您還可以訪問包依賴關系:
>>> metadata.requires("realpython-reader") ['feedparser', 'html2text', 'importlib-resources', 'typing']
require()列出軟件包的依賴關系。可以看到,例如realpython-reader在后臺使用feedparser來閱讀和解析文章提要。
PyPI上有一個importlib.metadata的反向端口,該端口在Python的早期版本上也可以用。可以使用pip安裝:
try: from importlib import metadata except ImportError: import importlib_metadata as metadata ..
新增和改進的數學和統計功能
Python 3.8對現有的標準庫軟件包和模塊進行了許多改進。標準庫中的數學有了一些新功能。math.prod()與內置sum()類似,但對于乘法乘積:
>>> import math >>> math.prod((2, 8, 7, 7)) 784 >>> 2 * 8 * 7 * 7 784
這兩個語句是等效的。當你把因素存儲在可迭代對象中時,prod()將更易于使用。
另一個新功能是math.isqrt()。可以使用isqrt()來找到平方根的整數部分:
9的平方根是3。你可以看到isqrt()返回整數結果,而math.sqrt()始終返回浮點數。15的平方根約等于3.9。請注意,本例中,isqrt()將答案截斷為下一個整數。
最后,現在你可以更輕松地使用標準庫中的n維點和向量。使用math.dist()找到兩點之間的距離,并通過math.hypot()找到向量的長度:
這使得使用標準庫更容易處理點和向量。但是,如果要對點或向量進行許多計算,則應簽出NumPy。
統計模塊還具有幾個新功能:
statistics.fmean()計算浮點數的平均值。
statistics.geometric_mean()計算浮點數的幾何平均值。
statistics.multimode()查找序列中最頻繁出現的值。
statistics.quantiles()計算用于將數據等概率分為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中,有一個新的statistics.NormalDist類,這使得高斯正態分布更加方便。
要查看使用NormalDist的示例,可以對新的statistics.fmean()和傳統的statistics.mean()的速度進行比較:
>>> 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來衡量mean()和fmean()的執行時間。為了獲得可靠的結果,你可以讓timeit將每個函數執行100次,并為每個函數收集30個這樣的時間樣本。基于這些示例,你將創建兩個NormalDist對象。請注意,如果自行運行代碼,則可能需要一分鐘的時間來收集不同的時間樣本。
NormalDist具有許多方便的屬性和方法,請參閱官方文檔查看完整列表。檢查.mean和.stdev,你會發現舊的statistics.mean()的運行時間為0.826±0.078秒,而新的statistics.fmean()則為0.0105±0.0009秒。換句話說,對于這些數據,fmean()的速度大約是前者的80倍。
新增危險語法警告功能
Python有一個SyntaxWarning功能,可以警告不是SyntaxError的可疑語法。Python 3.8添加了一些新功能,可以在編碼和調試過程中為你提供幫助。
is和==之間的區別可能會造成混淆。后者用于檢查是否有相等的值,而只有在對象相同時才為true。Python 3.8將在應該使用==而不是is時發出警告:
>>> # 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
寫長列表時,尤其是垂直格式化時,很容易漏掉逗號。當忘記元組列表中的逗號時會發出讓你不解的不可調用元組錯誤消息。Python 3.8不僅會發出警告,還會指出實際問題:
>>> [ ... (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
該警告正確地將丟失的逗號標識為真正的罪魁禍首。
優化
Python 3.8進行了一些優化,有的讓代碼運行得更快,有的優化減少了內存占用。例如,與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%。從具有已知長度的可迭代對象初始化列表時,可以節省一些空間。這樣可以節省內存:
>>> import sys >>> # Python 3.7 >>> sys.getsizeof(list(range(20191014))) 181719232 >>> # Python 3.8 >>> sys.getsizeof(list(range(20191014))) 161528168
本例中,該列表在Python 3.8中使用的內存比Python 3.7少了大約11%。
其他優化還包括子流程性能更高,帶有shutil的文件復制速度更快,pickle中的默認性能提高以及operator.itemgetter操作更快。有關優化的完整列表,請參見官方文檔。
所以,我們必須要更新到 Python3.8 嗎?
如果你想嘗鮮新功能,那是肯定要升級的。
實際產品的開發環境需要升級到 Python3.8 嗎?首先,如果在 Python3.8 中運行 3.7 版本代碼,問題應該不會很大;Python3.8 的beta版本也試用幾個月了,也解決了不少問題,如果能升級到Python3.8,肯定也是安全的,還能在新版本中進行優化。
如果你想嘗試一下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新功能有哪些”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。