许多人在学习了基本的Python语言知识后,就转入应用阶段了,后期很少对语言自己的新变化、新内容举行跟踪学习和知识更新,甚至连已经公布了好几年的Python3.6的新特征都缺乏领会。

本文列举了Python3.6、3.7、3.8三个版本的新特征,学习它们有助于提高对Python的领会,跟上最新的潮水。

一、Python3.6新特征

1、新的花样化字符串方式

新的花样化字符串方式,即在通俗字符串前添加 fF 前缀,其效果类似于str.format()。好比

name = "red"
print(f"He said his name is {name}.") 
# 'He said his name is red.'

相当于:

print("He said his name is {name}.".format(**locals()))

此外,此特征还支持嵌套字段,好比:

import decimal
width = 10
precision = 4
value = decimal.Decimal("12.34567")
print(f"result: {value:{width}.{precision}}") 
#'result:  12.35'

2、变量声明语法

可以像下面一样声明一个变量并指定类型:

from typing import List, Dict
 
primes: List[int] = []
captain: str  # 此时没有初始值
 
class Starship:
  stats: Dict[str, int] = {}

3、数字的下划线写法

允许在数字中使用下划线,以提高多位数字的可读性。

a = 1_000_000_000_000_000    # 1000000000000000
b = 0x_FF_FF_FF_FF       # 4294967295

除此之外,字符串花样化也支持_选项,以打印出更易读的数字字符串:

'{:_}'.format(1000000)     # '1_000_000'
'{:_x}'.format(0xFFFFFFFF)   # 'ffff_ffff'

4、异步天生器

在Python3.5中,引入了新的语法 async 和 await 来实现协同程序。然则有个限制,不能在同一个函数体内同时使用 yield 和 await。Python3.6中,这个限制被放开了,允许界说异步天生器:

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)

5、异步解析器

允许在列表list、聚集set 和字典dict 解析器中使用 async 或 await 语法。

result = [i async for i in aiter() if i % 2]
result = [await fun() for fun in funcs if await condition()]

6、新增添模块

尺度库(The Standard Library)中增添了一个新的模块:secrets。该模块用来天生一些安全性更高的随机数,用于治理passwords, account authentication, security tokens, 以及related secrets等数据。

7、其他新特征

  • 新的 PYTHONMALLOC 环境变量允许开发者设置内存分配器,以及注册debug钩子等。
  • asyncio模块加倍稳固、高效,而且不再是暂且模块,其中的API也都是稳固版的了。
  • typing模块也有了一定改善,而且不再是暂且模块。
  • datetime.strftime 和 date.strftime 最先支持ISO 8601的时间标识符%G, %u, %V。
  • hashlib 和 ssl 模块最先支持OpenSSL1.1.0。
  • hashlib模块最先支持新的hash算法,好比BLAKE2, SHA-3 和 SHAKE。
  • Windows上的 filesystem 和 console 默认编码改为UTF-8。
  • json模块中的 json.load() 和 json.loads() 函数最先支持 binary 类型输入。

更多内容参考官方文档:What's New In Python 3.6

二、Python3.7新特征

Python 3.7于2018年6月27日公布, 包罗许多新特征和优化,增添了众多新的类,可用于数据处置、针对剧本编译和垃圾网络的优化以及更快的异步I/O,主要如下:

  • 用类处置数据时削减样板代码的数据类。
  • 一处可能无法向后兼容的调换涉及处置天生器中的异常。
  • 面向注释器的“开发模式”。
  • 具有纳秒分辨率的时间工具。
  • 环境中默认使用UTF-8编码的UTF-8模式。
  • 触发调试器的一个新的内置函数。

1、新增内置函数breakpoint()

使用该内置函数,相当于通过代码的方式设置了断点,会自动进入Pbd调试模式。

若是在环境变量中设置PYTHONBREAKPOINT=0会忽略此函数。而且,pdb 只是众多可用调试器之一,你可以通过设置新的 PYTHONBREAKPOINT 环境变量来设置想要使用的调试器。

下面有一个简朴例子,用户需要输入一个数字,判断它是否和目的数字一样:

"""猜数字游戏"""

def guess(target):
    user_guess = input("请输入你猜的数 >>> ")
    if user_guess == target:
        return "你猜对了!"
    else:
        return "猜错了"


