Python 3.6全揭秘
剛才看到Learn Python the Hard Way第四版都開始使用Python 3.6??,。想起當時某些人還吐槽我的書竟然是使用Python 2的,好吧,我也來列一下Python 3.6中非常值得一提的變化(最詳細的當然還是看官方的What』s New)。
Literal String Interpolation
新增了格式化字元串變數語法,通過字元串的前綴f,實現類似於Scala/Swift等語言的字元串插值:
>>> name = Fredn>>> fMy name is {name}nMy name is Fredn>>> date = datetime.datetime.now().date()n>>> f{date} was on a {date:%A}n2017-02-25 was on a Saturdayn>>> f{"quoted string"}nquoted stringn>>> def foo():n... return 20n...n>>> fresult={foo()}nresult=20n
Asynchronous Generators
新增非同步生成器語法,可以直接在協程中用生成器:
async def coro():n for item in range(10):n yield itemnnasync def main():n async for item in coro():n ...n
Async comprehensions
新增非同步解析語法:
result = [await fun() for fun in funcs]nresult = {await fun() for fun in funcs}nresult = {fun: await fun() for fun in funcs}nresult = [func async for fun in funcs]nresult = {func async for fun in funcs}nresult = {func async for fun in funcs}n
Variable annotations
在Python 3.5的時候已經添加了類型標註語法:
primes = [] # type: List[int]nprimes = 1n
不過得通過mypy做類型檢查:
? mypy prime.pynprime.py:2: error: Incompatible types in assignment (expression has type "int", variable has type List[int])n
現在又新增給變數添加註釋語法:
>>> from typing import Listn>>> primes: List[int] = []n>>> __annotations__n{primes: typing.List[int]}n
Underscores in Numeric Literals
新增數字變數使用下劃線語法:
>>> {:_}.format(1000000)n1_000_000n>>> 10_000_000.0n10000000.0n
新模塊secrets
用來以簡化使用於管理密碼,比如賬號認證,令牌等的密碼的隨機數的生成:
>>> import secretsn>>> https://mydomain.com/reset= + secrets.token_urlsafe()nhttps://mydomain.com/reset=3-dr2ZQLSDO1lOOgEG4Pd518iwNS-FuNNTptzYdI7VAn
重新實現了dict
之前的大量實驗證實,Python 3一直比較慢,這也是我一直觀望的原因。目前看,Python 2.7還是最快的Python解釋器。官方一直致力於速度的提升,所以 Python 3.4 < Python 3.5 < Python 3.6。
所以,3.6中參考PyPy重新實現了字典dict,使其更加緊湊。此次重新實現的dict比Python3.5中的字典內存使用減少了20%-25%。
PS: 看目前正在開發的3.7, 也會有一些顯著的改善。
定製類的創建使用新協議進行了簡化
Simpler customisation of class creation提供了一種可以在不使用元類的情況下自定義子類的方法。每當創建一個新的子類時,新的__init_subclass__類方法會被調用:
>>> class PluginBase:n>>> subclasses = []n>>> def __init_subclass__(cls, **kwargs):n>>> super().__init_subclass__(**kwargs)n>>> cls.subclasses.append(cls)nn>>> class Plugin1(PluginBase):n>>> passn n>>> class Plugin2(PluginBase):n>>> passn n>>> PluginBase.subclassesn[__main__.Plugin1, __main__.Plugin2]n
這樣讓自定義類的變得更簡單了。
描述符協議增強
描述符是一個具有綁定行為的對象屬性,由於它的優先順序高會改變一個屬性的基本的獲取、設置和刪除方式,我們先看一個例子:
class Integer(object):n def __init__(self, name):n self.name = namenn def __get__(self, instance, owner):n return instance.__dict__[self.name]nn def __set__(self, instance, value):n if value < 0:n raise ValueError(Negative value not allowed)n instance.__dict__[self.name] = valuennnclass Movie(object):n score = Integer(score)n amount = Integer(amount)nnnmovie = Movie()nmovie.score = 9nprint(movie.score)n
相當於把score和amount這個2個屬性都綁定上Integer的對象上了,結果會是:
? python3 movie.py9n
上面的用法有個問題,就是初始化的時候都明確讓屬性的值綁定在Integer上的name屬性上,而無法獲知所有者類的屬性名。使用在PEP487上提供的可選的__set_name__()可以獲得這個屬性名字,並且可以自定義這部分內容:
class Integer(object):n def __get__(self, instance, owner):n return instance.__dict__[self.name]nn def __set__(self, instance, value):n if value < 0:n raise ValueError(Negative value not allowed)n instance.__dict__[self.name] = valuenn def __set_name__(self, owner, name):n self.name = namennnclass Movie(object):n score = Integer()n amount = Integer()nnnmovie = Movie()nmovie.score = 9nprint(movie.score)n
Preserving Class Attribute Definition Order
我們知道Python 2中dict是不能保存鍵值順序的:
? python2n>>> d = {a: 1, b: 2, c: 3}n>>> dn{a: 1, c: 3, b: 2}n
現在則會保存類屬性定義順序。也就是按照源碼中屬性名出現的順序存儲在__dict__ 的屬性中。
而且我發現dict的實現也保留了順序:
? python3nPython 3.6.0 (default, Dec 24 2016, 00:01:50)n...n>>> d = {a: 1, b: 2, c: 3}n>>> dn{a: 1, b: 2, c: 3}n>>>n
看來OrderdDict要失業了~
Preserving Keyword Argument Order
現在也會保存關鍵字參數順序了:
>>> def test(**kw):n... print(kw)n...n>>> test(a=1, b=2, c=3)n{a: 1, b: 2, c: 3}n
asyncio可用於生產環境
asyncio模板添加了很多新的功能、重要的可用性、性能改進以及大量的bug,現在asyncio模塊的API已經很穩定,可用於生產環境了。其中:
- 有了一個更快的asyncio.Future的C的實現。
- 有了一個更快的asyncio.Task的C的實現。
使用這2個實現可以讓效率提高15%左右。而使用第三方的uvloop還能讓速度提升5%-10%。
re模塊
- 在正則表達式中,增加對spans修飾符的支持。示例: (?i:p)ython 匹配 python 和 Python, 但不匹配 PYTHON; (?i)g(?-i:v)r 匹配 GvR 和 gvr, 但不匹配 GVR。
- 匹配對象組可通過__getitem__訪問, 它就等價於 group()。因此, 現在mo[name] 就等價於 mo.group(name)。
- Match對象支持index-like對象一樣的組索引。
glob優化
通過os.scandir對glob模塊中的glob()及iglob()進行優化,使得它們現在大概快了3-6倍。?? 唉,我當時咋沒想到呢。有興趣的可以看Issue 25596。如果你正常也有這種目錄掃描的需求,請參看實現。
pickle優化
當對大量小對象進行反序列化時,pickle.load()和pickle.loads()的速度可提高10%。
無恥的廣告:《Python Web開發實戰》上市了!
歡迎關注本人的微信公眾號獲取更多Python相關的內容(也可以直接搜索「Python之美」):
推薦閱讀:
※[Python]因果檢驗工具
※Python 爬蟲實戰(一):使用 requests 和 BeautifulSoup
※ELEMENTARY.01.Say Hi
※【精心解讀】關於Jupyter Notebook的28個技巧
※理解 Python 裝飾器看這一篇就夠了