有些功能即使是經(jīng)驗(yàn)豐富的開發(fā)者也會被難住。
我也曾被它們絆倒,花數(shù)小時(shí)撓頭苦思,最終才學(xué)會如何正確應(yīng)對。
所以,不浪費(fèi)時(shí)間,讓我們來探索 Python 中最易誤解的功能,它們?yōu)楹渭郑约澳闳绾文茏罱K掌握它們。
1. 可變默認(rèn)參數(shù)
問題:如果你曾寫過一個(gè)帶有默認(rèn)列表或字典參數(shù)的函數(shù),你可能會注意到一些奇怪的現(xiàn)象。它會在函數(shù)調(diào)用之間“記住”值!
def add_item(item, items=[]):
items.append(item)
return items
print(add_item("apple")) # ['apple']
print(add_item("banana")) # ['apple', 'banana']
等等,這是怎么回事?
為什么
apple
還在?items
不應(yīng)該重置為[]
嗎?
為何令人困惑:
默認(rèn)值并不是每次函數(shù)被調(diào)用時(shí)都重新創(chuàng)建的。它是在函數(shù)定義時(shí)創(chuàng)建一次。
如何掌握它:使用None
作為默認(rèn)值,并在函數(shù)內(nèi)部初始化列表。
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
與 ==
的困境
問題:你可能認(rèn)為is
和==
可以互換使用。它們不是。
a = [1, 2, 3]
b = [1, 2, 3]
print(a == b) # True
print(a is b) # False
為何令人困惑:==
檢查值是否相同,而is
檢查它們是否是內(nèi)存中的同一個(gè)對象。
如何掌握它:僅在進(jìn)行身份比較(例如None
、單例)時(shí)使用is
,而進(jìn)行值比較時(shí)堅(jiān)持使用==
。
if a is None:
print("這是檢查身份!")
if a == b:
print("這是檢查值相等!")
3. 神秘的*args
和**kwargs
問題:這兩個(gè)看起來像是 Python 版的象形文字。那些星號到底是什么意思?
def func(*args, **kwargs):
print(args)
print(kwargs)
像這樣調(diào)用它:
func(1, 2, 3, name="Alice", age=25)
# args -> (1, 2, 3)
# kwargs -> {'name': 'Alice', 'age': 25}
為何令人困惑:一開始不清楚如何有效地使用它們。
如何掌握它:在 Python 中,*args
和 **kwargs
是用于函數(shù)定義中的特殊語法,主要用于處理不確定數(shù)量的參數(shù)。它們分別用于位置參數(shù)和關(guān)鍵字參數(shù)。
-
*args
用于將可變數(shù)量的位置參數(shù)傳遞給函數(shù)。它將所有的位置參數(shù)打包成一個(gè)元組,可以在函數(shù)內(nèi)部使用它像操作元組一樣處理參數(shù)。 -
**kwargs
用于將可變數(shù)量的關(guān)鍵字參數(shù)傳遞給函數(shù)。它將所有的關(guān)鍵字參數(shù)打包成一個(gè)字典。
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. 迭代器的特性
問題:可以多次遍歷同一個(gè)迭代器。
it = iter([1, 2, 3])
print(list(it)) # 輸出 [1, 2, 3]
print(list(it)) # 輸出 []
如何掌握它:Python 中的迭代器不能多次遍歷。迭代器是一次性對象,遍歷一次后便耗盡。如果需要多次遍歷相同的數(shù)據(jù),可以使用支持多次遍歷的可迭代對象(如列表、元組等),或者創(chuàng)建新的迭代器。
lst = [1, 2, 3]
for x in lst:
print(x) # 遍歷一次
for x in lst:
print(x) # 再次遍歷,依然有效
為什么迭代器不能多次遍歷?
迭代器是惰性求值的,每次調(diào)用 next() 時(shí)會生成或返回下一個(gè)值,且沒有“重置”功能。一旦遍歷完所有元素,內(nèi)部狀態(tài)已經(jīng)耗盡,再次遍歷會直接觸發(fā) StopIteration 異常。
5. 列表推導(dǎo)式的古怪之處
問題:列表推導(dǎo)式很簡潔,但它們很快就會變得難以閱讀。
nums = [1, 2, 3, 4, 5]
squares = [x ** 2 for x in nums if x % 2 == 0]
為何令人困惑:添加條件或嵌套循環(huán)會使它們更難閱讀。
如何掌握它:保持它們簡單。當(dāng)事情變得復(fù)雜時(shí),將邏輯分解為單獨(dú)的行或使用常規(guī)循環(huán)。
# 簡單的列表推導(dǎo)式
nums = [1, 2, 3, 4, 5]
even_squares = [x ** 2 for x in nums if x % 2 == 0]
# 對于更復(fù)雜的邏輯,堅(jiān)持使用循環(huán)
result = []
for x in nums:
if x % 2 == 0:
result.append(x ** 2)
6. 全局關(guān)鍵字的謎團(tuán)
問題:人們以為函數(shù)內(nèi)的變量默認(rèn)是全局的,但并非如此。
x = 10
def modify():
x = x + 1 # 錯(cuò)誤!
modify()
為何令人困惑:Python 假設(shè)你想創(chuàng)建一個(gè)新的局部變量,除非你明確聲明否則。
如何掌握它:如果你確實(shí)需要修改全局變量,請使用global
(但盡可能避免使用全局變量)。
x = 10
def modify():
global x
x = x + 1
modify()
print(x) # 11
本文由mdnice多平臺發(fā)布