Python 3.3 如何改进代码中的异常处理

探索异常处理和其他未被充分利用但仍然有用的 Python 功能。
42 位读者喜欢这篇文章。
Coding on a computer

这是关于 Python 3.x 版本中首次出现的功能系列文章的第四篇。Python 3.3 于 2012 年首次发布,即使它已经发布很长时间了,但它引入的许多功能仍然未被充分利用,而且非常酷。这里有其中三个功能。

yield from

yield 关键字使 Python 更加强大。不出所料,每个人都开始使用它来创建一个完整的迭代器生态系统。itertools 模块和 more-itertools PyPI 包只是两个例子。

有时,一个新的生成器会想要使用一个现有的生成器。作为一个简单的(如果有些牵强的)例子,想象一下你想枚举所有自然数对。

一种方法是按照 pair 的和,pair 的第一个元素 的顺序生成所有 pair。使用 yield from 实现这一点是很自然的。

yield from <x> 关键字是以下代码的简写:

for item in x:
    yield item
import itertools

def pairs():
    for n in itertools.count():
        yield from ((i, n-i) for i in range(n+1))
list(itertools.islice(pairs(), 6))
    [(0, 0), (0, 1), (1, 0), (0, 2), (1, 1), (2, 0)]

隐式命名空间包

想象一家名为 Parasol 的虚构公司,该公司生产很多东西。其大部分内部软件都是用 Python 编写的。虽然 Parasol 已经开源了部分代码,但其中一些代码过于专有或专业,不适合开源。

该公司使用内部 DevPI 服务器来管理内部软件包。Parasol 的每位 Python 程序员都在 PyPI 上找到一个未使用的名称是没有意义的,因此所有内部软件包都称为 parasol.<业务部门>.<项目>。为了遵守最佳实践,开发人员希望包名称反映该命名系统。

这很重要!如果软件包 parasol.accounting.numeric_tricks 安装了一个名为 numeric_tricks 的顶级模块,这意味着任何依赖于此软件包的人都将无法使用名为 numeric_tricks 的 PyPI 软件包,无论它多么巧妙。

然而,这给开发人员留下了一个难题:哪个软件包拥有 parasol/__init__.py 文件?从 Python 3.3 开始,最好的解决方案是将 parasol,以及可能的 parasol.accounting,设为 命名空间包,它们没有 __init__.py 文件。

抑制异常上下文

有时,在从异常中恢复的过程中发生异常是一个问题,并且拥有上下文来跟踪它是有用的。但是,有时情况并非如此:异常已被处理,并且新情况是不同的错误条件。

例如,想象一下,在字典中查找键失败后,如果无法分析该键,则希望使用 ValueError() 失败

import time

def expensive_analysis(data):
    time.sleep(10)
    if data[0:1] == ">":
        return data[1:]
    return None

此函数需要很长时间,因此当您使用它时,您希望缓存结果

cache = {}

def last_letter_analyzed(data):
    try:
        analyzed = cache[data]
    except KeyError:
        analyzed = expensive_analysis(data)
        if analyzed is None:
            raise ValueError("invalid data", data)
        cached[data] = analyzed
    return analyzed[-1]

不幸的是,当发生缓存未命中时,回溯看起来很糟糕

last_letter_analyzed("stuff")
    ---------------------------------------------------------------------------

    KeyError                                  Traceback (most recent call last)

    <ipython-input-16-a525ae35267b> in last_letter_analyzed(data)
          4     try:
    ----> 5         analyzed = cache[data]
          6     except KeyError:


    KeyError: 'stuff'

在处理上述异常期间,又发生了一个异常

    ValueError                                Traceback (most recent call last)

    <ipython-input-17-40dab921f9a9> in <module>
    ----> 1 last_letter_analyzed("stuff")
    

    <ipython-input-16-a525ae35267b> in last_letter_analyzed(data)
          7         analyzed = expensive_analysis(data)
          8         if analyzed is None:
    ----> 9             raise ValueError("invalid data", data)
         10         cached[data] = analyzed
         11     return analyzed[-1]


    ValueError: ('invalid data', 'stuff')

如果您使用 raise ... from None,您可以获得更易读的回溯

def last_letter_analyzed(data):
    try:
        analyzed = cache[data]
    except KeyError:
        analyzed = expensive_analysis(data)
        if analyzed is None:
            raise ValueError("invalid data", data) from None
        cached[data] = analyzed
    return analyzed[-1]
last_letter_analyzed("stuff")
    ---------------------------------------------------------------------------

    ValueError                                Traceback (most recent call last)

    <ipython-input-21-40dab921f9a9> in <module>
    ----> 1 last_letter_analyzed("stuff")
    

    <ipython-input-20-5691e33edfbc> in last_letter_analyzed(data)
          5         analyzed = expensive_analysis(data)
          6         if analyzed is None:
    ----> 7             raise ValueError("invalid data", data) from None
          8         cached[data] = analyzed
          9     return analyzed[-1]


    ValueError: ('invalid data', 'stuff')

欢迎来到 2012 年

虽然 Python 3.3 几乎在十年前发布,但它的许多功能仍然很酷——而且未被充分利用。如果您还没有这样做,请将它们添加到您的工具包中。

接下来阅读什么
标签
Moshe sitting down, head slightly to the side. His t-shirt has Guardians of the Galaxy silhoutes against a background of sound visualization bars.
自 1998 年以来,Moshe 一直参与 Linux 社区,在 Linux “安装聚会”中提供帮助。自 1999 年以来,他一直从事 Python 编程,并为核心 Python 解释器做出了贡献。Moshe 在 DevOps/SRE 这些术语出现之前就一直是 DevOps/SRE,非常关心软件可靠性、构建可重现性等问题。

评论已关闭。

© . All rights reserved.