Python 3.8 新特性全面解读

本文详细介绍 Python 3.8 中的新功能,以及和与 3.7 相比的一些不同点。

新功能

编译的字节码文件的并行文件系统缓存新的 PYTHONPYCACHEPREFIX设置 (也可用 )将隐式字节码缓存配置为使用单独的并行文件系统树,而不是每个源目录中的默认子目录。 -X pycache_prefix__pycache_ 报告缓存的位置 sys.pycache_prefix (None表示 pycache 子目录中的默认位置)。

其他语言变更

一个 continue 说法是非法 finally 条款因与实施问题。在Python 3.8中,这一限制被取消了。

该int类型现在具有 as_integer_ratio() 与现有 float.as_integer_ratio() 方法兼容的新方法。

增加了对 \N{name} 的支持。

Dictdictviews 现在可以使用反向插入顺序进行迭代  reversed()

函数调用中允许关键字名称的语法进一步受到限制。特别是,f((keyword)=arg)不再允许。它从来没有打算在关键字参数赋值术语的左侧允许多于一个裸名称。见bpo-34641。

现在允许Iterable解包,而不使用括号yield 和return语句。(由David Cuthbert和Jordan Chapman在bpo-32117中提供。)

不是有效转义序列的反斜杠字符对DeprecationWarning从Python 3.6开始生成。在Python 3.8中它生成了一个SyntaxWarning代替。(由Serhiy Storchaka供稿于bpo-32912。)

SyntaxWarning在某些情况下,编译器会在元组或列表之前错过逗号时生成。例如:

1data = [
2    (1, 2, 3) # oops, missing comma!
3    (4, 5, 6)
4]

子类之间的算术运算 datetime.date 或  datetime.datetimedatetime.timedelta 对象现在返回子类的实例,而不是基类。这也会影响其实现(直接或间接)使用 datetime.timedelta 算术的操作的返回类型,例如  datetime.datetime.astimezone()

当Python解释器被Ctrl-C(SIGINT)中断并且KeyboardInterrupt未捕获到的结果异常时,Python进程现在通过SIGINT信号或正确的退出代码退出,以便调用进程可以检测到它因Ctrl而死亡-C。POSIX和Windows上的shell使用它来正确终止交互式会话中的脚本。

改进的模块

现在的_asdict()方法 collections.namedtuple() 返回一个dict而不是一个 collections.OrderedDict 。这是有效的,因为自Python 3.7以来,常规dicts已经保证了排序。如果需要额外的功能OrderedDict,建议的补救措施是将结果转换为所需的类型:OrderedDict(nt._asdict())。该 unicodedata 模块已升级为使用Unicode 12.0.0 版本。

ASYNCIO

在Windows上,现在是默认的事件循环ProactorEventLoop。

gettext

添加 pgettext() 及其变体。

检查

如果该属性是值为 docstrings 的位置,该 inspect.getdoc() 函数现在可以找到文档字符串。这提供了类似于我们已经有文件的选项,以及: __slots__dictproperty()classmethod()staticmethod()

1class AudioClip:
2    __slots__ = {'bit_rate': 'expressed in kilohertz to one decimal place',
3                 'duration': 'in seconds, rounded up to an integer'}
4    def __init__(self, bit_rate, duration):
5        self.bit_rate = round(bit_rate / 1000.0, 1)
6        self.duration = ceil(duration)

GC

get_objects()现在可以接收一个可选的生成参数,指示从中获取对象的生成。由Pablo Galindo 提供的 bpo-36016。

gzip

添加了mtime参数以gzip.compress()获得可重现的输出。(由Guo Ci Teo在bpo-34898供稿。)

idlelib和IDLE

超过N行的输出(默认为50)被压缩到一个按钮。可以在“设置”对话框的“常规”页面的PyShell部分中更改N. 右键单击输出可以挤压更少但可能超长的线条。通过双击按钮或通过右键单击按钮进入剪贴板或单独的窗口,可以扩展压缩输出。(由Tal Einat在bpo-1529353供稿。)

上述更改已被移植到3.7维护版本。

json.tool

添加选项--json-lines以将每个输入行解析为单独的JSON对象。(由Weipeng Hong在bpo-31553供稿。)

计算

增加 math.dist() 了计算两点之间欧氏距离的新函数。

扩展了 math.hypot() 处理多个维度的功能。以前,它只支持2-D案例。