if __name__ == '__main__':
    a = 100
    print(guess(a))

不幸的是,纵然猜的数和目的数一样,打印的效果也是‘猜错了’,而且没有任何异常或错误信息。

为了弄清楚发生了什么,我们可以插入一个断点,来调试一下。以往一样平常通过print大法或者IDE的调试工具,但现在我们可以使用 breakpoint()

"""猜数字游戏"""


def guess(target):
    user_guess = input("请输入你猜的数 >>> ")
    breakpoint()   //加入这一行
    if user_guess == target:
        return "你猜对了!"
    else:
        return "猜错了"


if __name__ == '__main__':
    a = 100
    print(guess(a))

在 pdb 提醒符下,我们可以挪用 locals() 来查看当前的内陆作用域的所有变量。(pdb 有大量的下令,你也可以在其中运行正常的Python 语句)

请输入你猜的数 >>> 100
> d:\work\for_test\py3_test\test.py(7)guess()
-> if user_guess == target:
(Pdb) locals()
{'target': 100, 'user_guess': '100'}
(Pdb) type(user_guess)
<class 'str'>

搞明了了,target是一个整数,而user_guess 是一个字符串,这里发生了类型对比错误。

2、类型和注解

从 Python 3.5 最先,类型注解就越来越受欢迎。对于那些不熟悉类型提醒的人来说,这是一种完全可选的注释代码的方式,以指定变量的类型。

什么是注解?它们是关联元数据与变量的语法支持,可以是随便表达式,在运行时被 Python 盘算但被忽略。注解可以是任何有用的 Python 表达式。

下面是个对比的例子:

# 不带类型注解
def foo(bar, baz):
# 带类型注解
def foo(bar: 'Describe the bar', baz: print('random')) -> 'return thingy':

上面的做法,其实是Python对自身弱类型语言的强化,希望获得一定的类型可靠和结实度,向Java等语言靠拢。

在 Python 3.5 中,注解的语法获得尺度化,今后,Python 社区普遍使用了注解类型提醒。

然则,注解仅仅是一种开发工具,可以使用 PyCharm 等 IDE 或 Mypy 品级三方工具举行检查,并不是语法层面的限制。

我们前面的猜数程序若是添加类型注解,它应该是这样的:

"""猜数字游戏"""


def guess(target:str):
    user_guess:str = input("请输入你猜的数 >>> ")
    breakpoint()
    if user_guess == target:
        return "你猜对了!"
    else:
        return "猜错了"


if __name__ == '__main__':
    a:int = 100
    print(guess(a))

PyCharm会给我们灰色的规范错误提醒,但不会给红色的语法错误提醒。

用注解作为类型提醒时,有两个主要问题:启动性能和前向引用

  • 在界说时盘算大量随便表达式相当影响启动性能,而且 typing 模块异常慢
  • 你不能用尚未声明的类型来注解

typing 模块云云缓慢的部门原因是,最初的设计目的是在不修改焦点 CPython 注释器的情形下实现 typing 模块。随着类型提醒变得越来越盛行,这一限制已经被移除,这意味着现在有了对 typing 的焦点支持。

而对于向前引用,看下面的例子:

class User:
    def __init__(self, name: str, prev_user: User) -> None:
        pass

错误在于 User类型还没有被声明,此时的 prev_user 不能界说为 User 类型。

为领会决这个问题,Python3.7 将注解的评估举行了推迟。而且,这项改动向后不兼容,需要先导入annotations,只有到Python 4.0后才会成为默认行为。

from __future__ import annotations

class User: 
    def __init__(self, name: str, prev_user: User) -> None:
        pass

或者如下面的例子:

class C:
    def validate_b(self, obj: B) -> bool:
        ...
class B:
    ...

3、新增dataclasses模块

这个特征可能是 Python3.7以后对照常用的,它有什么作用呢?

如果我们需要编写一个下面的类:

from datetime import datetime
import dateutil

