Python编程陷阱(三)

本文揭示了Python编程中三个常见陷阱:1)不应使用and/or运算符实现条件赋值,2)不要用try-except语句盲目忽略错误,3)避免直接用==比较浮点数,以防精度问题。正确的方法应使用条件表达式、指定异常类型和设置误差范围。
摘要由CSDN通过智能技术生成

陷阱8:不要使用andor运算符来实现条件赋值

  • andor运算符是Python中的逻辑运算符,它们可以用来连接两个布尔值,返回一个布尔值。
  • 有时候,我们需要根据一个条件,来给一个变量赋不同的值,比如根据一个数的正负,来给它取绝对值或相反数。
  • 但是,如果我们使用andor运算符来实现条件赋值,就可能导致一些意想不到的结果,甚至引发错误。

错误的代码

# 定义一个函数,用于根据一个数的正负,来给它取绝对值或相反数
def transform(number):
    return number > 0 and number or -number # 使用and和or运算符来实现条件赋值

# 调用函数,期望得到 5
print(transform(5)) # 5

# 调用函数,期望得到 -6
print(transform(-6)) # -6

# 调用函数,期望得到 0
print(transform(0)) # 0

为什么会出错呢?

  • 因为andor运算符并不是用来实现条件赋值的,它们的返回值并不一定是布尔值,而是根据短路求值的规则,返回第一个确定结果的值。
  • 短路求值的规则是这样的:
    • 对于and运算符,如果第一个值是False,那么就返回第一个值,否则返回第二个值。
    • 对于or运算符,如果第一个值是True,那么就返回第一个值,否则返回第二个值。
  • 这就导致了一些非零的数,使用andor运算符来实现条件赋值,会得到正确的结果,因为它们的布尔值都是True,所以会返回期望的值。
  • 但是,对于零,使用andor运算符来实现条件赋值,会得到错误的结果,因为它的布尔值是False,所以会返回错误的值。

正确的代码

# 定义一个函数,用于根据一个数的正负,来给它取绝对值或相反数
def transform(number):
    return number if number > 0 else -number # 使用条件表达式来实现条件赋值

# 调用函数,期望得到 5
print(transform(5)) # 5

# 调用函数,期望得到 -6
print(transform(-6)) # -6

# 调用函数,期望得到 0
print(transform(0)) # 0

陷阱9:不要使用try-except语句来忽略错误

  • try-except语句是Python中的一种异常处理机制,它可以让我们在遇到错误时,执行一些恢复或处理的操作,而不是让程序崩溃。
  • 有时候,我们可能觉得某些错误不重要,或者不想让用户看到错误信息,就会使用try-except语句来忽略错误,比如使用一个空的except子句。
  • 但是,如果我们使用try-except语句来忽略错误,就可能导致一些严重的问题,甚至引发错误。

错误的代码

# 定义一个函数,用于打开一个文件,并读取其中的内容
def read_file(filename):
    try:
        f = open(filename, "r") # 尝试打开文件
        content = f.read() # 读取文件内容
        f.close() # 关闭文件
        return content # 返回文件内容
    except: # 使用一个空的except子句来忽略错误
        pass

# 调用函数,期望得到 "Hello, world!"
print(read_file("hello.txt")) # Hello, world!

# 调用函数,期望得到 None
print(read_file("not_exist.txt")) # None

为什么会出错呢?

  • 因为使用一个空的except子句来忽略错误,会捕获所有的异常,不管它们是不是我们想要处理的,这就可能导致一些严重的问题,比如:
    • 我们无法区分不同类型的异常,无法针对不同的情况进行恰当的处理,比如文件不存在、文件无法打开、文件格式错误等。
    • 我们无法得到异常的详细信息,无法知道错误的原因和位置,无法进行调试和修复。
    • 我们无法抛出异常,让上层的代码或用户知道发生了什么,无法进行适当的反馈或处理。
  • 例如,上面的代码中,如果我们传入一个不存在的文件名,就会触发一个FileNotFoundError异常,但是我们使用了一个空的except子句来忽略错误,所以我们无法知道发生了什么,也无法告诉用户文件不存在,只是返回了一个None值,这就会让用户感到困惑和沮丧。

