Python 防御性编程简介
介绍
现在是星期五下午,你的新版本已经发布几天了。这一周一开始,你感到自豪和如释重负,但随着时间的流逝,你的自豪感逐渐消退。发布这样一个没有错误的版本需要付出很多努力和奉献。事实上,在发布之日,你确信接下来的几周会很平静,因为用户没有其他需要或想要的东西。
当然,这太好了,难以置信,发布后不久,您的第一份错误报告就来了。第一份错误报告只是一些无关紧要的事情,新对话框中的一个小拼写错误。然后,又有几张小错误单子陆续进来,您很快就修复了它们并将它们推送到存储库。
然后事情发生了,这是每个开发人员最可怕的噩梦,你最珍视的系统部分报告了一个错误。你疯狂地查看代码,即使你记住了它。在这种情况下,代码分支怎么可能被执行?代码肯定在骗你。
几天后,你仍然不知道这是怎么发生的。你甚至无法在测试环境中重现该场景。如果你有更多关于故障的调试信息就好了……
真理会让你自由
如果您编写软件已有一段时间,您就会意识到这种情况。尽管您尽了最大努力,但还是再次交付了有问题的软件,这令人沮丧。别担心,这种情况会发生。
故事的这一部分,我将揭示一劳永逸地为您解决这个问题的妙招。不幸的是,我不能,而且我不认为这样的事情存在。
隐藏的事实是所有软件都有错误。然而,这并不意味着我们应该放弃,不追求完美。这只是意味着我们最好稍微改变一下对这一现实的看法。我们应该像计划缺陷一样编写软件。我们应该防御性地编写软件,即冷静地为不可避免的和毫无防备的错误设置陷阱。
防御性编程
描述这种风格的最佳术语是防御性编程。维基百科的描述并没有完全表达出我的想法,但它是一个很好的起点:
一种防御性设计,旨在确保软件在不可预见的使用情况下仍能继续运行。这个想法可以被视为减少或消除墨菲定律发挥作用的可能性。防御性编程技术尤其适用于软件可能被恶意或无意地滥用而造成灾难性后果的情况。
我真正谈论的是以下指导原则的组合:
- 每行代码都是一项责任
- 整理你的假设
- 可执行文档更佳
可执行文档这一术语有时用于描述doctests。“文学测试”这一术语用于描述这一概念。
这些准则对于确保我们能够保护代码和理智免受不可避免的错误的影响至关重要。请记住,我们是从不会编写无错误的代码的角度出发进行操作的。
我们需要牢记这些准则,以帮助我们快速找到错误。很多时候,找到错误是最困难的部分。所以,让我们优化查找,而不是完全阻止它们这一不可能完成的任务。
Python 工具
让我们深入了解一些可用于帮助遵循指南的工具。我们将使用Python作为我们的语言进行演示,但大多数语言都有非常相似的工具。
- 断言
- 日志记录
- 单元测试
假设我们有以下函数,它从用户那里获取值并将指定范围的数据规范化为 0 到 1 之间的某个值,以便以后的新小部件可以使用它。
def normalize_ranges(colname):
"""
Normalize given data range to values in [0 - 1]
Return dictionary new 'min' and 'max' keys in range [0 - 1]
"""
# 1-D numpy array of data we loaded application with
original_range = get_base_range(colname)
colspan = original_range['datamax'] - original_range['datamin']
# User filtered data from GUI
live_data = get_column_data(colname)
live_min = numpy.min(live_data)
live_max = numpy.max(live_data)
ratio = {}
try:
ratio['min'] = (live_min - original_range['datamin']) / colspan
ratio['max'] = (live_max - original_range['datamin']) / colspan
except ZeroDivisionError:
ratio['min'] = 0.0
ratio['max'] = 0.0
return ratio
现在,假设我们有get_column_data()函数返回的以下“列” :
age = numpy.array([10.0, 20.0, 30.0, 40.0, 50.0])
height = numpy.array([60.0, 66.0, 72.0, 63.0, 66.0])
让我们验证一下它确实将给定的范围变成0 - 1之间的某个值:
>>> normalize_ranges('age')
{'max': 1.0, 'min': 0.0}
好的,这是一个相当短的测试,但它似乎有效。我们传入一系列“实数”,并将其标准化为0 - 1空间中的某个值。
还记得上面提到的指导原则吗?让我们找出这个函数中存在的错误。我们在代码中隐含地做了哪些假设?
我可以看到几个假设:
- original_range仅包含正数
- 返回的比例介于 0.0 和 1.0 之间
仔细检查后,发现上述代码中存在相当多的假设。不幸的是,在浏览代码时,这些假设并不是立即显而易见的。如果我们能让这些假设更清楚就好了……要深入了解澄清假设的不同方法,请继续阅读以下指南:
断言以及 Python 防御性编程的缺点 日志记录以及 Python 防御性编程的缺点 单元测试以及 Python 防御性编程的缺点
结论
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~