10 件你可能不知道會破壞 Python 腳本的事情

Python 以其簡單性和可靠性而聞名,但即使是最優秀的開發者也會遇到神秘的錯誤和意外的錯誤。有些陷阱是顯而易見的,但其他的則潛伏在陰影中,等待破壞你的腳本。如果你曾經對代碼中的某個問題感到困惑,那麼這些隱藏的 Python 殺手之一很可能是罪魁禍首。

這裡有 10 件你可能不知道會破壞你的 Python 腳本的事情——以及如何避免它們。

1. 可變的預設參數

問題:在函數定義中使用可變對象(如列表或字典)作為默認參數可能會導致意外行為。

# Bad practice
def add_item(item, items=[]):
    items.append(item)
    return items


print(add_item(1))  # [1]
print(add_item(2))  # [1, 2] – Wait, what?!

修正方法:始終使用不可變的默認值,如 None,並在函數內部初始化。

def add_item(item, items=None):
    if items is None:
        items = []
    items.append(item)
    return items

2. 混合環境中的不正確縮排

問題: 混合使用制表符和空格可能會導致難以發現的錯誤,特別是在協作項目時。

# Mixing spaces and tabs
if True:
	print("This will fail in some environments!")

修正方法: 使用一致的縮排風格 — 最好是空格。配置您的編輯器自動將制表符轉換為空格。

3. 在迭代時修改列表

問題: 在迴圈中更改列表可能會導致跳過元素和不可預測的行為。

numbers = [1, 2, 3, 4, 5]
for num in numbers:
    if num % 2 == 0:
        numbers.remove(num)  # Oops! Skips elements

修正方法:遍歷列表的副本或使用列表推導式。

numbers = [num for num in numbers if num % 2 != 0]

4. 使用 is 而不是 == 進行比較

問題: is 運算符檢查對象的身份,而不是相等性。

x = 256
y = 256
print(x is y)  # True (because of interning)


x = 300
y = 300
print(x is y)  # False!

修正方法: 使用 == 進行值比較,並且僅在必要時使用 is 進行身份檢查。

5. 預設字典鍵的意外行為

問題: 在常規字典中訪問缺失的鍵會引發 KeyError,而 defaultdict 會自動創建缺失的鍵,有時會導致微妙的錯誤。

from collections import defaultdict

d = defaultdict(list)
d["missing"].append(42)  # Key is created automatically!

修正方法: 當您需要安全查找時,使用 dict.get()

value = my_dict.get("missing", [])

6. 迴圈變數洩漏到全域範圍

問題:在 Python 2 中,循環變量會洩漏到循環外,導致意外的修改。

for i in range(5):
    pass
print(i)  # i is still accessible

修正方法: 使用函數範圍來封裝變量,或使用 Python 3,這已經修復。

7. 浮點數精度錯誤

問題: 浮點運算可能導致微小的不準確性。

print(0.1 + 0.2)  # 0.30000000000000004

修正方法: 當精確度至關重要時,使用 decimal 模組。

from decimal import Decimal
print(Decimal("0.1") + Decimal("0.2"))  # 0.3

8. 多執行緒中的競爭條件

問題:同時訪問共享資源的線程可能會導致不可預測的行為。

import threading

def increment(counter):
    for _ in range(1000):
        counter["count"] += 1

counter = {"count": 0}
threads = [threading.Thread(target=increment, args=(counter,)) for _ in range(10)]

for t in threads:
    t.start()
for t in threads:
    t.join()

print(counter["count"])  # Not 10000!

修正方法: 使用線程安全的結構,如 threading.Lock

9. 循環導入

問題:兩個模組互相導入可能會導致ImportError

# module_a.py
import module_b

# module_b.py
import module_a  # Circular import error!

解決方案: 通過使用本地導入或重構代碼來打破依賴關係。

10. 默默忽略例外

問題: 捕捉所有異常而不正確處理會使調試變得困難。

try:
    risky_function()
except Exception:
    pass  # Silent failure!

修正方法: 記錄例外並在可能的情況下處理特定的例外。

import logging

try:
    risky_function()
except ValueError as e:
    logging.error(f"Value error: {e}")

結論

Python 是一種強大的語言,但即使是經驗豐富的開發人員也可能會陷入這些陷阱。通過了解這些隱藏的陷阱,您可以編寫更可靠、可維護且無錯誤的 Python 代碼。