鱼C论坛

 找回密码
 立即注册
查看: 2653|回复: 42

[技术交流] 你知道什么是防御性编程吗?

[复制链接]
发表于 2023-12-4 04:18:13 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 小甲鱼的二师兄 于 2023-12-4 04:22 编辑

最近圈子里总在传这个图:

微信图片_20231204040329.jpg

很多兄弟顿时悟了 —— 所谓 “防御性编程”,就是确保自己被裁掉之后,代码无人能维护的编程实践!

好家伙……



其实,正儿八经确实是有这个词汇的:

防御性编程(Defensive programming)是防御式设计的一种具体体现,它是为了保证,对程序的不可预见的使用,不会造成程序功能上的损坏。

它可以被看作是为了减少或消除墨菲定律效力的想法。防御式编程主要用于可能被滥用,恶作剧或无意地造成灾难性影响的程序上。

简单地说,防御性编程就像是为你的代码穿上了保护装备,让它在面对各种突发情况(比如错误的输入或者意外的行为)时,能够稳定地运行而不是崩溃。

opt_防御性编程.png

下面我将结合实例,给大家解释一下在实际开发中,如何进行防御性编程实践。

一个简单的例子是,你的代码需要一个非零的数字进行除法运算。

在防御性编程中,你要先检查这个数字确实是非零的,然后再进行除法:
def divide(x, y):
    if y == 0:
        print("错了:0 不能作除数。")
        return
    return x / y
如果 y 为零,我们打印出一个错误信息,并直接返回,避免了除零的错误。这就是防御性编程的一个简单例子。


另一个防御性编程的例子:使用断言。

断言(assert)是一种在代码中设置检查点的方式,这通常用于检查那些 “绝对不能出错” 的条件。

如果断言条件为假,那么程序就会在那里停止,并抛出一个 AssertionError 异常。

例如,我们有一个函数,用于计算一个人的年龄。这个函数接受两个参数:出生年份和当前年份。

在这里,我们可以假设当前年份应该大于或等于出生年份。我们可以使用断言来检查这个条件:
def calculate_age(birth_year, current_year):
    assert current_year >= birth_year, "当前年份不能小于出生年份~"
    return current_year - birth_year

在防御性编程中,我们通常需要处理可能出现的错误或异常,以防止程序在遇到问题时崩溃。

Python 中,我们可以使用 try/except 语句来捕获和处理异常。在 try 块中的代码可能会抛出异常,如果确实抛出了异常,那么就会立即跳到 except 块中的代码去处理这个异常。

例如,我们有一个函数,用于从网络上下载文件。假设在网络连接有问题的情况下,这个函数可能会抛出一个 NetworkError 异常。

我们可以使用 try/except 来捕获这个异常,并打印出一个错误信息:
def download_fishc(url):
    try:
        # 这里的代码可能会抛出 NetworkError
        do_some_network_operation(url)
    except NetworkError:
        print(f"下载失败!")
在上面的代码中,如果 do_some_network_operation(url) 这行代码抛出了 NetworkError 异常,那么程序就会立即跳到 except NetworkError: 这一行,然后执行 print(f"下载失败!") 这行代码。

这样,即使在网络连接有问题的情况下,我们的程序也不会崩溃,而是打印出一个错误信息,并继续执行后面的代码。


我们再来看看日志记录。

在防御性编程中,保留详细的日志是非常重要的,因为它可以帮助我们了解系统在运行时的状态,以及当问题出现时提供详细的上下文信息。

Python 中,我们可以使用 logging 模块来记录日志。

比如,我们可以记录一个函数被调用的时间,以及它的输入参数:
import logging

def calculate_age(birth_year, current_year):
    logging.info(f"calculate_age called with {birth_year}, {current_year}")
    return current_year - birth_year
这样,如果我们的程序在运行时出现了问题,我们就可以查看日志,了解问题出现时的具体情况。


最后是单元测试,单元测试是检查代码功能是否正常的一种方法,每一个单元测试都关注于程序的一个小部分功能。

写好单元测试可以帮助我们确认代码的质量,并在修改或者添加新特性时,保证现有功能的稳定性。这也是防御性编程的重要组成部分。

在 Python 中,我们可以使用内置的 unittest 模块来编写单元测试。

例如,我们有一个函数,用于计算两个数的和。

我们可以写一个单元测试来确认这个函数的功能是否正常:
import unittest

def add(x, y):
    return x + y

class TestAdd(unittest.TestCase):
    def test_add(self):
        result = add(1, 2)
        self.assertEqual(result, 3)

if __name__ == "__main__":
    unittest.main()
在上面的代码中,TestAdd 类是一个单元测试类,它继承自 unittest.TestCase 类。test_add 方法是一个测试方法,它调用了 add 函数,并检查了 add 函数的返回值是否为预期的值。

如果 add 函数的返回值不是预期的值,那么 self.assertEqual(result, 3) 这行代码就会抛出一个异常,表明这个测试失败了。如果所有的测试方法都没有抛出异常,那么我们就可以说我们的代码通过了所有的单元测试。

