Python编程陷阱(五)

陷阱16:不要使用in运算符来判断一个字符串是否包含另一个字符串

  • 字符串是Python中的一种基本的数据类型,它可以表示文本或其他符号序列。
  • 有时候,我们需要判断一个字符串是否包含另一个字符串,比如判断一个网址是否包含某个域名,或者判断一个单词是否包含某个字母。
  • 但是,如果我们使用in运算符来判断一个字符串是否包含另一个字符串,就可能导致一些意想不到的结果,甚至引发错误。

错误的代码

# 定义一个字符串,表示一个网址
url = "https://www.bing.com/search?q=python"

# 使用in运算符来判断字符串是否包含"bing",期望得到 True
print("bing" in url) # True

# 使用in运算符来判断字符串是否包含"google",期望得到 False
print("google" in url) # False

# 使用in运算符来判断字符串是否包含"python",期望得到 True
print("python" in url) # True

# 使用in运算符来判断字符串是否包含"py",期望得到 True
print("py" in url) # True

为什么会出错呢?

  • 因为使用in运算符来判断一个字符串是否包含另一个字符串,会返回True,如果这个字符串是另一个字符串的子串,也就是说,它在另一个字符串中连续出现,而不管它是否是一个单独的单词或部分。
  • 这就导致了一些字符串,使用in运算符来判断,会返回True,即使它们并不是我们想要判断的内容,而是一些无关的字符,这就会影响我们的逻辑判断,比如判断一个网址是否包含某个域名,或者判断一个单词是否包含某个字母。
  • 例如,上面的代码中,如果我们使用in运算符来判断字符串是否包含"py",就会返回True,因为"py"是"python"的子串,而"python"是网址的一部分,但是这并不是我们想要的结果,因为"py"并不是一个单独的域名或单词,而是一个无关的字符。

正确的代码

# 定义一个字符串,表示一个网址
url = "https://www.bing.com/search?q=python"

# 使用split方法来将字符串按照"/"分割,得到一个列表,然后使用in运算符来判断列表是否包含"www.bing.com",期望得到 True
print("www.bing.com" in url.split("/")) # True

# 使用split方法来将字符串按照"/"分割,得到一个列表,然后使用in运算符来判断列表是否包含"www.google.com",期望得到 False
print("www.google.com" in url.split("/")) # False

# 使用split方法来将字符串按照"="分割,得到一个列表,然后使用in运算符来判断列表是否包含"python",期望得到 True
print("python" in url.split("=")) # True

# 使用split方法来将字符串按照"="分割,得到一个列表,然后使用in运算符来判断列表是否包含"py",期望得到 False
print("py" in url.split("=")) # False

陷阱17:不要使用is运算符来比较数字

  • 数字是Python中的一种基本的数据类型,它可以表示整数、小数或复数,比如13.142+3j
  • 有时候,我们需要比较两个数字是否相等,比如判断一个数是否是零,或者一个计算结果是否符合预期。
  • 但是,如果我们使用is运算符来比较数字,就可能导致一些意想不到的结果,甚至引发错误。

错误的代码

# 定义一个函数,用于判断一个数是否是零
def is_zero(x):
    return x is 0 # 使用is运算符来比较数字

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

# 调用函数,期望得到 False
print(is_zero(1)) # False

# 调用函数,期望得到 False
print(is_zero(0.0)) # False

为什么会出错呢?

  • 因为使用is运算符来比较数字,会返回True,如果这两个数字是同一个对象,也就是说,它们在内存中的地址是相同的,而不管它们的值是否相等。
  • 这就导致了一些数字,使用is运算符来比较,会返回False,即使它们的值是相等的,这就会影响我们的逻辑判断,比如判断一个数是否是零,或者一个计算结果是否符合预期。
  • 例如,上面的代码中,如果我们使用is运算符来判断0.0是否是零,就会返回False,因为0.0是一个浮点数,而0是一个整数,它们在内存中的地址是不同的,即使它们的值都是零。

正确的代码

# 定义一个函数,用于判断一个数是否是零
def is_zero(x):
    return x == 0 # 使用==运算符来比较数字

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

# 调用函数,期望得到 False
print(is_zero(1)) # False

# 调用函数,期望得到 True
print(is_zero(0.0)) # True

陷阱18:不要使用+=运算符来修改元组

  • 元组是Python中的一种数据结构,它可以存储任意类型的元素,并且可以用索引来访问元素,它的字面值用圆括号()来表示,比如(1, 2, 3)
  • 元组是不可变的,也就是说,一旦创建了一个元组对象,就不能再修改它的内容,比如增加或删除元素。
  • 有时候,我们需要拼接或修改一个元组,比如在循环中不断地添加新的元素。
  • 但是,如果我们使用+=运算符来修改元组,就可能导致一些意想不到的结果,甚至引发错误。

错误的代码

# 定义一个函数,用于将一个列表中的元素拼接成一个元组
def join_elements(lst):
    result = () # 定义一个空元组
    for x in lst:
        result += (x,) # 使用+=运算符来修改元组
    return result # 返回修改后的元组

# 调用函数,期望得到 (1, 2, 3, 4, 5, 6)
print(join_elements([1, 2, 3, 4, 5, 6])) # (1, 2, 3, 4, 5, 6)