class Article(object):
    def __init__(self, _id, author_id, title, text, tags=None, 
                 created=datetime.now(), edited=datetime.now()):
    self._id = _id
    self.author_id = author_id
    self.title = title
    self.text = text
    self.tags = list() if tags is None else tags
    self.created = created
    self.edited = edited

    if type(self.created) is str:
       self.created = dateutil.parser.parse(self.created)

    if type(self.edited) is str:
       self.edited = dateutil.parser.parse(self.edited)

    def __eq__(self, other):
        if not isinstance(other, self.__class__):
            return NotImplemented
        return (self._id, self.author_id) == (other._id, other.author_id)

    def __lt__(self, other):
        if not isinstance(other, self.__class__):
            return NotImplemented
        return (self._id, self.author_id) < (other._id, other.author_id)

    def __repr__(self):
        return '{}(id={}, author_id={}, title={})'.format(
                self.__class__.__name__, self._id, self.author_id, self.title)

大量的初始化属性要界说默认值,可能还需要重写一堆邪术方式,来实现类实例的打印、对照、排序和去重等功能。

若是使用dataclasses举行革新,可以写成这个样子:

from dataclasses import dataclass, field
from typing import List
from datetime import datetime
import dateutil

@dataclass(order=True)   //注重这里
class Article(object):
    _id: int
    author_id: int
    title: str = field(compare=False)
    text: str = field(repr=False, compare=False)
    tags: List[str] = field(default=list(), repr=False, compare=False)
    created: datetime = field(default=datetime.now(), repr=False, compare=False)
    edited: datetime = field(default=datetime.now(), repr=False, compare=False)

    def __post_init__(self):
       if type(self.created) is str:
           self.created = dateutil.parser.parse(self.created)

       if type(self.edited) is str:
           self.edited = dateutil.parser.parse(self.edited)

这使得类不仅容易设置,而且当我们建立一个实例并打印出来时,它还可以自动天生优美的字符串。在与其他类实例举行对照时,它也会有适当的行为。这是由于dataclasses除了帮我们自动天生 __init__ 方式外,还天生了一些其他特殊方式,如 repreqhash 等。

Dataclasses 使用字段 field来完提供默认值,手动组织一个 field() 函数能够接见其他选项,从而更改默认值。例如,这里将 field 中的 default_factory 设置为一个 lambda 函数,该函数提醒用户输入其名称。

from dataclasses import dataclass, field
class User:
    name: str = field(default_factory=lambda: input("enter name"))

4、天生器异常处置

在Python 3.7中,天生器引发StopIteration异常后,StopIteration异常将被转换成RuntimeError异常,那样它不会悄悄一起影响应用程序的客栈框架。这意味着若何处置天生器的行为方面不太敏锐的一些程序会在Python 3.7中抛出RuntimeError。在Python 3.6中,这种行为天生一个弃用忠告;在Python 3.7中,它将天生一个完整的错误。

一个浅易的方式是使用try/except代码段,在StopIteration传播到天生器的外面捕捉它。更好的解决方案是重新考虑若何构建天生器――好比说,使用return语句来终止天生器,而不是手动引发StopIteration。

5、开发模式

Python注释器添加了一个新的下令行开关:-X,让开发人员可以为注释器设置许多低级选项。

这种运行时的检查机制通常对性能有重大影响,但在调试历程中对开发人员很有用。

-X 激活的选项包罗:

  • asyncio模块的调试模式。这为异步操作提供了更详细的日志纪录和异常处置,而异常操作可能很难调试或推理。
  • 面向内存分配器的调试钩子。这对于编写CPython扩展件的那些人很有用。它能够实现更明确的运行时检查,领会CPython若何在内部门配内存和释放内存。
  • 启用faulthandler模块,那样发生溃逃后,traceback始终转储出去。

6、 高精度时间函数

Python 3.7中一类新的时间函数返回纳秒精度的时间值。只管Python是一种注释型语言,然则Python的焦点开发人员维克多•斯廷纳(Victor Stinner)主张讲述纳秒精度的时间。最主要的原因是,在处置转换其他程序(好比数据库)纪录的时间值时,可以制止丢失精度。

新的时间函数使用后缀_ns好比说,time.process_time()的纳秒版本是time.process_time_ns()。请注重,并非所有的时间函数都有对应的纳秒版本。