通过这种方式,我们可以为我们的代码编写多个单元测试,以检查代码的各个部分是否都能正常工作。

这是防御性编程的一个重要组成部分,也是保证代码质量的一种有效方法。


然而,重要的是要理解,防御性编程并不是要你在每个可能出错的地方都添加异常处理或者日志记录。

因为过度使用防御性编程可能会导致代码冗余,可读性差,且难以维护。

使用防御性编程不仅是为了防止错误,更是一种编程思想,目的是让代码更健壮,更易于维护。

最佳的做法是在编程时就考虑到可能出现的问题,而不是在问题出现后再去修复。


这也是为什么单元测试如此重要,通过单元测试,我们可以在代码还在开发阶段就发现并修复问题,而不是等到代码部署到生产环境后再去解决。

总的来说,防御性编程是一个包含了参数检查、断言、异常处理、日志记录和单元测试等多种策略的编程方法,目的是让代码更健壮,更易于维护。

在编程时,我们应该根据实际的需要,适度地使用这些策略。


想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-12-4 04:18:37 | 显示全部楼层
防御性编程是一种编程思想,旨在确保程序在面对各种异常情况时能够稳定运行而不崩溃。它是通过一系列的编程实践来减少或消除程序功能受损的可能性。

防御性编程的主要策略包括参数检查、断言、异常处理、日志记录和单元测试等。

1. 参数检查:在使用参数进行计算或操作之前,先进行必要的检查以确保参数满足预期条件。例如,在进行除法运算前,先检查除数是否为零,避免出现除零错误。

2. 断言:使用断言语句来检查那些“绝对不能出错”的条件,如果断言条件为假,则程序会立即停止并抛出一个 AssertionError 异常。断言可用于验证代码逻辑的正确性。

3. 异常处理:使用 try/except 语句来捕获和处理可能出现的异常。在 try 块中的代码可能会抛出异常,如果发生异常,则立即跳到 except 块中的代码来处理异常。异常处理使得程序可以在遇到问题时不崩溃,并能够采取适当的措施进行处理。

4. 日志记录:保留详细的日志是非常重要的,因为它可以帮助我们了解系统在运行时的状态,并提供详细的上下文信息。可以使用 logging 模块来记录日志,便于排查问题和分析程序的运行情况。

5. 单元测试:编写单元测试是一种验证代码功能是否正常的方法。每个单元测试关注程序的一个小部分功能,通过编写多个单元测试来检查代码的各个部分是否能正常工作。在 Python 中,可以使用 unittest 模块来编写单元测试。

防御性编程的目的是提高代码的健壮性和可维护性,避免出现意外的错误和异常。在编程时,我们应该根据实际需求适度地使用这些策略,并在开发阶段就考虑到可能出现的问题,而不是在问题出现后才进行修复。通过合理的防御性编程实践,可以确保代码质量并降低维护成本。

以上回复来自 -- ChatGPT(FishC官方接口),如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-12-4 08:40:12 | 显示全部楼层
自己写的代码,自己未必能看懂
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-12-4 09:42:06 | 显示全部楼层
eat蟒蛇 发表于 2023-12-4 08:40
自己写的代码,自己未必能看懂

是这样的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-12-4 22:46:07 From FishC Mobile | 显示全部楼层
一寸长,一寸强
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-12-4 22:46:15 From FishC Mobile | 显示全部楼层
有点高级没太理解
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-12-4 22:47:13 From FishC Mobile | 显示全部楼层
正儿八经
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-12-4 22:47:49 From FishC Mobile | 显示全部楼层
加油学习兄弟们。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-12-4 22:48:02 | 显示全部楼层
是要做好防御!!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-12-4 22:53:08 From FishC Mobile | 显示全部楼层
学到了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-12-4 22:57:29 | 显示全部楼层
还在学基础,这个不太清楚。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-12-4 22:57:45 From FishC Mobile | 显示全部楼层
我明白了,所谓“防御性编程”就是让对手看不懂自己写的代码。最主要是对一些意料之外的错误进行处理,不让程序崩溃
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

发表于 2023-12-4 23:05:50 From FishC Mobile | 显示全部楼层
高级
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-12-4 23:18:48 From FishC Mobile | 显示全部楼层
学到了学到了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-12-4 23:40:40 From FishC Mobile | 显示全部楼层
哈哈哈,学到了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-12-4 23:42:46 From FishC Mobile | 显示全部楼层
凡事留一手
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-12-4 23:47:13 From FishC Mobile | 显示全部楼层
不错
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-12-4 23:57:44 | 显示全部楼层
努力学习python!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-12-5 00:30:10 From FishC Mobile | 显示全部楼层
学到了,现在写Python在接收一些数字的输入时都习惯加个判断是否为数字
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-12-5 04:08:16 From FishC Mobile | 显示全部楼层
编程可以练习,高手可以养成
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-11-25 02:21

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表