你在享受十一長假時,Python 已悄悄地變了

文 |?太陽雪
來源:Python 技術(shù)「ID: pythonall」

Python 3.9 在經(jīng)歷了將近一年的試用期后,于 10月5日(2020年)發(fā)布了穩(wěn)定版,意味著,在下一版本發(fā)布之前,不會在做改動,童鞋們可以放心大膽地更新了。享受完愜意的十一長假后,我們快來看看新版本帶來了哪些驚喜
先附上一個 16 歲印度小哥哥整理的特性圖:

節(jié)能篇
這次版本最喜人的特性事節(jié)能,不僅節(jié)省電能,更重要的是節(jié)省了敲代碼的次數(shù),以及我們寶貴的時間
字典的合并與更新
毫無疑問,字典對象(Dict)是日常編程中最常用到的數(shù)據(jù)結(jié)構(gòu),從存儲鍵值對到支持復(fù)雜算法,都依賴于字典對象,而且常用一些字段的合并、更新等操作,雖然 Python 中已經(jīng)提供了字段更新的方法和字典展開操作符( ** ),但是仍然不夠簡潔,我理解,在你看到新版本中的更新之前,不會感覺有什么不簡潔的
原來的合并:
d1?=?{'a':?'A',?'b':?'B',?'c':?'C'}
d2?=?{'d':?'D',?'e':?'E'}
d3?=?{**d1,?**d2}??#?使用展開操作符,將合并結(jié)果存入?d3
print(d3)??#?{'a':?'A',?'b':?'B',?'c':?'C',?'d':?'D',?'e':?'E'}
d1.update(d2)??#?update?方法,將?d1?d2?合并,且更新?d1
print(d1)??#?{'a':?'A',?'b':?'B',?'c':?'C',?'d':?'D',?'e':?'E'}
現(xiàn)在的合并:
d1?=?{'a':?'A',?'b':?'B',?'c':?'C'}
d2?=?{'d':?'D',?'e':?'E'}
d3?=?d1?|?d2??#?效果等同于展開操作符
print(d3)??#?{'a':?'A',?'b':?'B',?'c':?'C',?'d':?'D',?'e':?'E'}
d1?|=?d2??#?等同于?update
print(d1)??#?{'a':?'A',?'b':?'B',?'c':?'C',?'d':?'D',?'e':?'E'}
|操作符,除了對數(shù)值的與操作之外,現(xiàn)在還可以做字典對象的合并|=如果要用合并的結(jié)果更新前面的字典對象,在合并操作符后加賦值號就行
是不是簡潔多了,不僅簡潔了,而且更容易理解了
這還沒完,合并賦值操作符(|=)除了字典之間的合并,還可以合并類字典對象
先看一段代碼:
d1?=?{'a':?'A',?'b':?'B',?'c':?'C'}
l1?=?[('d',?'D'),?('e',?'E')]
d1?|=?l1
print(d1)??#?{'a':?'A',?'b':?'B',?'c':?'C',?'d':?'D',?'e':?'E'}
l1 是一個列表對象,其中的元素是二維元組 這里的特別之處在于二維元組對象,合并時,第一個元素被看成字典的 Key,第二個被看成字典的 Value,如果不是這樣,則會報錯
如果遇到這種特殊的場景,合并運算簡直太方便了,你能想到有哪些類似場景嗎?歡迎留言
拓撲排序
首先需要理解什么是拓撲圖,簡單來說就是一定空間內(nèi)若干個點之間的關(guān)系,例如對于一項工作來說,包含有若干個任務(wù),任務(wù)之間有相互依賴的關(guān)系,任務(wù)加上它們之間的關(guān)系,就構(gòu)成了一個拓撲結(jié)構(gòu)圖
拓撲排序,就是對一個拓撲圖中的點按照點之間的相互關(guān)系的一種排序
例如這樣一個拓撲圖