添加了新函数, math.prod() 作为类似函数sum() 返回 “start” 值(默认值:1)乘以可迭代数字的乘积。

os.path

os.path 返回一个布尔值结果类似功能 exists()lexists()isdir() ,  isfile()islink() ,和 ismount() 现在回到False代替升高 ValueError 或它的子类  UnicodeEncodeError ,并 UnicodeDecodeError 为包含字符或字节在OS级不可表示的路径。

expanduser() 在Windows上现在更喜欢 USERPROFILE 环境变量,不使用 HOME,通常不为常规用户帐户设置。

ncurses

添加了一个新变量,其中包含底层 ncurses 库的结构化版本信息:ncurses_version。

pathlib

pathlib.Path返回布尔结果类似方法 exists(),is_dir(), is_file(),is_mount(), is_symlink(),is_block_device(), is_char_device(),is_fifo(), is_socket()现在回到False而不是提高 ValueError或它的子类UnicodeEncodeError的包含字符的不可表示在操作系统级别路径。(由Serhiy Storchaka供稿于bpo-33721。)

shutil

shutil.copytree() 现在接受一个新的 dirs_exist_ok 关键字参数。

SSL

添加 SSLContext.post_handshake_auth 以启用和  ssl.SSLSocket.verify_client_post_handshake() 启动TLS 1.3握手后身份验证。

统计

添加 statistics.fmean() 为更快的浮点变体 statistics.mean()

添加 statistics.multimode() 了返回最常见值的列表。

添加 statistics.NormalDist 了一个用于创建和操作随机变量的正态分布的工具.

1>>>
2>>> temperature_feb = NormalDist.from_samples([4, 12, -3, 2, 7, 14])
3>>> temperature_feb
4NormalDist(mu=6.0, sigma=6.356099432828281)
5
6>>> temperature_feb.cdf(3)            # Chance of being under 3 degrees
70.3184678262814532
8>>> # Relative chance of being 7 degrees versus 10 degrees
9>>> temperature_feb.pdf(7) / temperature_feb.pdf(10)
101.2039930378537762
11
12>>> el_nino = NormalDist(4, 2.5)
13>>> temperature_feb += el_nino        # Add in a climate effect
14>>> temperature_feb
15NormalDist(mu=10.0, sigma=6.830080526611674)
16
17>>> temperature_feb * (9/5) + 32      # Convert to Fahrenheit
18NormalDist(mu=50.0, sigma=12.294144947901014)
19>>> temperature_feb.samples(3)        # Generate random samples
20[7.672102882379219, 12.000027119750287, 4.647488369766392]

tar文件

该tarfile模块现在默认为新档案的现代pax(POSIX.1-2001)格式,而不是之前的GNU特定格式。这通过标准化和可扩展格式的一致编码(UTF-8)提高了跨平台的可移植性,并提供了其他一些好处。

令牌化

当提供没有尾随新行的输入时,tokenize模块现在隐式地发出NEWLINE令牌。此行为现在与C tokenizer在内部执行的操作相匹配。

Tkinter

添加的方法selection_from(), selection_present(), selection_range()和 selection_to() 在tkinter.Spinbox类。

moveto() 在tkinter.Canvas课堂上添加了方法。

时间

CLOCK_UPTIME_RAW为macOS 10.12 添加了新时钟。

unicodedata

新函数 is_normalized() 可用于验证字符串是否处于特定的正常形式。

单元测试

添加addModuleCleanup()并 addClassCleanup()进行unittest以支持setUpModule()和的 清理setUpClass()。

VENV

venv现在,Activate.ps1在PowerShell Core 6.1下,所有平台上都包含一个用于激活虚拟环境的脚本。

XML

作为对DTD和外部实体检索的缓解,默认情况下, xml.dom.minidom和xml.sax模块不再处理外部实体。

