標籤: 編碼技巧

  • 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 代碼。