UP | HOME

Python3.0-3.6的版本变化

目录

1 前言

我记得上次整理 2.5-2.7 的版本变化的时候还是寒假, 结果这个暑假有轮到 3.0-3.6 了。

虽然已经用了一段时间的 Python3 了, 感觉也还可以, 但是还是没有对 Python3 的新特性进行系统的了解。

前段时间 Python3.7 横空出世, 看了看我电脑上的 Python3.6, 觉得有必要对 Python3 的特性进行一下了解了。

3.0-3.6 一共七个版本, 估计要花不少时间, 准备慢慢搞了, 一天弄一点。

2 Python3.0

2.1 简单的变化

  • Print Is A Function

    print 现在是一个 function 而不是一个关键字了, 对于这个变化我只能说 ⑥

  • Views And Iterators Instead Of Lists

    某些接口的返回值由 List 替换为了 ViewIterators:

    • 字典 dict 的方法 dict.keys(), dict.items()dict.values() 现在返回的是 View 而不是 List
    • 内置函数 map()filter() 现在返回 Iterators 而不是返回 List
    • range() 的行为变得和 xrange() 一样, 而 xrange() 惨遭移除 QAQ
    • zip() 现在返回的也是 Iterators

    感觉这些变化适应了就挺好的, 还可以在一定程度上提升 Python 的性能, 就是苦了那些需要兼容 Python2 的程序 @_@

  • Ordering Comparisons
    • 比较操作符 <, <=, >=> 现在比较两个无法比较的对象时会引发 TypeError, 比如 0 > None 之类的操作。 不包括 !=== 这两个操作符。

      Python2 居然可以这样比较……

    • 内置函数 builtin.sorted()list.sort() 不在支持 cmp 参数。

      让坑过……

    • 不在支持 cmp()__cmp__(), 现在使用 __lt__() 进行排序, __eq__()__hash__() 用于比较。

      这个没啥存在感 @_@

  • Text Vs. Data Instead Of Unicode Vs. 8-bit

    老话题了, byte 变成了 unicode, 不过用起来感觉不错

2.2 语法的变化

2.2.1 新语法

  • PEP 3107 – Function Annotations

    现在函数的参数和返回值都可以有注释了, 但是貌似没看到有人用, 有兴趣的可以了解一下:

    def compile(source: "something compilable",
                filename: "where the compilable thing comes from",
                mode: "is this a single statement or a suite?"):
        ...
    
    def haul(item: Haulable, *vargs: PackAnimal) -> Distance:
        ...
    
  • PEP 3102 – Keyword-Only Arguments

    def compare(a, b, *ignore, key=None):
        if ignore:  # If ignore is not empty
            raise TypeError
    

    类似上面代码的代码现在可以用如下方式代替:

    def compare(a, b, *, key=None):
        ...
    
  • PEP 3104 – Access to Names in Outer Scopes

    新的关键字 nonlocal, 可以声明一个变量不是本地变量, 具体使用可以去看文档。

  • PEP 3132 – Extended Iterable Unpacking

    扩展的可迭代包, 原来这样的语法是 3.0 出来的:

    (a, *rest, b) = range(5)
    

    其实感觉用的也不多, 但是确实是一个很不错的特性

  • PEP 274 – Dict Comprehensions

    字典推导式 的正确证明, 莫非当初只是提出了 PEP 274 但一时没实现 ?

    反正感觉编写文档的作者挺高兴的 <_<

  • 集合字面值

    也就是说类似下面的字面值表示一个集合:

    {1, 2}
    

    同时, 集合推导式 也自然而然的出现了:

    {x for x in stuff} 
    
  • 新的八进制字面值

    类似 0o720 的数字代表八进制数字, 早在 2.6 就有了

  • 新的二进制字面值

    类似 0b1010 的数字代表二进制数字, 也是 2.6 就有了, 同时新增内置函数 bin()

  • 字节字符串

    现在使用前导字符 bB 来表示一个字节字符串:

    b'123456'
    

    同时, 新增内置函数 bytes()

2.2.2 改动的语法

  • 新的 raise 语法

    raise [expr [from expr]]
    

    额, 感觉没人用的样子

  • 这些东西现在是保留字: True, False, None, with, as
  • PEP 3110 – Catching Exceptions in Python 3000

    就是这个:

    try:
        try_body
    except E, N:
        except_body
    

    变成了:

    try:
        try_body
    except E as N:
        except_body
    
  • PEP 3115 – Metaclasses in Python 3000

    元类的指定方式变了:

    # Python2
    class C:
        __metaclass__ = M
        ...
    
    
    # Python3
    class C(metaclass=M):
        ...
    

    贼坑, 如果要兼容可以使用 with_metaclass

2.3 剩下的变化

这次的整理主要是了解一些新特性和常用的变化, 对于哪些说出去基本没人知道的特性的变化还是算了吧……

因此, 剩下的变化我选择省略, 如果你有兴趣的话, 可以到 官方文档 了解一波。

另外, 这里有一个很有趣的事情:

PEP-3101.png

Python 3.6.2 (v3.6.2:5fd33b5, Jul  8 2017, 04:14:34) [MSC v.1900 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> "%s" % 123456
'123456'

@_@

3 Python3.1

相对 3.0 来说, 3.1 的变化不是很多, 简单来看看。

  • PEP 372 – Adding an ordered dictionary to collections

    In [1]: from collections import OrderedDict
    
    In [2]: d = OrderedDict()
    
    In [3]: d['parrot'] = 'dead'
    
    In [4]: d['penguin'] = 'exploded'
    
    In [5]: d.items()
    Out[5]: odict_items([('parrot', 'dead'), ('penguin', 'exploded')])
    

    有序字典, 这个在一些需要保持原有顺序的地方很有用。

  • PEP 378: Format Specifier for Thousands Separator

    In [1]: format(1234567, ',d')
    Out[1]: '1,234,567'
    
    In [2]: format(1234567.89, ',.2f')
    Out[2]: '1,234,567.89'
    
    In [3]: format(12345.6 + 8901234.12j, ',f')
    Out[3]: '12,345.600000+8,901,234.120000j'
    

    都快忘记有 format 这个内置函数了 QAQ

    感觉这个特性还是挺好的, 用到的时候可以省不少劲。

  • new method bit_length() for int type

    >>> n = 37
    >>> bin(n)
    '0b100101'
    >>> n.bit_length()
    6
    

虽然还有一些其他的变化, 但我觉得剩下的变化简单了解一下就好, 就不列出来了。

4 Python3.2

3.1 一样, 变换不是很多, 简单看一下就好。

  • PEP 3147: PYC Repository Directories

    新的缓存机制, 以前的缓存方案为 .pyc 文件, 但是这个方案在安装了多个 Python 的机器上运行的不太好。

    于是现在更换的缓存机制, 将缓存保存在了 __pycache__ 目录中, 同时根据 Python 版本命名缓存文件。

    目录 __pycache__ 基本上一出现我就直接删除了 QAQ

  • new start option -q

    使用 Python -q 启动解释器可以不显示版本信息, 感觉对我来说暂时没啥用。

  • range objects now support index and count methods

    >>> range(0, 100, 2).count(10)
    1
    >>> range(0, 100, 2).index(10)
    5
    >>> range(0, 100, 2)[5]
    10
    >>> range(0, 100, 2)[0:5]
    range(0, 10, 2)
    

    我觉得这是一个很棒的特性 ( ̄▽ ̄)/

  • The callable() builtin function from Py2.x was resurrected

    什么, callable() GG 过 !!!∑(゚Д゚ノ)ノ

剩下的变化主要是关于内置模块和低层接口的, 这些东西还是在实践中看相关的文档好了。

5 Python3.3

和前面两个版本一样, 核心的语法变化不是很多, 简单来看一下就好。

  • PEP 397 – Python launcher for Windows

    如果你的操作系统是 Windows, 并且安装了不止一个版本的 Python, 那么这个特性应该不陌生。

    通过如下的指令来启动指定版本的 Python 解释器:

    py -2.7
    py -3.6
    
  • PEP 380 – Syntax for Delegating to a Subgenerator

    我觉的这是个好东西, 通过文档中的一个例子来看:

    >>> def g(x):
    ...     yield from range(x, 0, -1)
    ...     yield from range(x)
    ...
    >>> list(g(5))
    [5, 4, 3, 2, 1, 0, 1, 2, 3, 4]
    

    这个很爽啊, 又可以少写几行代码 @_@

  • PEP 409 – Suppressing exception context

    这个特性可以让异常的输出更加清楚 ?

    >>> class D:
    ...     def __init__(self, extra):
    ...         self._extra_attributes = extra
    ...     def __getattr__(self, attr):
    ...         try:
    ...             return self._extra_attributes[attr]
    ...         except KeyError:
    ...             raise AttributeError(attr) from None
    ...
    >>> D({}).x
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 8, in __getattr__
    AttributeError: x
    

    关键点在 from None 上, 没有这个 from None 的话, 抛出的异常会是这样的:

    Traceback (most recent call last):
      File "<stdin>", line 6, in __getattr__
    KeyError: 'x'
    
    During handling of the above exception, another exception occurred:
    
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 8, in __getattr__
    AttributeError: x
    
  • PEP 414 – Explicit Unicode Literal for Python 3.3

    这个特性运行在 Python3 的版本环境中使用 u 前缀显示的声明 unicode 字符串:

    u'text'
    U'text'
    

    虽然已经习惯了, 但还是想吐槽 2 -> 3 的版本变化是真的阔怕……

  • PEP 3155 – Qualified name for classes and functions

    函数和类对象的新属性: __qualname__, 效果看代码:

    >>> class C:
    ...     class D:
    ...         def meth(self):
    ...             pass
    ...
    >>> C.D.__name__
    'D'
    >>> C.D.__qualname__
    'C.D'
    >>> C.D.meth.__name__
    'meth'
    >>> C.D.meth.__qualname__
    'C.D.meth'
    

6 Python3.4

这个版本的文档结构比前面几个版本清楚多了, 简单看一下新特性。

emmmm, 剩下的变化对我们写代码的影响不大, 省略。

7 Python3.5

  • PEP 492 – Coroutines with async and await syntax

    针对 协程 的新关键字 asyncawait, 官网的例子:

    import asyncio
    
    async def coro(name, lock):
        print('coro {}: waiting for lock'.format(name))
        async with lock:
            print('coro {}: holding the lock'.format(name))
            await asyncio.sleep(1)
            print('coro {}: releasing the lock'.format(name))
    
    loop = asyncio.get_event_loop()
    lock = asyncio.Lock()
    coros = asyncio.gather(coro(1, lock), coro(2, lock))
    try:
        loop.run_until_complete(coros)
    finally:
        loop.close()
    
    # results
    coro 2: waiting for lock
    coro 2: holding the lock
    coro 1: waiting for lock
    coro 2: releasing the lock
    coro 1: holding the lock
    coro 1: releasing the lock
    

    我觉得这是一个很重要的新特性, 目前在 Github 上已经可以看到一些只针对高版本 Python 开发的库,其中就用到了这一特性。

    当然了, 目前我对协程的了解并不多, 因此也更应该去了解。 嗯, 现在知道这么一个特性了。

  • PEP 465 – A dedicated infix operator for matrix multiplication

    这应该算是语言的应用场景反过来影响语法开发的一个实例吧, 针对 矩阵运算 的操作符 @.

    >>> import numpy
    
    >>> x = numpy.ones(3)
    >>> x
    array([ 1., 1., 1.])
    
    >>> m = numpy.eye(3)
    >>> m
    array([[ 1., 0., 0.],
           [ 0., 1., 0.],
           [ 0., 0., 1.]])
    
    >>> x @ m
    array([ 1., 1., 1.])
    

    这些东西都没用过, 不做评价。 有兴趣的可以了解一下。

  • PEP 448 – Additional Unpacking Generalizations

    扩展了 *iterable**dictionary 拆包操作符的允许用法, 现在可以在函数中调用任意数量的拆包:

    >>> print(*[1], *[2], 3, *[4, 5])
    1 2 3 4 5
    
    >>> def fn(a, b, c, d):
    ...     print(a, b, c, d)
    ...
    
    >>> fn(**{'a': 1, 'c': 3}, **{'b': 2, 'd': 4})
    1 2 3 4
    

    同时, 元组, 列表, 集合, 字典等允许同时多个解包:

    >>> *range(4), 4
    (0, 1, 2, 3, 4)
    
    >>> [*range(4), 4]
    [0, 1, 2, 3, 4]
    
    >>> {*range(4), 4, *(5, 6, 7)}
    {0, 1, 2, 3, 4, 5, 6, 7}
    
    >>> {'x': 1, **{'y': 2}}
    {'x': 1, 'y': 2}
    

    恐怖如斯 !

  • PEP 484 – Type Hints

    和这个特性有关的一个特性: PEP 3107. 我觉得, 只要看了它的表现形式你也应该明白是和什么有关了:

    def greeting(name: str) -> str:
        return 'Hello ' + name
    

    通过注释来表示参数和返回值的类型,但是解释器运行时会忽略这些注释,因此,也只有注释的作用。

    感觉 Python 代码长得越来越奇怪了 QAQ

8 Python3.6

  • PEP 498 – Literal String Interpolation

    现在我学过的脚本语言都会这一套了:

    >>> name = "Fred"
    >>> f"He said his name is {name}."
    'He said his name is Fred.'
    >>> width = 10
    >>> precision = 4
    >>> value = decimal.Decimal("12.34567")
    >>> f"result: {value:{width}.{precision}}"  # nested fields
    'result:      12.35'
    

    感觉通过 Python名称空间 来实现这个特性还是很方便的, 不知道是不是这样来实现的。

  • PEP 526 – Syntax for Variable Annotations

    通过特殊的语法来对变量的类型进行注释:

    primes: List[int] = []
    
    captain: str  # Note: no initial value!
    
    class Starship:
        stats: Dict[str, int] = {}
    

    其他的注释也可以:

    name: 'your name'
    

    但似乎就只有注释的作用 ?

    >>> name: str = 10
    
  • PEP 515 – Underscores in Numeric Literals

    通过在数字中添加下划线来提高可读性:

    >>> 1_000_000_000_000_000
    1000000000000000
    >>> 0x_FF_FF_FF_FF
    4294967295
    
  • PEP 525 – Asynchronous Generators

    3.5 引入了关键字 asyncawait, 但是, 通过 async 修饰的函数内部不能在使用 yield, 现在, 这个限制解除了:

    async def ticker(delay, to):
        """Yield numbers from 0 to *to* every *delay* seconds."""
        for i in range(to):
            yield i
            await asyncio.sleep(delay)
    

    代码更难懂了……

  • PEP 530 – Asynchronous Comprehensions

    现在在各种推导式, 生成式中都可以用 async 了:

    result = [i async for i in aiter() if i % 2]
    result = [await fun() for fun in funcs if await condition()]
    
  • PEP 487 – Simpler customisation of class creation

    现在可以在不使用元类的情况下自定义子类创建, 通过方法 __init_subclass__:

    >>> class QuestBase:
    ...    # this is implicitly a @classmethod (see below for motivation)
    ...    def __init_subclass__(cls, swallow, **kwargs):
    ...        cls.swallow = swallow
    ...        super().__init_subclass__(**kwargs)
    
    >>> class Quest(QuestBase, swallow="african"):
    ...    pass
    
    >>> Quest.swallow
    'african'
    
  • PEP 487 – Simpler customisation of class creation

    PEP 487 除了前面那个特性以外, 还增强了 描述器 协议 (ノ`Д)ノ

    class IntField:
        def __get__(self, instance, owner):
            return instance.__dict__[self.name]
    
        def __set__(self, instance, value):
            if not isinstance(value, int):
                raise ValueError(f'expecting integer in {self.name}')
            instance.__dict__[self.name] = value
    
        # this is the new initializer:
        def __set_name__(self, owner, name):
            self.name = name
    
    class Model:
        int_field = IntField()
    

    __set_name__ 这个方法会在描述器定义时自动定义, owner 是这个描述器的拥有者, name 则是描述器在 owner 中的名称。

    在上述例子中, name 就是 int_field.

  • PEP 529: Change Windows filesystem encoding to UTF-8
  • PEP 528: Change Windows console encoding to UTF-8
  • PEP 520 – Preserving Class Attribute Definition Order

    现在类的 __dict__ 中的属性顺序和定义顺序保持一致了。

  • PEP 468 – Preserving the order of **kwargs in a function

    **kwargs 形式的参数现在会保持传入的顺序:

    >>> def func(**kwargs):
    ...     print(kwargs)
    ...
    >>> func(a=1, b=2, c=3, ab=4)
    {'a': 1, 'b': 2, 'c': 3, 'ab': 4}
    

9 完结撒花

了解这些版本特性变化的过程中, 虽然已经省略了相等一部分的内容, 但还是花了我不少时间。

并且, 这次只是知道了有什么新特性, 不代表会用了 @_@

感觉 Python 的特性是越来越多, 可以说, 我学过的所有语言中, Python 的特性是最多的。

想起前几天 Guido van Rossum 退出核心决策圈的原因, 还有已经发布的 Python3.7

<・)))><<

10 相关链接

版权声明:本作品采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可