有些功能即使是经验丰富的开发者也会被难住。
我也曾被它们绊倒,花数小时挠头苦思,最终才学会如何正确应对。
所以,不浪费时间,让我们来探索 Python 中最易误解的功能,它们为何棘手,以及你如何能最终掌握它们。
1. 可变默认参数
问题:如果你曾写过一个带有默认列表或字典参数的函数,你可能会注意到一些奇怪的现象。它会在函数调用之间“记住”值!
def add_item(item, items=[]):
items.append(item)
return items
print(add_item("apple")) # ['apple']
print(add_item("banana")) # ['apple', 'banana']
等等,这是怎么回事?
为什么
apple
还在?items
不应该重置为[]
吗?
为何令人困惑:
默认值并不是每次函数被调用时都重新创建的。它是在函数定义时创建一次。
如何掌握它:使用None
作为默认值,并在函数内部初始化列表。
def add_item(item, items=None):
if items is None:
items = []
items.append(item)
return items
print(add_item("apple")) # ['apple']
print(add_item("banana")) # ['banana']
2. is
与 ==
的困境
问题:你可能认为is
和==
可以互换使用。它们不是。
a = [1, 2, 3]
b = [1, 2, 3]
print(a == b) # True
print(a is b) # False
为何令人困惑:==
检查值是否相同,而is
检查它们是否是内存中的同一个对象。
如何掌握它:仅在进行身份比较(例如None
、单例)时使用is
,而进行值比较时坚持使用==
。
if a is None:
print("这是检查身份!")
if a == b:
print("这是检查值相等!")
3. 神秘的*args
和**kwargs
问题:这两个看起来像是 Python 版的象形文字。那些星号到底是什么意思?
def func(*args, **kwargs):
print(args)
print(kwargs)
像这样调用它:
func(1, 2, 3, name="Alice", age=25)
# args -> (1, 2, 3)
# kwargs -> {'name': 'Alice', 'age': 25}
为何令人困惑:一开始不清楚如何有效地使用它们。
如何掌握它:在 Python 中,*args
和 **kwargs
是用于函数定义中的特殊语法,主要用于处理不确定数量的参数。它们分别用于位置参数和关键字参数。
-
*args
用于将可变数量的位置参数传递给函数。它将所有的位置参数打包成一个元组,可以在函数内部使用它像操作元组一样处理参数。 -
**kwargs
用于将可变数量的关键字参数传递给函数。它将所有的关键字参数打包成一个字典。
def greet(*args, **kwargs):
for name in args:
print(f"Hello, {name}!")
for key, value in kwargs.items():
print(f"{key} = {value}")
greet("Alice", "Bob", language="Python", level="Intermediate")
4. 迭代器的特性
问题:可以多次遍历同一个迭代器。
it = iter([1, 2, 3])
print(list(it)) # 输出 [1, 2, 3]
print(list(it)) # 输出 []
如何掌握它:Python 中的迭代器不能多次遍历。迭代器是一次性对象,遍历一次后便耗尽。如果需要多次遍历相同的数据,可以使用支持多次遍历的可迭代对象(如列表、元组等),或者创建新的迭代器。
lst = [1, 2, 3]
for x in lst:
print(x) # 遍历一次
for x in lst:
print(x) # 再次遍历,依然有效
为什么迭代器不能多次遍历?
迭代器是惰性求值的,每次调用 next() 时会生成或返回下一个值,且没有“重置”功能。一旦遍历完所有元素,内部状态已经耗尽,再次遍历会直接触发 StopIteration 异常。
5. 列表推导式的古怪之处
问题:列表推导式很简洁,但它们很快就会变得难以阅读。
nums = [1, 2, 3, 4, 5]
squares = [x ** 2 for x in nums if x % 2 == 0]
为何令人困惑:添加条件或嵌套循环会使它们更难阅读。
如何掌握它:保持它们简单。当事情变得复杂时,将逻辑分解为单独的行或使用常规循环。
# 简单的列表推导式
nums = [1, 2, 3, 4, 5]
even_squares = [x ** 2 for x in nums if x % 2 == 0]
# 对于更复杂的逻辑,坚持使用循环
result = []
for x in nums:
if x % 2 == 0:
result.append(x ** 2)
6. 全局关键字的谜团
问题:人们以为函数内的变量默认是全局的,但并非如此。
x = 10
def modify():
x = x + 1 # 错误!
modify()
为何令人困惑:Python 假设你想创建一个新的局部变量,除非你明确声明否则。
如何掌握它:如果你确实需要修改全局变量,请使用global
(但尽可能避免使用全局变量)。
x = 10
def modify():
global x
x = x + 1
modify()
print(x) # 11
本文由mdnice多平台发布