优化

  • subprocess现在,模块可以os.posix_spawn()在某些情况下使用该功能以获得更好的性能。目前,如果满足所有这些条件,它仅用于 macOSLinux

    -close_fds为false;

    未设置preexec_fn,pass_fds,cwd和start_new_session参数;

    该可执行文件路径中包含一个目录。

    -shutil.copyfile(),shutil.copy(),shutil.copy2(), shutil.copytree()并shutil.move()使用特定于平台的“快速复制”在Linux,MacOS的和Solaris,以更有效地复制文件系统调用。“快速复制”意味着复制操作发生在内核中,避免在Python中使用用户空间缓冲区,如“ outfd.write(infd.read())”。在Windows上shutil.copyfile()使用更大的默认缓冲区大小(1 MiB而不是16 KiB),并使用memoryview()基于a 的变体 - shutil.copyfileobj()。在同一分区中复制512 MiB文件的速度在Linux上约为+ 26%,在macOS上为+ 50%,在Windows上为+ 40%。此外,消耗的CPU周期更少。请参阅与平台相关的高效复制操作部分。

  • shutil.copytree()使用os.scandir()函数和依赖它的所有复制函数使用缓存os.stat()值。复制具有8000个文件的目录的速度在Linux上约为+ 9%,在Windows上为+ 20%,在Windows SMB共享上为+ 30%。此外,os.stat() 系统调用的数量减少了38%,使shutil.copytree()网络文件系统的速度更快。

    -pickle模块中的默认协议现在是协议4,首先在Python 3.4中引入。与Python 3.0以来提供的Protocol 3相比,它提供了更好的性能和更小的尺寸。

    删除了一个Py_ssize_t成员PyGC_Head。所有GC跟踪对象(例如元组,列表,字典)的大小减少了4或8个字节。

  • uuid.UUID现在用于 slots__减少其内存占用。 -性能提升operator.itemgetter()了33%。优化参数处理并为单个非负整数索引的常见情况添加快速路径到元组(这是标准库中的典型用例)。 -加速字段查找collections.namedtuple()。它们现在的速度提高了两倍以上,使它们成为Python中最快的实例变量查找形式。 -list如果输入iterable具有已知长度(输入实现__len ),则构造函数不会全局定位内部项缓冲区。这使得创建的列表平均减少12%。(由Raymond Hettinger和Pablo Galindo在bpo-33234中提供。)

    -将类变量写入的速度加倍。更新非dunder属性时,会有不必要的更新插槽调用。(由Stefan Behnel,Pablo Galindo Salgado,Raymond Hettinger,Neil Schemenauer和Serhiy Storchaka供稿于bpo-36012。)

    -减少转换传递给许多内置函数和方法的参数的开销。加快调用一些简单的内置函数和方法,最多可达20-50%。(由Serhiy Storchaka在bpo-23867, bpo-35582和bpo-36127供稿。)

构建和C API更改

  • 这些PyByteArray_Init()和PyByteArray_Fini()功能已被删除。他们没有做任何事情,因为Python 2.7.4和Python 3.2.0被排除在有限的API(稳定的ABI)之外,并且没有记录。

  • 结果PyExceptionClass_Name()现在是类型 而不是。const char *char *

  • 二元性 Modules/Setup.dist 和  Modules/Setup 已被删除。以前,在更新CPython源代码树时,必须手动将Modules/Setup.dist(在源代码树内)复制到 Modules/Setup(在构建树内)以反映上游的任何更改。这对包装商来说是一个小小的好处,代价是CPython开发后开发人员经常烦恼,因为忘记复制文件可能会导致构建失败。

  • 现在构建系统总是从Modules/Setup源树内部读取。鼓励想要自定义该文件的人将其更改保存在CPython的git fork中或作为补丁文件,就像它们对源树的任何其他更改一样。

  • 将Python数转换为C整数的 PyLong_AsLong() 函数和参数解析函数(如 PyArg_ParseTuple()整数转换格式单位)'i' 现在将使用 __index__() 特殊方法而不是(  int__()如果可用)。将使用 _int_ ()方法但没有  _index_ ()方法(如 Decimal和 Fraction) 为对象发出弃用警告。  PyNumber_Check() 现在将返回 1实现的对象__index ()。

  • 堆分配的类型对象现在将增加它们PyObject_Init()(和它的并行宏PyObject_INIT)中的引用计数而不是in PyType_GenericAlloc()。可能需要调整修改实例分配或释放的类型。

不支持

  • 不建议使用的方法 getchildren()getiterator()ElementTree 模块现在发出  DeprecationWarning 来代替 PendingDeprecationWarning 。它们将在Python 3.9中删除。

  • 传递一个不是 concurrent.futures.ThreadPoolExecutorto 的实例的对象已  asyncio.loop.set_default_executor() 被弃用,并且将在Python 3.9中被禁止。

  • getitem() 方法 xml.dom.pulldom.DOMEventStream ,  wsgiref.util.FileWrapper 并fileinput.FileInput已被弃用。

