Python2寿命只剩一个月啦!还不快赶紧学起Python3酷炫到爆的新特性!
Python3.8已經(jīng)發(fā)布了將近一個月了,距離Python3.0第一個版本發(fā)布也將超過10年了。相信很多人還是依舊在使用Python2.7版本,想要遷移到最新版本卻不知道怎么能夠快速掌握其中最Amazing的方法。下面這篇文章,我會給大家推薦3.0版本依賴最最新潮的函數(shù)和語法,讓你們能夠在Review代碼時候“脫穎而出”!
前言
首先我們先來講幾個時間點:
Python2.7正式停止維護時間 2020年1月1日,距今還有1個多月
Python3.8正式開始發(fā)布時間 2019年10月14日,距今將近1個多月
從這兩個數(shù)字我們可以看出,Python3這個大版本已經(jīng)發(fā)展很長的時間了,而距離Python2.7的結(jié)束也越來越近了。在距離Python2.7停止維護的一年內(nèi),很多優(yōu)秀開源項目都已經(jīng)停止了對 2.7 的支持,例如到今年 1 月份,NumPy 將停止支持 Python 2;到今年年末,Ipython、Cython 和 Pandas 等等都將陸續(xù)停止支持 Python 2。
所以,為了響應號召,順應趨勢。我們慢慢的向Python3.X去遷移,那我們?nèi)绾文軌蚩焖俚恼莆誔ython3.X版本的精髓呢?下面我們從幾個有趣的新特性入手,這些特性或方法都是 Python 3 各個版本中新加的,它們相比傳統(tǒng)的 Python 方法,更容易解決實踐中的一些問題。
所有的示例都是在 Python 3.7 的環(huán)境下編寫的,每個特性示例都給出了其正常工作所需的最低的 Python 版本。
潮流特性
Q
你覺得你Python中最騷的操作是哪些?
Python小學生
解包!裝飾器!Typing家族!DataClass類!格式化字符串 f-string(最低 Python 版本為 3.6)
“如何格式化字符串”這個話題我想是每個開發(fā)者在接觸一門新語言的時候都會去學習的語法,而在Python中格式化語法的方式大家通常都會偏向于【Format】或者 【%S】這兩種方法,操作如下:
print("My name is %s" % ('phithon', )) print("My name is %(name)s" % {'name':'phithon'}) print("My name is {}".format("bob")) print("My name is {name}".format(name="bob"))而到了Python3.6版本,推出了新的格式化字符串的靈活方法【f-string】,使用【f-string】編寫的與上面功能相同的代碼是這樣的
name="bob" print(f"My name is {name}")我們對比這幾種格式化字符串的方法,可以發(fā)現(xiàn)相比于常見的字符串格式符【%S】 或 【Format】 方法,【f-string】 直接在占位符中插入變量顯得更加方便,也更好理解,關(guān)于格式化速度方面可以參考這個博文看看詳細的解釋。
2. 路徑管理庫 Pathlib(最低 Python 版本為 3.4)
從上個特性可以看出【f-string】 確實非常強大和美觀,而在文件路徑方面,Python遵循了他們的開發(fā)理念:萬物皆是對象,所以他們把路徑也單拎出來搞了一個路徑對象庫,也就是一個處理文件路徑的抽象庫【pathlib】。如果你不知道為什么應該使用 【pathlib】,請參閱下面這篇 Trey Hunner 編寫的炒雞棒的博文以及它的后續(xù)版本,下面我們對比同一案例的新舊兩個版本Python的實現(xiàn):
from glob import globfile_contents = [] for filename in glob('**/*.py', recursive=True):with open(filename) as python_file:file_contents.append(python_file.read()) from pathlib import Pathfile_contents = [path.read_text()for path in Path.cwd().rglob('*.py') ]s')如上所示,您可以read_text對Path對象使用方法和列表理解,將文件內(nèi)容全部讀入一個新列表中,相比于使用舊版本Python的實現(xiàn),在語法和美觀上無疑是更加出色!
3. 類型提示 Type hinting(最低 Python 版本為 3.5)
編程語言有很多類型,靜態(tài)編譯型語言和動態(tài)解釋型語言的對比是軟件工程中一個熱門的話題,幾乎每個人對此有自己的看法。在靜態(tài)語言中類型標注無疑是讓人又愛又恨,愛的是編譯速度加快,團隊合作中準確了解函數(shù)方法的入?yún)㈩愋?#xff0c;恨的是Coding時極其繁瑣的標注。不過,標注這種極其符合團隊文化的操作還是在Python3中被引入,并且很快得到了人們的喜愛。
def print_yes_or_no(codition: str) -> bool:pass4. 枚舉(最低 Python 版本為 3.4)
大家在寫Java或者C語言的時候都會接觸到枚舉這個特性,枚舉也是幫我們節(jié)省了很多時間,也讓我們的代碼更加美觀。舊版本Python中大家想要實現(xiàn)枚舉的話實現(xiàn)方法五花八門,“八仙過海,各顯神通”,充分發(fā)揮了Python的動態(tài)語言特性。我們下面舉些例子:
#利用type自建類的騷操作 def enum(**enums):return type('Enum', (), enums)Numbers = enum(ONE=1, TWO=2, THREE='three') # Numbers.ONE == 1, Numbers.TWO == 2 and Numbers.THREE == 'three' #利用type自建類的騷操作升級版 def enum(*sequential, **named):enums = dict(zip(sequential, range(len(sequential))), **named)return type('Enum', (), enums)Numbers = enum('ZERO', 'ONE', 'TWO') # Numbers.ZERO == 0 and Numbers.ONE == 1 #有帶值到名稱映射的 def enum(*sequential, **named):enums = dict(zip(sequential, range(len(sequential))), **named)reverse = dict((value, key) for key, value in enums.iteritems())enums['reverse_mapping'] = reversereturn type('Enum', (), enums)# Numbers.reverse_mapping['three'] == 'THREE' # 更有甚者,利用namedtuple實現(xiàn)的 from collections import namedtuple def enum(*keys):return namedtuple('Enum', keys)(*keys)MyEnum = enum('FOO', 'BAR', 'BAZ')# 帶字符數(shù)字映射的,像C/C++ def enum(*keys):return namedtuple('Enum', keys)(*range(len(keys)))# 帶字典映射的,可以映射出各種類型,不局限于數(shù)字 def enum(**kwargs):return namedtuple('Enum', kwargs.keys())(*kwargs.values())看過了以上這么多騷操作,現(xiàn)在Python3給你凈化一下眼睛,Python3.4新推出通過「Enum」類編寫枚舉的簡單方法。
from enum import Enum, auto class Monster(Enum):ZOMBIE = auto()WARRIOR = auto()BEAR = auto() print(Monster.ZOMBIE) for i in Monster:print(i) #Monster.ZOMBIE #Monster.ZOMBIE #Monster.WARRIOR #Monster.BEAR以上我們可以看出枚舉是符號名稱(成員)的集合,這些符號名稱與唯一的常量值綁定在一起。在枚舉中,可以通過標識對成員進行比較操作,枚舉本身也可以被遍歷
5. 原生 LRU 緩存(最低 Python 版本為 3.2)
緩存是大家在開發(fā)中都會用到的一個特性,如果我們準確的使用好它,它會節(jié)省我們很多時間和成本。相信很多人初學Python裝飾器的時候都會去實現(xiàn)一個緩存的裝飾器來節(jié)省斐波那契函數(shù)的計算時間。而Python 3 之后將 LRU(最近最少使用算法)緩存作為一個名為「lru_cache」的裝飾器,使得對緩存的使用非常簡單。
下面是一個簡單的斐波那契函數(shù),我們知道使用緩存將有助于該函數(shù)的計算,因為它會通過遞歸多次執(zhí)行相同的工作。
import time def fib(number: int) -> int:if number == 0:return 0if number == 1:return 1return fib(number-1) + fib(number-2) start = time.time() fib(40) print(f'Duration: {time.time() - start}s') # Duration: 30.684099674224854s我們看到,我們沒用緩存裝飾器的時候計算的時間是30秒左右,現(xiàn)在,我們可以使用「lru_cache」來優(yōu)化它(這種優(yōu)化技術(shù)被稱為「memoization」)。通過這種優(yōu)化,我們將執(zhí)行時間從幾秒降低到了幾納秒。
from functools import lru_cache @lru_cache(maxsize=512) def fib_memoization(number: int) -> int:if number == 0:return 0if number == 1:return 1return fib_memoization(number-1) + fib_memoization(number-2) start = time.time() fib_memoization(40) print(f'Duration: {time.time() - start}s') # Duration: 6.866455078125e-05s可以看出,我們在開發(fā)計算函數(shù)的時候使用緩存裝飾器是多么提高成本的一種手段,另外,在新版本Python3.8之后,lru_cache現(xiàn)在可直接作為裝飾器而不是作為返回裝飾器的函數(shù)。因此這兩種寫法現(xiàn)在都被支持:
@lru_cache def f(x):...@lru_cache(maxsize=256) def f(x):...6. 擴展的可迭代對象解包(最低 Python 版本為 3.0)
Python解包相信在我們初學Python的時候都有所了解,如果我們很多地掌握這個特性,相信是一件非常酷的事情。那什么是擴展的解包呢?我們可以從pep3132中了解更多,舉個例子:
# Python 3.4 中 print 函數(shù) 不允許多個 * 操作 >>> print(*[1,2,3], *[3,4])File "<stdin>", line 1print(*[1,2,3], *[3,4])^ SyntaxError: invalid syntax >>> # 再來看看 python3.5以上版本 # 可以使用任意多個解包操作 >>> print(*[1], *[2], 3) 1 2 3 >>> *range(4), 4 (0, 1, 2, 3, 4) >>> [*range(4), 4] [0, 1, 2, 3, 4] >>> {*range(4), 4} {0, 1, 2, 3, 4} >>> {'x': 1, **{'y': 2}} {'x': 1, 'y': 2}我們可以看到,解包這個操作也算的上Python中極其潮流的玩法了,耍的一手好解包,真的會秀翻全場啊!
7. Data class 裝飾器(最低 Python 版本為 3.7)
Python 3.7 引入了【data class】,新特性大大簡化了定義類對象的代碼量,代碼簡潔明晰。通過使用@dataclass裝飾器來修飾類的設(shè)計,可以用來減少對樣板代碼的使用,因為裝飾器會自動生成諸如「__init__()」和「__repr()__」這樣的特殊方法。在官方的文檔中,它們被描述為「帶有缺省值的可變命名元組」。
from dataclasses import dataclass@dataclass class DataClassCard:rank: strsuit: str#生成實例 queen_of_hearts = DataClassCard('Q', 'Hearts') print(queen_of_hearts.rank) print(queen_of_hearts) print(queen_of_hearts == DataClassCard('Q', 'Hearts')) #Q #DataClassCard(rank='Q', suit='Hearts') #True而常規(guī)的類,按照Python 3.7之前的語法類似于這樣
class RegularCarddef __init__(self, rank, suit):self.rank = rankself.suit = suit queen_of_hearts = RegularCard('Q', 'Hearts') print(queen_of_hearts.rank) print(queen_of_hearts) print(queen_of_hearts == RegularCard('Q', 'Hearts')) #'Q' #<__main__.RegularCard object at 0x7fb6eee35d30> #False雖然這種寫法并沒有使用更多的代碼量,但是我們很容易看到為了初始化,僅僅只是為了初始化一個對象,rank和suit已經(jīng)重復了三次。此外,如果你試圖使用這個RegularCard類,你會注意到對象的表示不是很具描述性,并且已有的類與新聲明的類是無法比較是否相同的。因為每次聲明都會使用一個新的內(nèi)存地址,而“==”不止比較類存儲的信息,還比較內(nèi)存地址是否相同。
dataclass還在底層給我們做了更多的有用的封裝。默認情況下dataclass實現(xiàn)了__repr__方法,可以很好的提供字符串表示;也是了__eq__方法,可以做基本的對象比較。而如果RegularCard想實現(xiàn)上面的功能需要寫大量的聲明,代碼量多的嚇人。
class RegularCard(object):def __init__(self, rank, suit):self.rank = rankself.suit = suitdef __repr__(self):#可以將類的信息打印出來return (f'{self.__class__.__name__}'f'(rank={self.rank!r}, suit={self.suit!r})')#大家可以試著將“!r”去掉或者將其中的r改變?yōu)閟或a,看看輸出結(jié)果會有什么變化#conversion character: expected 's', 'r', or 'a'def __eq__(self, other):#可以比較類是否相同(不考慮內(nèi)存地址)if other.__class__ is not self.__class__:return NotImplementedreturn (self.rank, self.suit) == (other.rank, other.suit)8. 隱式命名空間包(最低 Python 版本為 3.3)
一種組織 Python 代碼文件的方式是將它們封裝在程序包中(包含一個「init.py」的文件夾)。下面是官方文檔提供的示例。
sound/ Top-level package__init__.py Initialize the sound packageformats/ Subpackage for file format conversions__init__.pywavread.pywavwrite.pyaiffread.pyaiffwrite.pyauread.pyauwrite.py ...effects/ Subpackage for sound effects__init__.pyecho.pysurround.pyreverse.py...filters/ Subpackage for filters__init__.pyequalizer.pyvocoder.pykaraoke.py...在 Python 2 中,上面每個文件夾都必須包含將文件夾轉(zhuǎn)化為 Python 程序包的「init.py」文件。在 Python 3 中,隨著隱式命名空間包的引入,這些文件不再是必須的了。
sound/ Top-level package__init__.py Initialize the sound packageformats/ Subpackage for file format conversionswavread.pywavwrite.pyaiffread.pyaiffwrite.pyauread.pyauwrite.py...effects/ Subpackage for sound effectsecho.pysurround.pyreverse.py...filters/ Subpackage for filtersequalizer.pyvocoder.pykaraoke.py...正如有些人說的那樣,這項工作并沒有像這篇文章說的那么簡單,官方文檔「PEP 420 Specification」指出,常規(guī)的程序包仍然需要「init.py」,把它從一個文件夾中刪除會將該文件夾變成一個本地命名空間包,這會帶來一些額外的限制。本地命名空間包的官方文檔給出了一個很好的示例,并且明確指出了所有的限制。
總結(jié)
上面給出的幾個很潮流的特性可能并不是很全,更多的還需要大家去探索符合自己和團隊的玩法,這篇文章只是向大家展示一些比較好玩的Python新功能,掌握它可以幫助你寫出更加Pythonic的代碼。
來和小伙伴們一起向上生長呀!
掃描下方二維碼,添加小詹微信,可領(lǐng)取千元大禮包并申請加入 Python 學習交流群,群內(nèi)僅供學術(shù)交流,日常互動,如果是想發(fā)推文、廣告、砍價小程序的敬請繞道!一定記得備注「交流學習」,我會盡快通過好友申請哦!
👆長按識別,添加微信
(添加人數(shù)較多,請耐心等待)
👆長按識別,關(guān)注小詹
(掃碼回復 1024 領(lǐng)取程序員大禮包)
推薦閱讀:(點擊標題即可跳轉(zhuǎn))
總結(jié)
以上是生活随笔為你收集整理的Python2寿命只剩一个月啦!还不快赶紧学起Python3酷炫到爆的新特性!的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数学大师丘成桐:中国的科技至少要倒退20
- 下一篇: 反转!奥斯卡般演技的果小云水果店耍了全世