Python 3.6全揭秘

ClariceQXI 7年前
   <p>刚才看到 Learn Python the Hard Way 第四版都开始使用Python 3.6:stuck_out_tongue_closed_eyes:,。想起当时某些人还吐槽我的书竟然是使用Python 2的,好吧,我也来列一下Python 3中非常值得一提的变化(最详细的当然还是看官方的 <a href="/misc/goto?guid=4959739029352831288" rel="nofollow,noindex">What’s New</a> )。</p>    <h3>Literal String Interpolation</h3>    <p>新增了 格式化字符串变量 语法,通过字符串的前缀f,实现类似于Scala/Swift等语言的字符串插值:</p>    <pre>  <code class="language-python">>>> 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'  </code></pre>    <h3>Asynchronous Generators</h3>    <p>新增 异步生成器 语法,可以直接在协程中用生成器:</p>    <pre>  <code class="language-python">async def coro():      for item in range(10):          yield item    async def main():      async for item in coro():          ...  </code></pre>    <h3>Async comprehensions</h3>    <p>新增 <a href="/misc/goto?guid=4959739029442541592" rel="nofollow,noindex">异步解析</a> 语法:</p>    <pre>  <code class="language-python">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}  </code></pre>    <h3>Variable annotations</h3>    <p>在Python 3.5的时候已经添加了 类型标注 语法:</p>    <pre>  <code class="language-python">primes = []  # type: List[int]  primes = 1  </code></pre>    <p>不过得通过mypy做类型检查:</p>    <pre>  <code class="language-python">❯ mypy prime.py  prime.py:2: error: Incompatible types in assignment (expression has type "int", variable has type List[int])  </code></pre>    <p>现在又新增 给变量添加注释 语法:</p>    <pre>  <code class="language-python">>>> from typing import List  >>> primes: List[int] = []  >>> __annotations__  {'primes': typing.List[int]}  </code></pre>    <h3>Underscores in Numeric Literals</h3>    <p>新增 数字变量使用下划线 语法:</p>    <pre>  <code class="language-python">>>> '{:_}'.format(1000000)  '1_000_000'  >>> 10_000_000.0  10000000.0  </code></pre>    <h3>新模块secrets</h3>    <p>用来以简化使用于管理密码,比如账号认证,令牌等的密码的随机数的生成:</p>    <pre>  <code class="language-python">>>> import secrets  >>> 'https://mydomain.com/reset=' + secrets.token_urlsafe()  'https://mydomain.com/reset=3-dr2ZQLSDO1lOOgEG4Pd518iwNS-FuNNTptzYdI7VA'  </code></pre>    <h3>重新实现了dict。</h3>    <p>之前的大量实验证实,Python 3一直比较慢,这也是我一直观望的原因。目前看,Python 2.7还是最快的Python解释器。官方一直致力于速度的提升,所以 Python 3.4 < Python 3.5 < Python 3.6。</p>    <p>所以,3.6中参考PyPy重新实现了字典dict,使其更加紧凑。此次重新实现的dict比Python3.5中的字典内存使用减少了20%-25%。</p>    <p>PS: 看目前正在开发的3.7, 也会有一些显著的改善。</p>    <h3>定制类的创建使用新协议进行了简化</h3>    <p>Simpler customisation of class creation 提供了一种可以在不使用元类的情况下自定义子类的方法。每当创建一个新的子类时,新的__init_subclass__类方法会被调用:</p>    <pre>  <code class="language-python">>>> 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]  </code></pre>    <p>这样让自定义类的变得更简单了。</p>    <h3>描述符协议增强</h3>    <p>描述符是一个具有绑定行为的对象属性,由于它的优先级高会改变一个属性的基本的获取、设置和删除方式,我们先看一个例子:</p>    <pre>  <code class="language-python">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)  </code></pre>    <p>相当于把score和amount这个2个属性都绑定上Integer的对象上了,结果会是:</p>    <pre>  <code class="language-python">❯ python3 movie.py  9  </code></pre>    <p>上面的用法有个问题,就是初始化的时候都明确让属性的值绑定在Integer上的name属性上,而无法获知所有者类的属性名。使用在 <a href="/misc/goto?guid=4959726475919068110" rel="nofollow,noindex">PEP487</a> 上提供的可选的__set_name__()可以获得这个属性名字,并且可以自定义这部分内容:</p>    <pre>  <code class="language-python">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)  </code></pre>    <h3>Preserving Class Attribute Definition Order</h3>    <p>我们知道Python 2中dict是不能保存键值顺序的:</p>    <pre>  <code class="language-python">❯ python2  >>> d = {'a': 1, 'b': 2, 'c': 3}  >>> d  {'a': 1, 'c': 3, 'b': 2}  </code></pre>    <p>现在则会 保存类属性定义顺序 。也就是按照源码中属性名出现的顺序存储在 <em>\</em> \dict__ 的属性中。</p>    <p>而且我发现dict的实现也保留了顺序:</p>    <pre>  <code class="language-python">❯ 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}  >>>  </code></pre>    <p>看来OrderdDict要失业了~</p>    <h3>Preserving Keyword Argument Order</h3>    <p>现在也会 保存关键字参数顺序 了:</p>    <pre>  <code class="language-python">>>> def test(**kw):  ...     print(kw)  ...  >>> test(a=1, b=2, c=3)  {'a': 1, 'b': 2, 'c': 3}  </code></pre>    <h3>asyncio可用于生产环境</h3>    <p>asyncio模板添加了很多新的功能、重要的可用性、性能改进以及大量的bug,现在asyncio模块的API已经很稳定,可用于生产环境了。其中:</p>    <ol>     <li>有了一个更快的asyncio.Future的C的实现。</li>     <li>有了一个更快的asyncio.Task的C的实现。</li>    </ol>    <p>使用这2个实现可以让效率提高15%左右。而使用第三方的uvloop还能让速度提升5%-10%。</p>    <h3>re模块</h3>    <ol>     <li>在正则表达式中,增加对spans修饰符的支持。示例: ‘(?i:p)ython’ 匹配 ‘python’ 和 ‘Python’, 但不匹配 ‘PYTHON’; ‘(?i)g(?-i:v)r’ 匹配 ‘GvR’ 和 ‘gvr’, 但不匹配 ‘GVR’。</li>     <li>匹配对象组可通过__getitem__访问, 它就等价于 group()。因此, 现在mo[‘name’] 就等价于 mo.group(‘name’)。</li>     <li>Match对象支持index-like对象一样的组索引。</li>    </ol>    <h3>glob优化</h3>    <p>通过os.scandir对glob模块中的glob()及iglob()进行优化,使得它们现在大概快了3-6倍。:pensive: 唉,我当时咋没想到呢。有兴趣的可以看 Issue 25596 。如果你正常也有这种目录扫描的需求,请参看实现。</p>    <h3>pickle优化</h3>    <p>当对大量小对象进行反序列化时,pickle.load()和pickle.loads()的速度可提高10%。</p>    <p> </p>    <p>来自:http://www.dongwm.com/archives/Python-3-6揭秘/</p>    <p> </p>