# 调用函数,期望得到 ('a', 'b', 'c', 'd', 'e', 'f')
print(join_elements(['a', 'b', 'c', 'd', 'e', 'f'])) # ('a', 'b', 'c', 'd', 'e', 'f')

为什么会出错呢?

  • 因为使用+=运算符来修改元组,会创建一个新的元组对象,并且把旧的元组对象和新的元素拼接起来,然后赋值给原来的变量。
  • 这样就会导致大量的内存分配和复制,消耗时间和空间,降低性能。
  • 如果元组很长或者循环次数很多,这种操作就会非常低效,甚至可能导致内存溢出或超时错误。

正确的代码

# 定义一个函数,用于将一个列表中的元素拼接成一个元组
def join_elements(lst):
    result = [] # 定义一个空列表
    for x in lst:
        result.append(x) # 使用append方法来添加元素
    return tuple(result) # 使用tuple函数来转换成元组

# 调用函数,期望得到 (1, 2, 3, 4, 5, 6)
print(join_elements([1, 2, 3, 4, 5, 6])) # (1, 2, 3, 4, 5, 6)

# 调用函数,期望得到 ('a', 'b', 'c', 'd', 'e', 'f')
print(join_elements(['a', 'b', 'c', 'd', 'e', 'f'])) # ('a', 'b', 'c', 'd', 'e', 'f')

陷阱19:不要使用list.sort方法来对列表进行排序

  • 列表是Python中最常用的数据结构之一,它可以存储任意类型的元素,并且可以动态地增加或删除元素。
  • 有时候,我们需要对列表中的元素进行排序,比如按照字母顺序或数字大小来排序,就需要使用sorted函数或list.sort方法来对列表进行排序。
  • 但是,如果我们使用list.sort方法来对列表进行排序,就可能导致一些意想不到的结果,甚至引发错误。

错误的代码

# 定义一个列表,它的元素都是字符串
lst = ["apple", "banana", "cherry", "date", "elderberry"]

# 使用list.sort方法来对列表进行排序,期望得到 ["apple", "banana", "cherry", "date", "elderberry"]
print(lst.sort()) # None

为什么会出错呢?

  • 因为使用list.sort方法来对列表进行排序,会直接修改列表本身,而不是返回一个新的列表,这就意味着,如果我们打印或赋值这个方法的返回值,就会得到一个None值,而不是排序后的列表。
  • 这就导致了我们无法正确地显示或使用排序后的列表,而是得到一个无意义的值。

正确的代码

# 定义一个列表,它的元素都是字符串
lst = ["apple", "banana", "cherry", "date", "elderberry"]

# 使用sorted函数来对列表进行排序,返回一个新的列表,期望得到 ["apple", "banana", "cherry", "date", "elderberry"]
print(sorted(lst)) # ["apple", "banana", "cherry", "date", "elderberry"]

陷阱20:不要使用eval函数来执行字符串中的代码

  • 字符串是Python中的一种基本的数据类型,它可以表示文本或其他符号序列。
  • 有时候,我们需要执行字符串中的代码,比如从用户输入或文件中读取一些表达式或语句,就需要使用eval函数或exec函数来执行字符串中的代码。
  • 但是,如果我们使用eval函数来执行字符串中的代码,就可能导致一些安全性和可靠性的问题,甚至引发错误。

错误的代码

# 定义一个函数,用于计算字符串中的表达式的值
def calculate(expr):
    return eval(expr) # 使用eval函数来执行字符串中的代码

# 调用函数,期望得到 6
print(calculate("2 + 4")) # 6

# 调用函数,期望得到 8
print(calculate("2 * 4")) # 8

# 调用函数,期望得到 2
print(calculate("2 ** 4")) # 16

为什么会出错呢?

  • 因为使用eval函数来执行字符串中的代码,会执行任何有效的Python代码,而不管它是不是我们想要执行的,这就可能导致一些问题,比如:
    • 我们无法控制字符串中的代码的来源和内容,可能会执行一些恶意的或者错误的代码,比如删除文件、修改系统设置、调用未定义的变量等。
    • 我们无法限制字符串中的代码的类型和范围,可能会执行一些不合适的或者危险的代码,比如导入模块、定义函数、执行语句等。
    • 我们无法保证字符串中的代码的正确性和安全性,可能会引发一些异常或者错误,比如语法错误、类型错误、逻辑错误等。
  • 例如,上面的代码中,如果我们传入一个不是表达式的字符串,比如"2 ** 4",就会得到一个错误的结果,因为**运算符的优先级高于*运算符,所以它会先执行,导致返回16而不是2。

正确的代码

# 定义一个函数,用于计算字符串中的表达式的值
def calculate(expr):
    # 使用ast模块中的literal_eval函数来执行字符串中的代码,它只会执行字面值,而不会执行其他的代码
    import ast
    return ast.literal_eval(expr)

# 调用函数,期望得到 6
print(calculate("2 + 4")) # 6

# 调用函数,期望得到 8
print(calculate("2 * 4")) # 8

# 调用函数,期望得到 2
print(calculate("2 ** 4")) # 16

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为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、付费专栏及课程。

余额充值