没有人知道的有用的Python语法

2020-09-23 02:48:03

这将是一个关于Python3的深奥特性的故事,以及我是如何在过去的几个月里复兴它并将它带到聚光灯下的。

早在2003年的Yee-haw时代,Raymond Hettinger就给python-dev邮件列表写了一封电子邮件,分享了一个改进Python处理捕获的异常并替换为其他异常的方式的想法。目标是避免在报告第二个异常时丢失有关第一个异常的信息。向用户显示完整的信息将使调试变得更容易,如果您以前关注过我的工作,您就知道没有什么比这更让我喜欢的了。

通过对python-dev的多次讨论,这个想法得到了完善和完善。一年后,Python核心开发人员Ka-Ping Yee编写了一个全面的PEP,当时称为PEP344,后来更名为PEP3134。这一想法在那里得到了详细的阐述,并列出了所有未解决的问题、潜在的问题和解决方案。Guido接受了PEP,它是为臭名昭著的Python3.0实现的,将使用…。任何人都不会。很长一段时间。

如果有一件事我没有错过,那就是Python生态系统要等10年才能采用Python3,但最终还是发生了。现在,PyPI上几乎所有的包都支持Python3,找到一份编写Python3代码的工作不再是一件奢侈品。就在几天前,NumPy终于放弃了对Python2的支持。我们生活在好日子里。

当现代Python开发人员捕捉到异常并引发新的异常来替换它时,他们可以很高兴地看到两种回溯的完整信息。这对调试非常有帮助,对大家来说都是双赢。

PEP3134有一个有趣的细节被遗忘了:它与这样一个问题有关:“当一个异常被另一个替换时意味着什么?为什么有人要这么做呢?“。

这些可以大致分为两种情况,PEP3134为每种情况提供了解决方案。

“出现了异常,我们正在处理,处理过程中出了问题。”

“引发了一个异常,我们决定用一个对调用此代码的人更有意义的不同异常来替换它。也许新的异常会更有意义,因为我们提供了更有用的错误消息。或者,我们可能正在使用与问题域更相关的异常类,调用我们代码的任何人都可以使用为此故障模式量身定做的EXCEPT子句来包装调用。“。

第二个案子挺冗长的,不是吗?第一种情况被定义为默认情况也无济于事。第二个案例最终被搁置。大多数Python开发人员还没有学会如何告诉Python第二种情况是他们的代码中发生了什么,以及当Python告诉他们当前正在调试的代码中发生了什么时,如何倾听。这导致了一种第22条军规的情况,与最初减缓Python3采用的情况没有太大不同。

在我告诉你我做了什么打破了第22条军规之前,我会把你带进这个圈子,并向你展示如何在你的项目中使用这个特性。

我将向您展示此功能的两个方面:如何告诉Python您正在捕获异常以用更友好的异常替换它,以及如何理解Python何时告诉您正在调试的代码中正在发生这种情况。

对于第一部分,这里有一个来自MyPy代码库的很好的示例:

Try:self.connection,_=self.sock.Accept(),socket.timeout除外e:从e引发IPCException(';套接字超时';)。

看到末尾的从e开始的那一位了吗?这就是告诉Python的一点:我们引发的IPCException只是我们刚刚捕获的socket.timeout的一个更友好的版本。

当我们运行该代码并达到该异常时,回溯将如下所示:

Traceback(最近一次调用):file";foo.py";,行19,在self.connection中,_=self.sock.Accept()File";foo.py";行,在Accept Raise socket.timeout socket.timeout中,上述异常是以下异常的直接原因:traceback(最近一次调用):file";foo.py";行21,在提升IPC异常(';套接字超时';)中异常:套接字超时。

看到中间的消息了吗,上面的异常是下面异常的直接原因?这才是最重要的部分。这就是如何知道您有一个友好的异常包装案例。

如果您正在处理第一种情况,即其中有错误的异常处理程序,则两个回溯之间的消息将是:

我发现几乎没有人知道这个功能,这很令人难过,因为我认为它在调试时是一条有用的信息。我决定尽我的一份力,推动Python社区使用这种语法。

我编写了一个小脚本,它使用Python的ast模块来分析代码库,并查找没有使用和应该使用该语法的所有实例。启发式很简单:如果您在Exception中进行加薪,那么在99.9%的情况下,您包装的是一个异常。

我从该脚本中获取输出,并使用它向大量开源Python包打开PR。我修复的一些项目有:Setuptools、SciPy、Matplotlib、Pandas、PyTest、IPython、MyPy、Pygments和Sphinx。请查看我的GitHub历史记录,了解完整的列表。

然后,我向PyLint添加了一个规则,现在称为W0707:RAISE-MISSING-FROM。在PyLint团队发布下一个版本之后,世界上数千个使用PyLint的项目升级到该版本后,当他们在应该使用RAISE的地方没有使用RAISE时,他们都会收到一个错误。

希望在几年内,Python的这一特性将在Python社区中变得更加根深蒂固。

您是否维护一个已经放弃了对Python2支持的Python项目?从GitHub安装最新版本的PyLint。如果您希望保持系统Python的整洁,您可以在一个虚拟环境中执行此操作。运行以下命令以安装:

您将获得一个行列表,显示您应该在代码中的什么位置添加RAISE。如果您没有得到任何输出,那么您的代码是好的!

我是以色列的一名软件开发人员,专门研究Python编程语言。我写技术、编程、创业、Python,以及我脑海中浮现的任何其他想法。

我有时可以在Python和Django上做自由撰稿人的工作。我的专长是从头开始开发产品。