这些方法的实现忽略了它们的索引参数,而是返回下一个项目。

  • typing.NamedTuple 已否决了, _field_types 赞成的属性 __annotations __具有相同信息的属性。

    ast类Num,Str,Bytes, NameConstant 和  Ellipsis 被标记是过时的,并将在未来的Python版本中删除。Constant应该用来代替。

  • 下面的函数和方法弃用在gettext 模块: lgettext()ldgettext() , lngettext()和ldngettext()。它们返回编码的字节,如果翻译的字符串存在编码问题,则可能会出现意外的与Unicode相关的异常。在Python 3中使用返回Unicode字符串的替代方法要好得多。这些功能已经被打破了很长时间。

  • 功能 bind_textdomain_codeset() ,方法  output_charset() 和  set_output_charset() ,以及代码集 的功能参数 translation()install() 也不赞成使用,因为它们仅用于为l*gettext()功能。

    -该 isAlive() 方法 threading.Thread 已被弃用。

许多带有整数参数的内置函数和扩展函数现在将为Decimals,Fractions和任何其他对象发出弃用警告, 这些对象只能在丢失的情况下转换为整数(例如,具有 int__() 方法但没有__index ()方法)。在将来的版本中,它们将是错误的。

API和功能删除

从`Python 3.8`中删除了以下功能和API:

  • macpath 已删除在 Python 3.7 中弃用的模块。

    该函数 platform.popen() 已被删除,自Python 3.3以来已被弃用:os.popen()改为使用。

  • 该pyvenv脚本已被删除, 以帮助消除关于 脚本绑定的Python解释器的混淆。python3.8 - m venvpyvenv

  • parse_qs,parse_qslescape 从除去cgi 模块。它们已从Python 3.2或更早版本弃用。

  • filemode 功能已从 tarfile 模块中删除。自Python 3.3以来,它没有记录和弃用。

    XMLParser 构造不再接受 HTML 参数。它从未产生过影响,在Python 3.4中已被弃用。所有其他参数现在都是仅关键字。

  • 删除了doctype()方法XMLParser。

  • unicode_internal 编解码器被删除。

移植

本节列出了先前描述的更改以及可能需要更改代码的其他错误修正。

## Python行为的变化

  • 屈服表达式(both yield和子句)现在在理解和生成器表达式中是不允许的(除了最左边的子句中的可迭代表达式)

  • 编译器现在生成一个 SyntaxWarning 何时身份检查 与某些类型的文字(例如字符串,整数)一起使用。这些通常可以在 CPython 中偶然使用,但不受语言规范的保证。警告建议用户使用相等测试。

