如果你還在用 python 3.6,那麼你應該掌握它的這些特點!

如果你還在用 python 3.6,那麼你應該掌握它的這些特點!

原文丨董明偉

Learn Python the Hard Way第四版早已經開始使用Python 3.6。想起現在還有很多朋友並有更新還一直在用Python 3.6 ,好吧,我也來列一下Python 3.6中非常值得一提的秘密。(最詳細的當然還是看官方的What’s New)。

Literal String Interpolation(私信小編007獲取大量Python視頻教程以及各類PDF!)

新增了格式化字符串變量語法,通過字符串的前綴f,實現類似於Scala/Swift等語言的字符串插值:

>>> name = 'Fred'
>>> f'My name is {name}'
'My name is Fred'
>>> date = datetime.datetime.now().date()
>>> f'{date} was on a {date:%A}'
'2017-02-25 was on a Saturday'
>>> f'{"quoted string"}'
'quoted string'
>>> def foo():
... return 20
...
>>> f'result={foo()}'
'result=20'

Asynchronous Generators

如果你還在用 python 3.6,那麼你應該掌握它的這些特點!

新增異步生成器語法,可以直接在協程中用生成器:

async def coro():
for item in range(10):
yield item
async def main():
async for item in coro():
...

Async comprehensions

新增異步解析語法:

result = [await fun() for fun in funcs]
result = {await fun() for fun in funcs}
result = {fun: await fun() for fun in funcs}
result = [func async for fun in funcs]
result = {func async for fun in funcs}
result = {func async for fun in funcs}

Variable annotations

在Python 3.5的時候已經添加了類型標註語法:

primes = [] # type: List[int]
primes = 1

不過得通過mypy做類型檢查:

❯ mypy prime.py
prime.py:2: error: Incompatible types in assignment (expression has type "int", variable has type List[int])

現在又新增給變量添加註釋語法:

>>> from typing import List
>>> primes: List[int] = []
>>> __annotations__

{'primes': typing.List[int]}

Underscores in Numeric Literals

新增數字變量使用下劃線語法:

>>> '{:_}'.format(1000000)
'1_000_000'
>>> 10_000_000.0
10000000.0

新模塊secrets

用來以簡化使用於管理密碼,比如賬號認證,令牌等的密碼的隨機數的生成:

如果你還在用 python 3.6,那麼你應該掌握它的這些特點!

重新實現了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:
>>> subclasses = []
>>> def __init_subclass__(cls, **kwargs):
>>> super().__init_subclass__(**kwargs)
>>> cls.subclasses.append(cls)
>>> class Plugin1(PluginBase):
>>> pass

>>> class Plugin2(PluginBase):
>>> pass

>>> PluginBase.subclasses
[__main__.Plugin1, __main__.Plugin2]

這樣讓自定義類的變得更簡單了。

描述符協議增強

描述符是一個具有綁定行為的對象屬性,由於它的優先級高會改變一個屬性的基本的獲取、設置和刪除方式,我們先看一個例子:

class Integer(object):
def __init__(self, name):
self.name = name
def __get__(self, instance, owner):
return instance.__dict__[self.name]
def __set__(self, instance, value):
if value < 0:
raise ValueError('Negative value not allowed')
instance.__dict__[self.name] = value
class Movie(object):
score = Integer('score')
amount = Integer('amount')
movie = Movie()
movie.score = 9
print(movie.score)

相當於把score和amount這個2個屬性都綁定上Integer的對象上了,結果會是:

❯ python3 movie.py9

上面的用法有個問題,就是初始化的時候都明確讓屬性的值綁定在Integer上的name屬性上,而無法獲知所有者類的屬性名。使用在PEP487上提供的可選的__set_name__()可以獲得這個屬性名字,並且可以自定義這部分內容:

class Integer(object):
def __get__(self, instance, owner):
return instance.__dict__[self.name]
def __set__(self, instance, value):

if value < 0:
raise ValueError('Negative value not allowed')
instance.__dict__[self.name] = value
def __set_name__(self, owner, name):
self.name = name
class Movie(object):
score = Integer()
amount = Integer()
movie = Movie()
movie.score = 9
print(movie.score)

Preserving Class Attribute Definition Order

我們知道Python 2中dict是不能保存鍵值順序的:

❯ python2
>>> d = {'a': 1, 'b': 2, 'c': 3}
>>> d
{'a': 1, 'c': 3, 'b': 2}

現在則會保存類屬性定義順序。也就是按照源碼中屬性名出現的順序存儲在__\\dict__ 的屬性中。

而且我發現dict的實現也保留了順序:

❯ python3
Python 3.6.0 (default, Dec 24 2016, 00:01:50)
...
>>> d = {'a': 1, 'b': 2, 'c': 3}
>>> d
{'a': 1, 'b': 2, 'c': 3}
>>>

看來OrderdDict要失業了~

Preserving Keyword Argument Order

現在也會保存關鍵字參數順序了:

>>> def test(**kw):
... print(kw)
...
>>> test(a=1, b=2, c=3)
{'a': 1, 'b': 2, 'c': 3}

asyncio可用於生產環境

asyncio模板添加了很多新的功能、重要的可用性、性能改進以及大量的bug,現在asyncio模塊的API已經很穩定,可用於生產環境了。其中:

  1. 有了一個更快的asyncio.Future的C的實現。有了一個更快的asyncio.Task的C的實現。

使用這2個實現可以讓效率提高15%左右。而使用第三方的uvloop還能讓速度提升5%-10%。

re模塊

  1. 在正則表達式中,增加對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 3.6,那麼你應該掌握它的這些特點!


分享到:


相關文章: