Python3 新特性

字符串为 Unicode

Python 3.0 新特性

  • PEP 3138 - Python 3000 中的字符串表示

  • PEP 3120 - 使用 UTF-8 作为默认源编码

  • PEP 3131 - 支持非 ASCII 标识符

Python 2

>>> s = 'Café'  # byte string
>>> s
'Caf\xc3\xa9'
>>> type(s)
<type 'str'>
>>> u = u'Café' # unicode string
>>> u
u'Caf\xe9'
>>> type(u)
<type 'unicode'>
>>> len([_c for _c in 'Café'])
5

Python 3

>>> s = 'Café'
>>> s
'Café'
>>> type(s)
<class 'str'>
>>> s.encode('utf-8')
b'Caf\xc3\xa9'
>>> s.encode('utf-8').decode('utf-8')
'Café'
>>> len([_c for _c in 'Café'])
4

除法运算符

Python 3.0 新特性

  • PEP 238 - 更改除法运算符

Python2

>>> 1 / 2
0
>>> 1 // 2
0
>>> 1. / 2
0.5

# back port "true division" to python2

>>> from __future__ import division
>>> 1 / 2
0.5
>>> 1 // 2
0

Python3

>>> 1 / 2
0.5
>>> 1 // 2
0

新的字典实现

Python 3.6 新特性

  • PEP 468 - 在函数中保留 **kwargs 的顺序

  • PEP 520 - 保留类属性定义顺序

  • bpo 27350 - 更紧凑的字典,迭代速度更快

Python 3.5 之前

>>> import sys
>>> sys.getsizeof({str(i):i for i in range(1000)})
49248

>>> d = {'timmy': 'red', 'barry': 'green', 'guido': 'blue'}
>>> d   # without order-preserving
{'barry': 'green', 'timmy': 'red', 'guido': 'blue'}

Python 3.6

  • 内存使用量小于 Python 3.5

  • 保留插入顺序

>>> import sys
>>> sys.getsizeof({str(i):i for i in range(1000)})
36968

>>> d = {'timmy': 'red', 'barry': 'green', 'guido': 'blue'}
>>> d   # preserve insertion ordered
{'timmy': 'red', 'barry': 'green', 'guido': 'blue'}

仅限关键字参数

Python 3.0 新特性

  • PEP 3102 - 仅限关键字参数

