Python 3.6全揭秘

ClariceQXI 7年前發布 | 20K 次閱讀 Python Python開發

剛才看到 Learn Python the Hard Way 第四版都開始使用Python 3.6:stuck_out_tongue_closed_eyes:,。想起當時某些人還吐槽我的書竟然是使用Python 2的,好吧,我也來列一下Python 3中非常值得一提的變化(最詳細的當然還是看官方的 What’s New )。

Literal String Interpolation

新增了 格式化字符串變量 語法,通過字符串的前綴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

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

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

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

>>> import secrets
>>> 'https://mydomain.com/reset=' + secrets.token_urlsafe()
'https://mydomain.com/reset=3-dr2ZQLSDO1lOOgEG4Pd518iwNS-FuNNTptzYdI7VA'

重新實現了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__類方法會被調用:

>>> classPluginBase:
>>>    subclasses = []
>>>    def__init_subclass__(cls, **kwargs):
>>>        super().__init_subclass__(**kwargs)
>>>        cls.subclasses.append(cls)

>>> classPlugin1(PluginBase):
>>>    pass

>>> classPlugin2(PluginBase):
>>>    pass

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

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

描述符協議增強

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

classInteger(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


classMovie(object):
    score = Integer('score')
    amount = Integer('amount')


movie = Movie()
movie.score = 9
print(movie.score)

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

? python3 movie.py
9

上面的用法有個問題,就是初始化的時候都明確讓屬性的值綁定在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的實現。
  2. 有了一個更快的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’。
  2. 匹配對象組可通過__getitem__訪問, 它就等價于 group()。因此, 現在mo[‘name’] 就等價于 mo.group(‘name’)。
  3. Match對象支持index-like對象一樣的組索引。

glob優化

通過os.scandir對glob模塊中的glob()及iglob()進行優化,使得它們現在大概快了3-6倍。:pensive: 唉,我當時咋沒想到呢。有興趣的可以看 Issue 25596 。如果你正常也有這種目錄掃描的需求,請參看實現。

pickle優化

當對大量小對象進行反序列化時,pickle.load()和pickle.loads()的速度可提高10%。

 

來自:http://www.dongwm.com/archives/Python-3-6揭秘/

 

 本文由用戶 ClariceQXI 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!