正确的代码

# 定义一个函数,用于打开一个文件,并读取其中的内容
def read_file(filename):
    try:
        f = open(filename, "r") # 尝试打开文件
        content = f.read() # 读取文件内容
        f.close() # 关闭文件
        return content # 返回文件内容
    except FileNotFoundError: # 指定要捕获的异常类型
        print("File not found: " + filename) # 打印异常信息
        return None # 返回None值

# 调用函数,期望得到 "Hello, world!"
print(read_file("hello.txt")) # Hello, world!

# 调用函数,期望得到 None
print(read_file("not_exist.txt")) # File not found: not_exist.txt
# None

陷阱10:不要使用==运算符来比较浮点数

  • 浮点数是Python中的一种数据类型,它可以表示小数或科学计数法的数值,比如3.141.23e-4
  • 浮点数是用二进制的方式来存储和计算的,这就意味着,一些十进制的小数,可能无法用二进制的方式精确地表示,而是会有一些舍入误差,比如0.1在二进制中就是一个无限循环的小数。
  • 有时候,我们需要比较两个浮点数是否相等,比如判断一个数是否是零,或者一个计算结果是否符合预期。
  • 但是,如果我们使用==运算符来比较浮点数,就可能导致一些意想不到的结果,甚至引发错误。

错误的代码

# 定义一个函数,用于计算一个数的平方根
def sqrt(x):
    # 使用牛顿法,不断迭代,直到找到一个近似的解
    guess = x / 2 # 初始猜测值
    while True:
        new_guess = (guess + x / guess) / 2 # 计算新的猜测值
        if new_guess == guess: # 使用==运算符来判断是否收敛
            break # 如果收敛,就跳出循环
        guess = new_guess # 如果没有收敛,就更新猜测值
    return guess # 返回近似的解

# 调用函数,期望得到 2
print(sqrt(4)) # 2.0

# 调用函数,期望得到 3
print(sqrt(9)) # 3.0

# 调用函数,期望得到 5
print(sqrt(25)) # 5.0

为什么会出错呢?

  • 因为使用==运算符来比较浮点数,会要求两个数完全相等,也就是没有任何的误差,这在计算机中是很难实现的,因为浮点数的表示和计算都可能有一些舍入误差,导致两个数在某些位上有微小的差异。
  • 这就导致了一些浮点数,使用==运算符来比较,会返回False,即使它们的值是非常接近的,这就会影响我们的逻辑判断,比如判断一个数是否是零,或者一个计算结果是否符合预期。
  • 例如,上面的代码中,如果我们传入一个不是完全平方数的数,比如2,就会发现,函数无法收敛,而是陷入了无限循环,因为new_guessguess永远不会完全相等,总会有一些微小的误差,导致==运算符返回False

正确的代码

# 定义一个函数,用于计算一个数的平方根
def sqrt(x):
    # 使用牛顿法,不断迭代,直到找到一个近似的解
    guess = x / 2 # 初始猜测值
    epsilon = 1e-6 # 定义一个误差范围
    while True:
        new_guess = (guess + x / guess) / 2 # 计算新的猜测值
        if abs(new_guess - guess) < epsilon: # 使用abs函数和误差范围来判断是否收敛
            break # 如果收敛,就跳出循环
        guess = new_guess # 如果没有收敛,就更新猜测值
    return guess # 返回近似的解

# 调用函数,期望得到 2
print(sqrt(4)) # 2.0

# 调用函数,期望得到 3
print(sqrt(9)) # 3.0

# 调用函数,期望得到 5
print(sqrt(25)) # 5.0

# 调用函数,期望得到 1.414213
print(sqrt(2)) # 1.414213562373095
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

K_n_i_g_h_t_1990

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值