• Python 3.11新功能:错误信息回溯


    错误信息回溯

    长按关注《Python学研大本营》,加入读者群,分享更多精彩 扫码关注《Python学研大本营》,加入读者群,分享更多精彩

    Python 3.11于2022 年 10 月 24 日发布。这个最新版本的 Python 速度更快,对用户更友好。

    与每个版本一样,Python 3.11 都进行了许多改进和更改。您可以在文档中看到所有这些的列表。在这里,您将探索最酷、最具影响力的新功能。

    在本专题的教程中,您将了解新功能和改进,例如:

    • 更好的错误消息和更多信息的回溯

    • 由于Faster CPython项目付出了巨大的努力,代码执行速度更快

    • 简化使用异步代码的任务和异常组

    • 改进 Python 的静态类型支持的几个新类型特性

    • 本机TOML 支持处理配置文件

    如果您想尝试本教程中的任何示例,则需要使用 Python 3.11。Python 3 安装和设置指南(https://realpython.com/installing-python/)以及如何安装 Python 的预发布版本(https://realpython.com/python-pre-release/)引导您完成向系统添加新版本 Python 的几个选项。

    除了了解有关该语言的新功能的更多信息外,您还将获得一些关于在升级到新版本之前要考虑什么的建议。下面的链接下载演示 Python 3.11 新功能的代码示例(https://realpython.com/bonus/python-311-examples/)

    信息错误回溯

    Python 通常被认为是一种很好的初学者编程语言,它具有可读的语法和强大的数据结构。所有人都面临的挑战,尤其是那些刚接触 Python 的人,是如何解释Python 遇到错误时显示的回溯。

    在Python 3.10中,Python 的错误信息得到了极大的改进。同样,Python 3.11最受期待的功能之一也将提升您的开发者体验。装饰性注释被添加到回溯中,可以帮助您更快地解释错误消息。

    要查看增强回溯的快速示例,请将以下代码添加到inverse.py的文件中:

    1. # inverse.py
    2. def inverse(number):
    3.     return 1 / number
    4. print(inverse(0))

    你可以用它inverse()来计算一个数的乘法倒数。没有乘法逆元0,因此您的代码在运行时会引发错误:

    1. $ python inverse.py
    2. Traceback (most recent call last):
    3.   File "/home/realpython/inverse.py"line 6in <module>
    4.     print(inverse(0))
    5.           ^^^^^^^^^^
    6.   File "/home/realpython/inverse.py"line 4in inverse
    7.     return 1 / number
    8.            ~~^~~~~~~~
    9. ZeroDivisionError: division by zero

    请注意嵌入在回溯中的^和符号~,它们用于引导您注意导致错误的代码。像往常一样使用回溯,您应该从底部开始,然后逐步向上。在此示例中, aZeroDivisionError是由除法引起的1 / number。真正的罪魁祸首是inverse(0),因为0没有相反的情况。

    在发现错误时获得这种额外的帮助很有用。但是,如果您的代码更复杂,带注释的回溯功能会更加强大。他们可能能够传达您以前无法从回溯中获得的信息。

    要了解改进的回溯的强大功能,您将构建一个关于少数程序员的信息的小型解析器。假设您有一个名为programmers.json的文件:

    1. [
    2.     {"name": {"first""Uncle Barry"}},
    3.     {
    4.         "name": {"first""Ada""last""Lovelace"},
    5.         "birth": {"year"1815},
    6.         "death": {"month"11"day"27}
    7.     },
    8.     {
    9.         "name": {"first""Grace""last""Hopper"},
    10.         "birth": {"year"1906"month"12"day"9},
    11.         "death": {"year"1992"month"1"day"1}
    12.     },
    13.     {
    14.         "name": {"first""Ole-Johan""last""Dahl"},
    15.         "birth": {"year"1931"month"10"day"12},
    16.         "death": {"year"2002"month"6"day"29}
    17.     },
    18.     {
    19.         "name": {"first""Guido""last""Van Rossum"},
    20.         "birth": {"year"1956"month"1"day"31},
    21.         "death"null
    22.     }
    23. ]

    请注意,有关程序员的信息非常不一致。虽然有关Grace Hopper和Ole-Johan Dahl的信息已完成,但您会错过Ada Lovelace 的出生日期和月份以及她的死亡年份。自然,您只有Guido van Rossum的出生信息。最重要的是,您只记录了Barry 叔叔的名字。

    您将创建一个可以包装此信息的类。首先从 JSON 文件中读取信息:

    1. # programmers.py
    2. import json
    3. import pathlib
    4. programmers = json.loads(
    5.     pathlib.Path("programmers.json").read_text(encoding="utf-8")
    6. )

    您用于pathlib读取 JSON 文件并将json信息解析为 Python 字典列表。

    接下来,您将使用数据类来封装有关每个程序员的信息:

    1. # programmers.py
    2. from dataclasses import dataclass
    3. # ...
    4. @dataclass
    5. class Person:
    6.     name: str
    7.     life_span: tuple[intint]
    8.     @classmethod
    9.     def from_dict(cls, info):
    10.         return cls(
    11.             name=f"{info['name']['first']} {info['name']['last']}",
    12.             life_span=(info["birth"]["year"], info["death"]["year"]),
    13.         )

    每个Person都有一个name和一个life_span属性。此外,您还可以添加一个方便的构造函数,该构造函数Person可以根据 JSON 文件中的信息和结构进行初始化。

    您还将添加一个可以一次性初始化两个Person对象的函数:

    1. # programmers.py
    2. # ...
    3. def convert_pair(firstsecond):
    4.     return Person.from_dict(first), Person.from_dict(second)

    该convert_pair()函数两次使用.from_dict()构造函数将一对程序员从 JSON 结构转换为Person对象。

    是时候探索您的代码了,尤其是查看一些回溯。使用标志-i运行程序以打开 Python 的交互式 REPL,其中包含所有可用的变量、类和函数:

    1. $ python -i programmers.py
    2. >>> Person.from_dict(programmers[2])
    3. Person(name='Grace Hopper', life_span=(19061992))

    Grace 的信息是完整的,因此您可以将她封装到一个Person包含有关她的全名和寿命信息的对象中。

    要查看实际的新回溯,请尝试转换 Barry 叔叔:

    1. >>> programmers[0]
    2. {'name': {'first''Uncle Barry'}}
    3. >>> Person.from_dict(programmers[0])
    4. Traceback (most recent call last):
    5.   File "/home/realpython/programmers.py"line 17in from_dict
    6.     name=f"{info['name']['first']} {info['name']['last']}",
    7.                                     ~~~~~~~~~~~~^^^^^^^^
    8. KeyError: 'last'

    你得到一个KeyError因为last缺少。虽然您可能记得那last是name中的一个子字,但注释会立即为您指出这一点。

    同样,回想一下关于 Ada 的生命周期信息是不完整的。你不能为她创建一个Person对象:

    1. >>> programmers[1]
    2. {
    3.     'name': {'first''Ada''last''Lovelace'},
    4.     'birth': {'year'1815},
    5.     'death': {'month'11'day'27}
    6. }
    7. >>> Person.from_dict(programmers[1])
    8. Traceback (most recent call last):
    9.   File "/home/realpython/programmers.py"line 18in from_dict
    10.     life_span=(info["birth"]["year"], info["death"]["year"]),
    11.                                       ~~~~~~~~~~~~~^^^^^^^^
    12. KeyError: 'year'

    你得到了另一个KeyError,这次是因为year失踪了。在这种情况下,回溯比前面的例子更有用。您有两个year子字段,一个 forbirth和一个 for death。回溯注释立即显示您错过了死亡年份。

    Guido怎么样了?你只有关于他出生的信息:

    1. >>> programmers[4]
    2. {
    3.     'name': {'first''Guido''last''Van Rossum'},
    4.     'birth': {'year'1956'month'1'day'31},
    5.     'death': None
    6. }
    7. >>> Person.from_dict(programmers[4])
    8. Traceback (most recent call last):
    9.   File "/home/realpython/programmers.py"line 18in from_dict
    10.     life_span=(info["birth"]["year"], info["death"]["year"]),
    11.                                       ~~~~~~~~~~~~~^^^^^^^^
    12. TypeError: 'NoneType' object is not subscriptable

    在这种情况下,TypeError出现了。您之前可能已经看到过这些'NoneType'类型的错误。众所周知,它们很难调试,因为不清楚哪个对象是出乎意料的None。但是,从注释中,您会看到info["death"]在此示例中是None。

    在最后一个示例中,您将探索嵌套函数调用会发生什么。请记住,convert_pair()调用Person.from_dict()两次。现在,尝试将 Ada 和 Ole-Johan 配对:

    1. >>> convert_pair(programmers[3], programmers[1])
    2. Traceback (most recent call last):
    3.   File "/home/realpython/programmers.py"line 24in convert_pair
    4.     return Person.from_dict(first), Person.from_dict(second)
    5.                                     ^^^^^^^^^^^^^^^^^^^^^^^^
    6.   File "/home/realpython/programmers.py"line 18in from_dict
    7.     life_span=(info["birth"]["year"], info["death"]["year"]),
    8.                                       ~~~~~~~~~~~~~^^^^^^^^
    9. KeyError: 'year'

    尝试封装 Ada 引发与KeyError之前相同的情况。但是,请注意来自内部的回溯convert_pair()。因为该函数调用两次.from_dict(),所以通常需要一些努力才能确定在处理first或second时是否引发了错误。在最新版本的 Python 中,您会立即看到问题是由second引起的.

    这些回溯使 Python 3.11 中的调试比早期版本更容易。您可以在 Python 3.11 预览教程Even Better Error Messages(https://realpython.com/python311-error-messages/)中查看更多示例、有关如何实现回溯的更多信息以及可以在调试中使用的其他工具。有关更多技术细节,请查看PEP 657(https://peps.python.org/pep-0657/)。

    带注释的回溯将有助于提高 Python 开发人员的工作效率。

    推荐书单

    《Pandas1.x实例精解》

    本书详细阐述了与Pandas相关的基本解决方案,主要包括Pandas基础,DataFrame基本操作,创建和保留DataFrame,开始数据分析,探索性数据分析,选择数据子集,过滤行,对齐索引,分组以进行聚合、过滤和转换,将数据重组为规整形式,组合Pandas对象,时间序列分析,使用Matplotlib、Pandas和Seaborn进行可视化,调试和测试等内容。此外,本书还提供了相应的示例、代码,以帮助读者进一步理解相关方案的实现过程。 本书适合作为高等院校计算机及相关专业的教材和教学参考书,也可作为相关开发人员的自学用书和参考手册。

    链接:https://u.jd.com/UKjx4et

    精彩回顾

    《Pandas1.x实例精解》新书抢先看!

    【第1篇】利用Pandas操作DataFrame的列与行

    【第2篇】Pandas如何对DataFrame排序和统计

    【第3篇】Pandas如何使用DataFrame方法链

    【第4篇】Pandas如何比较缺失值以及转置方向?

    【第5篇】DataFrame如何玩转多样性数据

    【第6篇】如何进行探索性数据分析?

    【第7篇】使用Pandas处理分类数据

    【第8篇】使用Pandas处理连续数据

    【第9篇】使用Pandas比较连续值和连续列

    【第10篇】如何比较分类值以及使用Pandas分析库

    长按关注《Python学研大本营》

    长按二维码,加入Python读者群

    扫码关注《Python学研大本营》,加入读者群,分享更多精彩

  • 相关阅读:
    Maven-基本概念
    一文详细拆解Agent工作原理
    基于Huffman码实现的编码译码系统
    知识运维概述
    C语言学习之路(基础篇)—— 内存管理
    AutoSAR EcuM系列03- Flex EcuM的状态管理
    C#窗体弹出方式总结
    Golang并发控制的三种方案
    模块化与单片化优缺点解析:为什么单片链仍是 DeFi 协议的最好选择?
    SpringCloud微服务(七)——Bus服务消息总线
  • 原文地址:https://blog.csdn.net/weixin_39915649/article/details/127944974