7、其他新特征

  • 字典现在保持插入顺序。这在 3.6 中是非正式的,但现在成为了官方语言规范。在大多数情形下,通俗的 dict 能够替换 collections.OrderedDict
  • .pyc 文件具有确定性,支持可重复构建 —— 也就是说,总是为相同的输入文件天生相同的 byte-for-byte 输出。
  • 新增contextvars模块,针对异步义务提供上下文变量。
  • __main__中的代码会显示弃用忠告(DeprecationWarning)。
  • 新增UTF-8模式。在Linux/Unix系统,将忽略系统的locale,使用UTF-8作为默认编码。在非Linux/Unix系统,需要使用-X utf8选项启用UTF-8模式。
  • 允许模块界说__getattr__、__dir__函数,为弃用忠告、延迟import子模块等提供便利。
  • 新的线程内陆存储C语言API。
  • 更新Unicode数据到11.0。

三、Python3.8新特征

Python3.8版本于2019年10月14日公布,以下是 Python 3.8 相比 3.7 的新增特征。

1、海象赋值表达式

新的语法 :=,将值赋给一个更大的表达式中的变量。它被亲热地称为 “海象运算符”(walrus operator),由于它长得像海象的眼睛和象牙。

“海象运算符” 在某些时刻可以让你的代码更整齐,好比:

在下面的示例中,赋值表达式可以制止挪用 len () 两次:

if (n := len(a)) > 10:	
    print(f"List is too long ({n} elements, expected <= 10)")

类似的利益还可体现在正则表达式匹配中需要使用两次匹配工具的情形中,一次检测用于匹配是否发生,另一次用于提取子分组:

discount = 0.0	

if (mo := re.search(r'(\d+)% discount', advertisement)):	
    discount = float(mo.group(1)) / 100.0

此运算符也可用于配合 while 循环盘算一个值,来检测循环是否终止,而同一个值又在循环体中再次被使用的情形:

# Loop over fixed length blocks	

while (block := f.read(256)) != '':	
    process(block)

或者泛起于列表推导式中,在筛选条件中盘算一个值,而同一个值又在表达式中需要被使用:

[clean_name.title() for name in names	

 if (clean_name := normalize('NFC', name)) in allowed_names]

请只管将海象运算符的使用限制在清晰的场所中,以降低复杂性并提升可读性。

2、仅限位置形参

新增一个函数形参语法 / 用来指明某些函数形参必须使用仅限位置而非要害字参数的形式。

这种符号语法与通过 help () 所显示的使用 Larry Hastings 的 Argument Clinic 工具符号的 C 函数相同。

在下面的例子中,形参 a 和 b 为仅限位置形参,c 或 d 可以是位置形参或要害字形参,而 e 或 f 要求为要害字形参:

def f(a, b, /, c, d, *, e, f):	

    print(a, b, c, d, e, f)

以下是正当的挪用:

f(10, 20, 30, d=40, e=50, f=60)

然则,以下均为不正当的挪用:

f(10, b=20, c=30, d=40, e=50, f=60)   # b 不能以是一个要害字参数
f(10, 20, 30, 40, 50, f=60)           # e 必须是一个要害字参数

这种符号形式的一个用例是它允许纯 Python 函数完整模拟现有的用 C 代码编写的函数的行为。例如,内置的 pow () 函数不接受要害字参数:

def pow(x, y, z=None, /):	

    "Emulate the built in pow() function"	

    r = x ** y	

    return r if z is None else r%z

另一个用例是在不需要形参名称时清扫要害字参数。例如,内置的 len () 函数的签名为 len (obj, /)。这可以清扫如下这种拙笨的挪用形式:

len(obj='hello')  # The "obj" keyword argument impairs readability

另一个益处是将形参符号为仅限位置形参将允许在未来修改形参名而不会损坏客户的代码。例如,在 statistics 模块中,形参名 dist 在未来可能被修改。这使得以下函数形貌成为可能:

def quantiles(dist, /, *, n=4, method='exclusive')	
    ...

由于在 / 左侧的形参不会被公然为可用要害字,其他形参名仍可在 **kwargs 中使用:

>>> def f(a, b, /, **kwargs):	
...     print(a, b, kwargs)	
...	
>>> f(10, 20, a=1, b=2, c=3)         # a and b are used in two ways	
10 20 {'a': 1, 'b': 2, 'c': 3}

这极大地简化了需要接受随便要害字参数的函数和方式的实现。例如,下面是 collections 模块中的代码摘录:

class Counter(dict):	

    def __init__(self, iterable=None, /, **kwds):	

        # Note "iterable" is a possible keyword argument