拓撲排序為
1、2、3、4、5
如果用算法生寫的話,需要十行以上,而且還不包括調(diào)試時間,以及為各種適應(yīng)性做的改善所花的時間
現(xiàn)在,排序只需要一行代碼:
from?graphlib?import?TopologicalSorter
tg?=?{5:?{3,?4},?4:?{2,?3},?3:?{2,?1},?2:?{1}}
ts?=?TopologicalSorter(tg)
print(list(ts.static_order()))?#?[1,?2,?3,?4,?5]
首先從 graphlib 中引入拓撲排序組件 TopologicalSorter 然后定義一個拓撲結(jié)構(gòu)圖,這里是用字典加集合的方式定義的,表示節(jié)點的前序節(jié)點是哪些 接著用排序組件對拓撲結(jié)構(gòu)進行排序,即創(chuàng)建一個排序?qū)ο?/section> 最好調(diào)用排序?qū)ο蟮? static_order方法展示排序結(jié)果
實際上最核心的就是創(chuàng)建排序?qū)ο蟮拇a,新特性提供了優(yōu)雅的封裝
說到封裝,你可能猜到他的功能并不單一,確實,排序組件 TopologicalSorter 不僅能對以及定義的結(jié)果排序,還可以對動態(tài)結(jié)構(gòu)排序,例如
from?graphlib?import?TopologicalSorter
ts?=?TopologicalSorter()
ts.add(5,?3,?4)
ts.add(4,?2,?3)
ts.add(3,?2,?1)
ts.add(2,?1)
print(list(ts.static_order()))?#?[1,?2,?3,?4,?5]
也就是說,可以逐步的將依賴添加進去,在迭代處理的情況下很方便,
需要注意的是 static_order 方法只能掉用一次,再次排序的話,需要重新創(chuàng)建 TopologicalSorter 對象
另外,如果拓撲圖結(jié)構(gòu)是個循環(huán)的,排序會報 CycleError 循環(huán)依賴錯誤
隨機字節(jié)碼
之前要產(chǎn)生隨機字節(jié)碼,需要先產(chǎn)生隨機數(shù),然后從定義的字符序列中獲取對應(yīng)位置的字符,最好再轉(zhuǎn)換為字節(jié),是挺麻煩的,現(xiàn)在,一行代碼搞定
import?random
print(random.randbytes(10))??#?b'\x0fzf\x17K\x00\xfb\x11LF'??隨機的,每次結(jié)果可能不同
最小公倍數(shù)
之前的 Python 版本中已經(jīng)實現(xiàn)了最大公約數(shù)的計算,雖然可以用最大公約數(shù)求得最小公倍數(shù),不過需要寫多行代碼(實際上我不記得怎么推送了)
現(xiàn)在,一行代碼搞定:
import?math
math.lcm(49,?14)??#?98
是不是方便多了,不信的話,和下面生算對比下:
def?lcm(num1,?num2):
??if?num1?==?num2?==?0:
????return?0
??return?num1?*?num2?//?math.gcd(num1,?num2)
lcm(49,?14)??#?98
功能篇
功能方面,Python 3.9 也做出了很多改善,下面來了解下
字符串去前綴后綴
本來字符串在 Python 中的操作已經(jīng)夠強大了,很難想到它會把去前后綴的功能作為更新,先看看效果吧
"three?cool?features?in?Python".removesuffix("?Python")
#?three?cool?features?in
"three?cool?features?in?Python".removeprefix("three?")
#?cool?features?in?Python
"three?cool?features?in?Python".removeprefix("Something?else")
#?three?cool?features?in?Python
很簡單,很容易想到用其他方式實現(xiàn),代碼也不會多,例如用 字符串的 strip 方法:
"three?cool?features?in?Python".strip("?Python")
#?ree?cool?features?i
很明顯,最終的效果并不是我們想要的,strip 會將前后遇到的字符模式一并修剪!
如果用其他方式,比如字符串查找,正則匹配等,也能實現(xiàn),不過沒有現(xiàn)成的方法方便,更重要的是,這個特性避免了自己不小心的犯錯
時區(qū)支持
對我們中國來說,時區(qū)問題不大,特別是只做在國內(nèi)使用的應(yīng)用的話,但是如果在每個,或者其他地方,時區(qū)會是個問題,之前,可以通過將時間轉(zhuǎn)換為 UTC 格式再轉(zhuǎn)為其他時區(qū)的時間,現(xiàn)在可以方便的用 zoneinfo 模塊實現(xiàn)了
zoneinfo 模塊為標(biāo)準(zhǔn)庫引入了 IANA 時區(qū)數(shù)據(jù)庫
from?zoneinfo?import?ZoneInfo
from?datetime?import?datetime
dt?=?datetime(2020,?10,?1,?1,?tzinfo=?ZoneInfo("America/Los_Angeles"))
如代碼所示,可以為本地時間設(shè)置時區(qū),將時間轉(zhuǎn)化為指定時區(qū)的時間
注意:使用 ZoneInfo 獲取時區(qū)屬性之前,需要安裝 tzdata 模塊
其他
數(shù)據(jù)類型提示
Python 本身是弱類型語言,但在一些大型項目中容易因為數(shù)據(jù)類型引入 bug,為了改善這一點,對聲明了數(shù)據(jù)類型的形參,如果實參與形參類型不符,執(zhí)行時會得到警告提醒,例如
def?fun(input:?str):
??print(str)
fun(10)??#?此時會得到數(shù)據(jù)類型不匹配的警告
更強悍的解析器
Python 3.9 重構(gòu)了解析器,雖然在日常編程中幾乎感覺不到,但這個更新確是最重要的,就行如果你感覺如履平地,必然有人在默默付出一樣
Python 之前一直使用 LL(1) 解析器將源代碼解析為解析樹,類似于一次讀取一個字符,并解釋源代碼而無需回溯的解析器。
新解釋器是基于 PEG(parsing expression grammar) 實現(xiàn)的,既高效,又靈活,不過需要使用更多的內(nèi)存
import()特性修改
__import__() 在之前的版本中,可能引發(fā) ValueError 異常,按官方解釋:ValueError 曾經(jīng)會在相對導(dǎo)入超出其最高層級包時發(fā)生 (不知所云),在新的版本中,異常時會拋出 ImportError,這樣更加合理
反正我沒遇到過,可能是沒有用過這種高級用法,就當(dāng)是學(xué)習(xí)了
總結(jié)
“人生苦短,用我 Python” —— Python 不但這么說,也這么做,當(dāng)我們享受愜意的雙節(jié)長假時,Python 默默的優(yōu)化自己,只能讓我們苦短的人生,更加精彩
還等什么,趕緊升級到 Python3.9 試試吧
參考
https://zhuanlan.zhihu.com/p/262914368 https://developer.51cto.com/art/202010/627903.htm https://blog.csdn.net/qq_42554007/article/details/107075651 https://www.sohu.com/a/422827870_114760 https://docs.python.org/zh-cn/3/whatsnew/3.9.html
PS:公號內(nèi)回復(fù)「Python」即可進入Python 新手學(xué)習(xí)交流群,一起 100 天計劃!
老規(guī)矩,兄弟們還記得么,右下角的 “在看” 點一下,如果感覺文章內(nèi)容不錯的話,記得分享朋友圈讓更多的人知道!


【代碼獲取方式】