Python API的变化

  • 该函数 platform.popen() 已被删除,自Python 3.3以来已被弃用:os.popen()改为使用。

  • statistics.mode() 给定多模态数据时,该函数不再引发异常。相反,它返回输入数据中遇到的第一个模式。

    该类的 selection() 方法  tkinter.ttk.Treeview 不再需要参数。在Python 3.6中不推荐使用带有参数来更改选择。使用专门的方法,如 selection_set() 更改选择。

  • writexml(),toxml()并且toprettyxml()所述的方法 xml.dom.minidom模块,和xml.etree现在保存由用户指定的属性顺序。(

    -dbm.dumb使用flags打开的数据库'r'现在是只读的。 dbm.dumb.open()带有标志'r','w'如果不存在则不再创建数据库。

  • 将不再调用 doctype() 子类中定义的方法,  XMLParser 并且将导致发出a RuntimeWarning而不是a  DeprecationWarningdoctype() 在目标上定义用于处理XML doctype声明的方法。

  • 一个RuntimeError是现在时引发自定义的元类不提供 classcell__传入的名称空间项 type.__new 。A DeprecationWarning是在Python 3.6-3.7中发出的。

  • 在cProfile.Profile类现在可以作为一个上下文管理器。

  • shutil.copyfile()shutil.copy()shutil.copy2() ,  shutil.copytree()shutil.move() 使用特定于平台的“快速复制”的系统调用

  • shutil.copyfile() Windows上的默认缓冲区大小从16 KiB更改为1 MiB。

  • PyGC_Head 结构完全改变了。触及 struct 成员的所有代码都应该被重写。

  • PyInterpreterState 结构已被移入“内部”头文件(特别是Include / internal / pycore_pystate.h)。 opaque PyInterpreterState 仍然可用作公共API(和稳定的ABI)的一部分。文档表明struct的字段都不公开,所以我们希望没有人使用它们。但是,如果您确实依赖于一个或多个私有字段而没有其他选择,那么请打开一个BPO问题。我们将努力帮助您进行调整(可能包括向公共API添加访问器功能)。

  • ASYNCIO任务现在可以命名,或者通过将name关键字参数 asyncio.create_task() 或create_task()事件循环的方法,或者通过调用 set_name() 任务对象的方法。任务名称在repr()输出中可见, asyncio.Task 也可以使用该 get_name() 方法检索。

  • mmap.flush() 方法现在返回None成功并在所有平台下引发错误异常。以前,它的行为是平台依赖的:成功时返回非零值; 在Windows下错误返回零。成功返回零值; 在Unix下出现异常错误。

  • 该函数 math.factorial() 不再接受非int类的参数。

  • xml.dom.minidom和xml.sax 模块默认不再处理外部实体。

  • 从只读dbm数据库(dbm.dumb, dbm.gnu或dbm.ndbm)中删除密钥会引发error(dbm.dumb.error, dbm.gnu.error或dbm.ndbm.error)而不是KeyError。

  • expanduser() 在Windows上现在更喜欢 USERPROFILE 环境变量,不使用 HOME,通常不为常规用户帐户设置。

使用#在分析或建筑价值的形式变体(例如 PyArg_ParseTuple(), Py_BuildValue()PyObject_CallFunction() 没有等) PY_SSIZE_T_CLEAN 定义提出了DeprecationWarning现在。它将在3.10或4.0中删除。阅读解析参数并为细节构建值。(由Inada Naoki在bpo-36381供稿。)

C API的变化

-堆分配类型的实例(例如用其创建的实例 PyType_FromSpec() )保存对其类型对象的引用。增加这些类型对象的引用计数已从  PyType_GenericAlloc() 更低级别的函数移动,  PyObject_Init() 并且 PyObject_INIT() 。这使得通过 PyType_FromSpec() 托管代码中的其他类行为创建类型。

静态分配的类型不受影响。

对于绝大多数情况,应该没有副作用。但是,在分配实例(可能是为了解决bug)之后手动增加引用计数的类型现在可能变得不朽。为避免这种情况,这些类需要在实例释放期间在类型对象上调用 Py_DECREF

要将这些类型正确移植到3.8,请应用以下更改:

Py_INCREF 分配实例后删除类型对象 - 如果有的话。这可能打完电话后发生的 PyObject_New() ,  PyObject_NewVar()PyObject_GC_New() ,  PyObject_GC_NewVar() ,或使用任何其他自定义分配器  PyObject_Init()PyObject_INIT()

例:

1static foo_struct *
2foo_new(PyObject *type) {
3    foo_struct *foo = PyObject_GC_New(foo_struct, (PyTypeObject *) type);
4    if (foo == NULL)
5        return NULL;
6#if PY_VERSION_HEX < 0x03080000
7    // Workaround for Python issue 35810; no longer necessary in Python 3.8
8    PY_INCREF(type)
9#endif
10    return foo;
11}

确保 tp_dealloc 堆分配类型的所有自定义函数都减少了类型的引用计数。

例:

1 static void
2foo_dealloc(foo_struct *instance) {
3    PyObject *type = Py_TYPE(instance);
4    PyObject_GC_Del(instance);
5#if PY_VERSION_HEX >= 0x03080000
6    // This was not needed before Python 3.8 (Python issue 35810)
7    Py_DECREF(type);
8#endif
9}

CPython字节码更改

通过移动将块堆栈展开到编译器中的逻辑,简化了解释器循环。编译器现在发出显式指令,用于调整值堆栈并调用清理代码 breakcontinue 和  return

删除操作码 BREAK_LOOP,CONTINUE_LOOP ,  SETUP_LOOP和SETUP_EXCEPT 。增加了新的操作码 ROT_FOUR,BEGIN_FINALLY,CALL_FINALLY 和  POP_FINALLY。改变了 END_FINALLY WITH_CLEANUP_START 。 添加了新的操作码, END_ASYNC_FOR`用于处理在等待循环中的下一个项目时引发的异常。

详情查看  KotlinPython 公众号 的这篇介绍。

我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章