Python 基础 —— Python程序员常犯的那些错误

本文探讨了Python编程中常见的几个陷阱,包括迭代时修改列表导致的错误、表达式作为函数默认参数的问题以及闭包环境中变量绑定的时机。通过具体示例展示了如何避免这些陷阱,并提供了简洁的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 迭代时修改一个列表

删除列表中的奇数

>>>numbers = [i for i in range(10)]
>>>numbers
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>>odd = lambda x: bool(x%2)
>>>for i in range(len(numbers)):
...    if odd(i):
...        del numbers[i]
IndexError: list assignment index out of range

迭代时,从一个列表(List)或数组中删除元素,这是一个总所周知的错误。尽管上述程序的错误十分明显,但在开发某些大型程序时,有时则并非那么故意而为之。

幸运的是,python包含大量简洁而优雅的编程范式,若使用得当,将大大简化代码。针对上例,一个优雅的范例是通过递推式列表(list comprehensions):

>>>evens = [i for i in numbers if not odd(i)]
>>>evens
[0, 2, 4, 8]

2. 滥用表达式作为函数参数的默认值

def foo(bar=[]):
	bar.append('baz')
	return bar
>>>foo()
['baz']
>>>foo()
['baz', 'baz']
>>>foo()
['baz', 'baz', 'baz']

这段代码的错误之处在于误以为:函数在没有指定形参时总是将形参设置为默认值,然而事实并非如此,对这段代码的调试以及如何使用PyCharm可参看之前的一篇文章<Python 基础——一张图告诉你PyCharm如何进行断点调试>。

正确的形式如下:

def foo(bar=None):
	if not bar:
		bar = []
		bar.append('baz')
	return bar
>>>foo()
['baz']
>>>foo()
['baz']
>>>foo()
['baz']

3. 不明白闭包环境变量的绑定时机

理解Python闭包与延迟绑定

闭包:把函数当做一个对象,因此可以作为某个函数的返回值。同时闭包必须满足下列三个条件:

  • 必须是一个嵌套的函数。
  • 闭包必须返回嵌套函数。
  • 嵌套函数必须引用一个外部的非全局的局部自由变量。
def create_multipliers():
	return [lambda x: i*x for i in range(5)]
				# 符合闭包的三个条件:存在嵌套函数且将嵌套函数返回,引用了一个非全局的局部自由变量 i;
>>>for multiplier in create_mupliiers(5):
...    print(multiplier(2))
...

期望输出的结果:

0
2
4
8

然而输出的结果是:

8
8
8
8
8

只是因为python的迟绑定——闭包中用到的环境变量(闭包所依赖的变量)只有在函数被调用时才会被赋值,在上述的代码中,任何时候,当返回的函数被调用时,Python会在该函数被调用时的作用域中查找i对应的值(此时循环已经结束,i被附上了最终的值4)

解决方案:

def multipliers():
	return [lambda x, i=i: i*x for i in range(5)]

>>>for multiplier in multipliers():
...    print(multiplier(2))
...
0
2
4
8

利用默认参数生成匿名函数,以实现我们想要的结果。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

五道口纳什

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

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

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

打赏作者

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

抵扣说明:

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

余额充值