3、f 字符串支持 =

增添 = 说明符用于 f-string。形式为 f'{expr=}' 的 f 字符串将扩展示意为表达式文本,加一个等于号,再加表达式的求值效果。例如:

>>> user = 'eric_idle'	
>>> member_since = date(1975, 7, 31)	
>>> f'{user=} {member_since=}'	

"user='eric_idle' member_since=datetime.date(1975, 7, 31)"

f 字符串花样说明符允许更仔细地控制所要显示的表达式效果:

>>> delta = date.today() - member_since	

>>> f'{user=!s}  {delta.days=:,d}'	
'user=eric_idle  delta.days=16,075'

= 说明符将输出整个表达式,以便详细演示盘算历程:

>>> print(f'{theta=}  {cos(radians(theta))=:.3f}')	
theta=30  cos(radians(theta))=0.866

4、 typing模块的改善

Python是动态类型语言,但可以通过typing模块添加类型提醒,以便第三方工具验证Python代码。Python 3.8给typing添加了一些新元素,因此它能够支持更结实的检查:

  • final修饰器和Final类型标注解释,被修饰或被标注的工具在任何时刻都不应该被重写、继续,也不能被重新赋值。
  • Literal类型将表达式限定为特定的值或值的列表(纷歧定是同一个类型的值)。
  • TypedDict可以用来建立字典,其特定键的值被限制在一个或多个类型上。注重这些限制仅用于编译时确定值的正当性,而不能在运行时举行限制。

5、多历程共享内存

multiprocessing模块新增SharedMemory类,可以在差别的Python进城之间建立共享的内存区域。

在旧版本的Python中,历程间共享数据只能通过写入文件、通过网络套接字发送,或接纳Python的pickle模块举行序列化等方式。共享内存提供了历程间通报数据的更快的方式,从而使得Python的多处置器和多内核编程更有用率。

共享内存片断可以作为单纯的字节区域来分配,也可以作为不能修改的类似于列表的工具来分配,其中能保留数字类型、字符串、字节工具、None工具等一小部门Python工具。

6、 新版本的pickle协议

Python的pickle模块提供了一种序列化和反序列化Python数据结构或实例的方式,可以将字典原样保留下来供以后读取。差别版本的Python支持的pickle协议差别,而3.8版本的支持局限更广、更壮大、更有用的序列化。

Python 3.8引入的第5版pickle协议可以用一种新方式pickle工具,它能支持Python的缓冲区协议,如bytes、memoryviews或Numpy array等。新的pickle制止了许多在pickle这些工具时的内存复制操作。

NumPy、Apache Arrow等外部库在各自的Python绑定中支持新的pickle协议。新的pickle也可以作为Python 3.6和3.7的插件使用,可以从PyPI上安装。

7、性能改善

  • 许多内置方式和函数的速率都提高了20%~50%,由于之前许多函数都需要举行不必要的参数转换。
  • 一个新的opcode缓存可以提高注释器中特定指令的速率。然则,现在实现了速率改善的只有LOAD_GLOBAL opcode,其速率提高了40%。以后的版本中也会举行类似的优化。
  • 文件复制操作如shutil.copyfile()shutil.copytree()现在使用平台特定的挪用和其他优化措施,来提高操作速率。
  • 新建立的列表现在平均比以前小了12%,这要归功于列表组织函数若是能提前知道列表长度的情形下,可以举行优化。
  • Python 3.8中向新型类(如class A(object))的类变量中的写入操作变得更快。operator.itemgetter()和collections.namedtuple()也得到了速率优化。

更多详细特征,请查阅Python 3.8.0文档:https://docs.python.org/zh-cn/3.8/whatsnew/3.8.html

更多内容请接见: https://www.liujiangblog.com

更多视频教程请接见: https://www.liujiangblog.com/video/

,

阳光在线

阳光在线www.asiashopp.com(原诚信在线)现已开放阳光在线手机版下载。阳光在线游戏公平、公开、公正,用实力赢取信誉。

Sunbet声明:该文看法仅代表作者自己,与本平台无关。转载请注明:无锡二手房网:你应该知道的Python3.6、3.7、3.8新特征
发布评论

分享到:

高雄市长放假去,说好的宝可梦日也没了
你是第一个吃螃蟹的人
发表评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。