>>> def f(a, b, *, kw):
...     print(a, b, kw)
...
>>> f(1, 2, 3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: f() takes 2 positional arguments but 3 were given
>>> f(1, 2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: f() missing 1 required keyword-only argument: 'kw'
>>> f(1, 2, kw=3)
1 2 3

新的 Super

Python 3.0 新特性

  • PEP 3135 - 新的 Super

Python 2

>>> class ParentCls(object):
...     def foo(self):
...         print "call parent"
...
>>> class ChildCls(ParentCls):
...     def foo(self):
...         super(ChildCls, self).foo()
...         print "call child"
...
>>> p = ParentCls()
>>> c = ChildCls()
>>> p.foo()
call parent
>>> c.foo()
call parent
call child

Python 3

>>> class ParentCls(object):
...     def foo(self):
...         print("call parent")
...
>>> class ChildCls(ParentCls):
...     def foo(self):
...         super().foo()
...         print("call child")
...
>>> p = ParentCls()
>>> c = ChildCls()
>>> p.foo()
call parent
>>> c.foo()
call parent
call child

移除 <>

Python 3.0 新特性

Python 2

>>> a = "Python2"
>>> a <> "Python3"
True

# equal to !=
>>> a != "Python3"
True

Python 3

>>> a = "Python3"
>>> a != "Python2"
True

BDFL 退休

Python 3.1 新特性

  • PEP 401 - BDFL 退休

>>> from __future__ import barry_as_FLUFL
>>> 1 != 2
  File "<stdin>", line 1
    1 != 2
       ^
SyntaxError: with Barry as BDFL, use '<>' instead of '!='
>>> 1 <> 2
True

不允许在函数内部使用 from module import *

Python 3.0 新特性

>>> def f():
...     from os import *
...
  File "<stdin>", line 1
SyntaxError: import * only allowed at module level

添加 nonlocal 关键字

Python 3.0 新特性

PEP 3104 - 访问外部作用域中的名称

注意

nonlocal 允许直接赋值给外部(但非全局)作用域中的变量

>>> def outf():
...     o = "out"
...     def inf():
...         nonlocal o
...         o = "change out"
...     inf()
...     print(o)
...
>>> outf()
change out

扩展的可迭代解包

Python 3.0 新特性

  • PEP 3132 - 扩展的可迭代解包

>>> a, *b, c = range(5)
>>> a, b, c
(0, [1, 2, 3], 4)
>>> for a, *b in [(1, 2, 3), (4, 5, 6, 7)]:
...     print(a, b)
...
1 [2, 3]
4 [5, 6, 7]

通用解包

Python 3.5 新特性

  • PEP 448 - 额外的解包泛化

Python 2

>>> def func(*a, **k):
...     print(a)
...     print(k)
...
>>> func(*[1,2,3,4,5], **{"foo": "bar"})
(1, 2, 3, 4, 5)
{'foo': 'bar'}

Python 3

>>> print(*[1, 2, 3], 4, *[5, 6])
1 2 3 4 5 6
>>> [*range(4), 4]
[0, 1, 2, 3, 4]
>>> {"foo": "Foo", "bar": "Bar", **{"baz": "baz"}}
{'foo': 'Foo', 'bar': 'Bar', 'baz': 'baz'}
>>> def func(*a, **k):
...     print(a)
...     print(k)
...
>>> func(*[1], *[4,5], **{"foo": "FOO"}, **{"bar": "BAR"})
(1, 4, 5)
{'foo': 'FOO', 'bar': 'BAR'}

函数注解

Python 3.0 新特性

  • PEP 3107 - 函数注解

  • PEP 484 - 类型提示

  • PEP 483 - 类型提示理论

>>> import types
>>> generator = types.GeneratorType
>>> def fib(n: int) -> generator:
...     a, b = 0, 1
...     for _ in range(n):
...         yield a
...         b, a = a + b, b
...
>>> [f for f in fib(10)]
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

变量注解

Python 3.6 新特性

  • PEP 526 - 变量注解语法

>>> from typing import List
>>> x: List[int] = [1, 2, 3]
>>> x
[1, 2, 3]

>>> from typing import List, Dict
>>> class Cls(object):
...     x: List[int] = [1, 2, 3]
...     y: Dict[str, str] = {"foo": "bar"}
...
>>> o = Cls()
>>> o.x
[1, 2, 3]
>>> o.y
{'foo': 'bar'}

核心支持 typing 模块和泛型

Python 3.7 新特性

  • PEP 560 - 核心支持 typing 模块和泛型

Python 3.7 之前

>>> from typing import Generic, TypeVar
>>> from typing import Iterable
>>> T = TypeVar('T')
>>> class C(Generic[T]): ...
...
>>> def func(l: Iterable[C[int]]) -> None:
...     for i in l:
...         print(i)
...
>>> func([1,2,3])
1
2
3

Python 3.7 或更高版本

>>> from typing import Iterable
>>> class C:
...     def __class_getitem__(cls, item):
...         return f"{cls.__name__}[{item.__name__}]"
...
>>> def func(l: Iterable[C[int]]) -> None:
...     for i in l:
...         print(i)
...
>>> func([1,2,3])
1
2
3

格式化字节字符串

Python 3.5 新特性

  • PEP 461 - 为 bytes 和 bytearray 添加 % 格式化

>>> b'abc %b %b' % (b'foo', b'bar')
b'abc foo bar'
>>> b'%d %f' % (1, 3.14)
b'1 3.140000'
>>> class Cls(object):
...     def __repr__(self):
...         return "repr"
...     def __str__(self):
...         return "str"
...
'repr'
>>> b'%a' % Cls()
b'repr'

f 字符串

Python 3.6 新特性

  • PEP 498 - 字面量字符串插值

>>> py = "Python3"
>>> f'Awesome {py}'
'Awesome Python3'
>>> x = [1, 2, 3, 4, 5]
>>> f'{x}'
'[1, 2, 3, 4, 5]'
>>> def foo(x:int) -> int:
...     return x + 1
...
>>> f'{foo(0)}'
'1'
>>> f'{123.567:1.3}'
'1.24e+02'

抑制异常

Python 3.3 新特性

  • PEP 409 - 抑制异常上下文

不使用 raise Exception from None

>>> def func():
...     try:
...         1 / 0
...     except ZeroDivisionError:
...         raise ArithmeticError
...
>>> func()
Traceback (most recent call last):
  File "<stdin>", line 3, in func
ZeroDivisionError: division by zero

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in func
ArithmeticError

使用 raise Exception from None

>>> def func():
...     try:
...         1 / 0
...     except ZeroDivisionError:
...         raise ArithmeticError from None
...
>>> func()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in func
ArithmeticError

# debug

>>> try:
...     func()
... except ArithmeticError as e:
...     print(e.__context__)
...
division by zero

生成器委托

Python 3.3 新特性

  • PEP 380 - 委托给子生成器的语法

>>> def fib(n: int):
...     a, b = 0, 1
...     for _ in range(n):
...         yield a
...         b, a = a + b, b
...
>>> def delegate(n: int):
...     yield from fib(n)
...
>>> list(delegate(10))
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

asyncawait 语法

Python 3.5 新特性

  • PEP 492 - 使用 async 和 await 语法的协程

Python 3.5 之前

>>> import asyncio
>>> @asyncio.coroutine
... def fib(n: int):
...     a, b = 0, 1
...     for _ in range(n):
...         b, a = a + b, b
...     return a
...
>>> @asyncio.coroutine
... def coro(n: int):
...     for x in range(n):
...         yield from asyncio.sleep(1)
...         f = yield from fib(x)
...         print(f)
...
>>> loop = asyncio.get_event_loop()
>>> loop.run_until_complete(coro(3))
0
1
1

Python 3.5 或更高版本

>>> import asyncio
>>> async def fib(n: int):
...     a, b = 0, 1
...     for _ in range(n):
...         b, a = a + b, b
...     return a
...
>>> async def coro(n: int):
...     for x in range(n):
...         await asyncio.sleep(1)
...         f = await fib(x)
...         print(f)
...
>>> loop = asyncio.get_event_loop()
>>> loop.run_until_complete(coro(3))
0
1
1

异步生成器

Python 3.6 新特性

  • PEP 525 - 异步生成器

>>> import asyncio
>>> async def fib(n: int):
...     a, b = 0, 1
...     for _ in range(n):
...         await asyncio.sleep(1)
...         yield a
...         b, a = a + b , b
...
>>> async def coro(n: int):
...     ag = fib(n)
...     f = await ag.asend(None)
...     print(f)
...     f = await ag.asend(None)
...     print(f)
...
>>> loop = asyncio.get_event_loop()
>>> loop.run_until_complete(coro(5))
0
1

异步推导式

Python 3.6 新特性

  • PEP 530 - 异步推导式

>>> import asyncio
>>> async def fib(n: int):
...     a, b = 0, 1
...     for _ in range(n):
...         await asyncio.sleep(1)
...         yield a
...         b, a = a + b , b
...

# async for ... else

>>> async def coro(n: int):
...     async for f in fib(n):
...         print(f, end=" ")
...     else:
...         print()
...
>>> loop = asyncio.get_event_loop()
>>> loop.run_until_complete(coro(5))
0 1 1 2 3

# async for in list

>>> async def coro(n: int):
...     return [f async for f in fib(n)]
...
>>> loop.run_until_complete(coro(5))
[0, 1, 1, 2, 3]

# await in list

>>> async def slowfmt(n: int) -> str:
...     await asyncio.sleep(0.5)
...     return f'{n}'
...
>>> async def coro(n: int):
...     return [await slowfmt(f) async for f in fib(n)]
...
>>> loop.run_until_complete(coro(5))
['0', '1', '1', '2', '3']

矩阵乘法

Python 3.5 新特性

  • PEP 465 - 用于矩阵乘法的专用中缀运算符

>>> # "@" represent matrix multiplication
>>> class Arr:
...     def __init__(self, *arg):
...         self._arr = arg
...     def __matmul__(self, other):
...         if not isinstance(other, Arr):
...             raise TypeError
...         if len(self) != len(other):
...             raise ValueError
...         return sum([x*y for x, y in zip(self._arr, other._arr)])
...     def __imatmul__(self, other):
...         if not isinstance(other, Arr):
...             raise TypeError
...         if len(self) != len(other):
...             raise ValueError
...         res = sum([x*y for x, y in zip(self._arr, other._arr)])
...         self._arr = [res]
...         return self
...     def __len__(self):
...         return len(self._arr)
...     def __str__(self):
...         return self.__repr__()
...     def __repr__(self):
...         return "Arr({})".format(repr(self._arr))
...
>>> a = Arr(9, 5, 2, 7)
>>> b = Arr(5, 5, 6, 6)
>>> a @ b  # __matmul__
124
>>> a @= b  # __imatmul__
>>> a
Arr([124])

数据类

Python 3.7 新特性

PEP 557 - 数据类

可变数据类

>>> from dataclasses import dataclass
>>> @dataclass
... class DCls(object):
...     x: str
...     y: str
...
>>> d = DCls("foo", "bar")
>>> d
DCls(x='foo', y='bar')
>>> d = DCls(x="foo", y="baz")
>>> d
DCls(x='foo', y='baz')
>>> d.z = "bar"

不可变数据类

>>> from dataclasses import dataclass
>>> from dataclasses import FrozenInstanceError
>>> @dataclass(frozen=True)
... class DCls(object):
...     x: str
...     y: str
...
>>> try:
...     d.x = "baz"
... except FrozenInstanceError as e:
...     print(e)
...
cannot assign to field 'x'
>>> try:
...     d.z = "baz"
... except FrozenInstanceError as e:
...     print(e)
...
cannot assign to field 'z'

内置 breakpoint()

Python 3.7 新特性

  • PEP 553 - 内置 breakpoint()

>>> for x in range(3):
...     print(x)
...     breakpoint()
...
0
> <stdin>(1)<module>()->None
(Pdb) c
1
> <stdin>(1)<module>()->None
(Pdb) c
2
> <stdin>(1)<module>()->None
(Pdb) c

海象运算符

Python 3.8 新特性

  • PEP 572 - 赋值表达式

海象运算符的目的是在表达式中赋值变量。完成 PEP 572 后,通常被称为 BDFL 的 Guido van Rossum 决定辞去 Python 核心开发者一职。

>>> f = (0, 1)
>>> [(f := (f[1], sum(f)))[0] for i in range(10)]
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

仅限位置参数

Python 3.8 新特性

  • PEP 570 - Python 仅限位置参数

>>> def f(a, b, /, c, d):
...     print(a, b, c, d)
...
>>> f(1, 2, 3, 4)
1 2 3 4
>>> f(1, 2, c=3, d=4)
1 2 3 4
>>> f(1, b=2, c=3, d=4)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: f() got some positional-only arguments passed as keyword arguments: 'b'

字典合并

Python 3.9 新特性

  • PEP 584 - 为 dict 添加联合运算符

>>> a = {"foo": "Foo"}
>>> b = {"bar": "Bar"}

# old way
>>> {**a, **b}
{'foo': 'Foo', 'bar': 'Bar'}
>>> a.update(b)
>>> a
{'foo': 'Foo', 'bar': 'Bar'}

# new way
>>> a | b
{'foo': 'Foo', 'bar': 'Bar'}
>>> a |= b
>>> a
{'foo': 'Foo', 'bar': 'Bar'}