Python 模塊與包

本章學習知識點

  • 模塊導入:import 模塊、from 模塊 import 函數、自定義模塊
  • 常用標準庫:
    • os/sys:系統操作(文件路徑、環境變量)
    • datetime:時間處理(日期轉換、計時)
    • json:JSON 數據解析與生成
    • collections:高級數據結構(defaultdict、deque、Counter)

模塊與包是 Python 代碼模塊化、可維護性的核心,能讓你實現「代碼複用、功能拆分、第三方集成」。本手冊聚焦 模塊導入機制、自定義模塊與包,並深入講解高頻實用的標準庫(os/sys/datetime/json/collections

一、模塊與包基礎

1.1 核心概念

  • 模塊(Module):一個 .py 文件就是一個模塊,包含變量、函數、類等代碼,可被其他文件導入使用(核心價值:代碼複用)。

  • 包(Package):包含:__init__.py文件的文件夾,用於組織多個相關模塊(核心價值:按功能拆分代碼,避免模塊名衝突)。

    • 注意:Python 3.3+ 支持「命名空間包」(無需 __init__.py),但推薦保留 __init__.py 用於初始化包、控制導入行為。

1.2 模塊導入機制

  • Python 導入模塊時,會按以下順序查找模塊文件:

    1. 當前執行腳本所在目錄(優先);
    2. 系統環境變量 PYTHONPATH 指定的目錄;
    3. Python 安裝目錄下的標準庫目錄;
    4. 第三方庫目錄(如 site-packages)。
  • 導入模塊的 4 種常用方式,需根據場景靈活選擇:

    • import 模塊名(導入整個模塊)

      • 語法:import 模塊名 [as 別名]

      • 特點:導入整個模塊,通過「模塊名。屬性」訪問模塊內的函數 / 變量 / 類,避免命名衝突。

      • 適用場景:模塊功能較多,需多次使用模塊內的不同屬性。

        # 示例1:導入標準庫模塊(無別名)
        import math
        print(math.pi)  # 訪問模塊變量 → 3.141592653589793
        print(math.sqrt(16))  # 調用模塊函數 → 4.0    計算平方根比如25返回就是5
        
        # 示例2:導入模塊並指定別名(簡化書寫)
        import datetime as dt
        current_time = dt.datetime.now()
        print(current_time)  # 輸出當前時間 → 2025-11-27 10:00:00.123456
        
    • from 模塊名 import 屬性(導入模塊指定屬性)

      • 語法:from 模塊名 import 函數/變量/類 [as 別名]

      • 特點:直接導入模塊內的指定屬性,可直接使用(無需加模塊名前綴),代碼更簡潔。

      • 適用場景:僅需使用模塊內的少數幾個屬性。

        # 示例1:導入模塊的單個屬性
        from math import pi, sqrt
        print(pi)  # 直接使用變量 → 3.141592653589793
        print(sqrt(25))  # 直接調用函數 → 5.0
        
        # 示例2:導入屬性並指定別名(避免命名衝突)
        from math import pow as power
        print(power(2, 3))  # 調用別名函數 → 8.0
        
        # 示例3:導入模塊的所有屬性(不推薦,易衝突)
        from math import *
        print(sin(pi/2))  # 直接使用所有屬性 → 1.0
        # 警告:若當前文件有同名函數/變量,會被覆蓋
        
    • from 包名 import 模塊(導入包內模塊)

      • 語法:from 包名 import 模塊名 [as 別名]from 包名.模塊名 import 屬性

      • 特點:按包的層級結構導入模塊,適合大型項目的代碼組織。

        # 假設項目結構如下:
        # my_project/
        #   main.py
        #   utils/  # 包
        #     __init__.py
        #     file_ops.py  # 模塊(含 read_file 函數)
        #     str_ops.py   # 模塊(含 format_str 函數)
        
        # 在 main.py 中導入包內模塊
        from utils import file_ops
        content = file_ops.read_file("test.txt")  # 包.模塊.函數
        
        # 直接導入包內模塊的屬性
        from utils.str_ops import format_str
        formatted = format_str("hello")  # 直接使用函數
        
        # 導入包內模塊並指定別名
        from utils import file_ops as fo
        content = fo.read_file("test.txt")
        
    • import 包名.模塊名(完整路徑導入)

      • 語法:import 包名.模塊名 [as 別名]

      • 特點:明確指定模塊的完整路徑,可讀性強,避免同名模塊衝突。

        # 延續上面的項目結構
        import utils.file_ops
        content = utils.file_ops.read_file("test.txt")
        
        # 完整路徑導入並指定別名
        import utils.str_ops as so
        formatted = so.format_str("hello")
        

1.3 自定義模塊

自定義模塊就是創建 .py 文件,編寫代碼後供其他文件導入,步驟如下:

  1. 創建模塊文件(my_module.py

    # my_module.py(自定義模塊)
    # 模塊變量
    MODULE_NAME = "我的自定義模塊"
    VERSION = "1.0"
    
    # 模塊函數
    def add(a, b):
        """兩數相加"""
        return a + b
    
    def multiply(a, b):
        """兩數相乘"""
        return a * b
    
    # 模塊類
    class Calculator:
        def subtract(self, a, b):
            """兩數相減"""
            return a - b
    
  2. 導入自定義模塊(在同一目錄下的 main.py

    # main.py
    # 方式1:導入整個模塊
    import my_module
    print(my_module.MODULE_NAME)  # 訪問變量 → 我的自定義模塊
    print(my_module.add(3, 5))  # 調用函數 → 8
    calc = my_module.Calculator()
    print(calc.subtract(10, 4))  # 調用類方法 → 6
    
    # 方式2:導入模塊指定屬性
    from my_module import multiply, Calculator
    print(multiply(4, 5))  # → 20
    calc2 = Calculator()
    print(calc2.subtract(20, 7))  # → 13
    
    # 方式3:導入模塊並指定別名
    import my_module as mm
    print(mm.VERSION)  # → 1.0
    
  3. 注意事項:

    • 模塊名遵循 PEP8 規範(小寫 + 下劃線,如 my_module),避免與標準庫 / 第三方庫模塊名衝突(如不要命名為 os.pyjson.py);

    • 若自定義模塊不在當前目錄,需將模塊所在目錄添加到 sys.path(見下文 sys 庫);

    • 模塊被導入時,其頂層代碼(如變量定義、函數定義、類定義)會被執行一次(可通過 if __name__ == "__main__": 控制僅在直接運行模塊時執行的代碼)。

      # 優化 my_module.py:添加主程序入口
      if __name__ == "__main__":
          # 僅當直接運行 my_module.py 時執行(導入時不執行)
          print("直接運行自定義模塊")
          print(add(2, 3))  # 測試函數
      

1.4 自定義包

自定義包用於組織多個相關模塊,步驟如下:

  1. 創建包結構

    # 項目結構
    my_project/
      main.py
      tools/  # 包名
        __init__.py  # 包初始化文件(可空,也可用於導入配置)
        math_ops.py  # 模塊1:數學運算
        str_ops.py   # 模塊2:字符串處理
    
  2. 編寫包內模塊代碼

    # tools/math_ops.py
    def calculate_sum(n):
        """計算1到n的和"""
        return sum(range(1, n+1))
    
    # tools/str_ops.py
    def reverse_str(s):
        """反轉字符串"""
        return s[::-1]
    
  3. (可選)優化 __init__.py(控制包導入行為)

    • __init__.py 可用於:1. 初始化包變量;2. 簡化導入路徑(通過 __all__ 指定默認導入的模塊 / 屬性)。

      # tools/__init__.py
      # 包變量
      PACKAGE_DESCRIPTION = "工具包:包含數學運算和字符串處理功能"
      
      # 指定 from tools import * 時導入的模塊(可選)
      __all__ = ["math_ops", "str_ops"]
      
      # 簡化導入:讓用户可直接 from tools import calculate_sum
      from .math_ops import calculate_sum
      from .str_ops import reverse_str
      
  4. 導入包並使用

    # main.py
    # 方式1:導入包內模塊
    from tools import math_ops, str_ops
    print(math_ops.calculate_sum(10))  # → 55
    print(str_ops.reverse_str("hello"))  # → olleh
    
    # 方式2:通過 __init__.py 簡化導入(直接導入屬性)
    from tools import calculate_sum, reverse_str
    print(calculate_sum(5))  # → 15
    print(reverse_str("python"))  # → nohtyp
    
    # 方式3:導入整個包
    import tools
    print(tools.PACKAGE_DESCRIPTION)  # 訪問包變量
    print(tools.calculate_sum(8))  # 調用簡化導入的函數
    

二、常用標準庫實戰

Python 標準庫是內置的「工具集」,無需安裝即可使用,以下是開發中最常用的 5 個標準庫,覆蓋系統操作、時間處理、數據解析、高級數據結構等核心場景。

模塊大類 子模塊 / 核心功能 核心用途 關鍵特性 / 適用場景
時間處理模塊 datetime 時間運算(增減)、時間字段修改、高精度時間獲取 比 time 更直觀,支持 timedelta 時間差計算
文件與目錄操作模塊 os 目錄增刪、路徑處理、系統環境獲取、文件屬性查看 跨系統路徑兼容,基礎文件 / 目錄管理
系統交互模塊 sys 獲取 Python 解釋器信息、命令行參數處理、程序退出控制 命令行工具開發、系統參數獲取
數據序列化模塊 json 跨語言數據序列化 / 反序列化,支持基礎數據類型 多語言交互、接口數據傳輸
數據結構擴展模塊 collections 提供高性能專用數據結構(Counter、defaultdict、OrderedDict、deque 等) 彌補內置數據結構不足,提升開發效率

2.1、sys 庫

sys 庫用於與 Python 解釋器本身交互,核心功能包括「命令行參數獲取、系統路徑配置、退出程序」等。

  • 核心功能與方法

    方法 / 屬性 功能描述 示例
    sys.argv 獲取命令行參數(列表,第一個元素是腳本名) 運行 python main.py 10 20sys.argv → ["main.py", "10", "20"]
    sys.path Python 模塊搜索路徑列表(可動態添加) print(sys.path) → [當前目錄, 標準庫目錄, ...]
    sys.version 獲取 Python 版本信息 print(sys.version) → 3.9.7 (default, ...)
    sys.platform 獲取操作系統平台 print(sys.platform) → linux/win32/darwin(Mac)
    sys.exit(code=0) 退出程序(code=0 表示正常退出,非 0 表示異常) sys.exit(1)(異常退出)
    sys.stdin 標準輸入流(如讀取用户輸入) line = sys.stdin.readline()
    sys.stdout 標準輸出流(如打印內容) sys.stdout.write("Hello")
  • 示例

    import sys
    
    # 1. 解析命令行參數(實現簡易計算器)
    print("命令行參數:", sys.argv)
    if len(sys.argv) != 4:
        print("用法:python main.py <操作符> <數字1> <數字2>")
        print("示例:python main.py add 10 20")
        sys.exit(1)  # 異常退出(非 0 狀態碼)
    
    op = sys.argv[1]
    num1 = float(sys.argv[2])
    num2 = float(sys.argv[3])
    
    if op == "add":
        print(f"{num1} + {num2} = {num1 + num2}")
    elif op == "sub":
        print(f"{num1} - {num2} = {num1 - num2}")
    elif op == "mul":
        print(f"{num1} × {num2} = {num1 * num2}")
    elif op == "div":
        if num2 == 0:
            print("錯誤:除數不能為 0")
            sys.exit(1)
        print(f"{num1} ÷ {num2} = {num1 / num2:.2f}")
    else:
        print("支持的操作符:add/sub/mul/div")
        sys.exit(1)
    
    ############ 寫法2 ############
    import sys
    print(sys.argv)
    
    if len(sys.argv) != 4 or len(sys.argv) >= 5:
        print("用法:python main.py <操作符[add,sub,mul]> <數字1> <數字2>")
        print("示例:python main.py add 10 20")
        sys.exit(1)  # 異常退出(非 0 狀態碼)
    
    # 如果不去掉第1個 控制枱四個參數 打印['絕對路徑/名稱.py', 'add', '10', '20']
    operator = sys.argv[1::]
    
    def args(*args):
        num1=float(args[1])
        num2=float(args[2])
        if args[0]=='add':
            print(num1+num2)
        elif args[0]=='sub':
            print(num1-num2)
        elif args[0]=='mul':
            print(num1*num2)
        else:
            print("請輸入正確的操作符")
            sys.exit(1)
    
    args(*operator)
        
    # 2. 動態添加模塊搜索路徑(導入非當前目錄的自定義模塊)
    # 假設自定義模塊在 /home/user/my_modules 目錄下
    custom_module_dir = "/home/user/my_modules"
    if custom_module_dir not in sys.path:
        sys.path.append(custom_module_dir)  # 添加到搜索路徑
        print(f"已添加模塊路徑:{custom_module_dir}")
    
    # 之後即可導入該目錄下的模塊
    # import my_custom_module
    

2.1、os 庫

os 庫提供與操作系統交互的接口,核心用於「文件路徑操作、目錄管理、系統命令執行」,是文件處理的基礎。

  • 核心功能與方法

    方法 / 屬性 功能描述 示例
    os.getcwd() 獲取當前工作目錄 print(os.getcwd()) → /home/user/project
    os.chdir(path) 切換工作目錄 os.chdir("/home/user")
    os.listdir(path=".") 列出目錄下的所有文件 / 子目錄 os.listdir("./tools") → ["math_ops.py", ...]
    os.mkdir(path) 創建單個目錄(父目錄必須存在) os.mkdir("./data")
    os.makedirs(path) 遞歸創建目錄(父目錄不存在則自動創建) os.makedirs("./data/logs")
    os.remove(path) 刪除文件 os.remove("./test.txt")
    os.rmdir(path) 刪除空目錄 os.rmdir("./data")
    os.removedirs(path) 遞歸刪除空目錄 os.removedirs("./data/logs")
    os.rename(old, new) 重命名文件 / 目錄 os.rename("old.txt", "new.txt")
    os.path.exists(path) 判斷路徑是否存在(文件 / 目錄) os.path.exists("./tools") → True
    os.path.isfile(path) 判斷是否為文件 os.path.isfile("./main.py") → True
    os.path.isdir(path) 判斷是否為目錄 os.path.isdir("./tools") → True
    os.path.join(p1, p2, ...) 拼接路徑(自動適配系統分隔符) os.path.join("./data", "logs") → ./data/logs
    os.path.abspath(path) 獲取路徑的絕對路徑 os.path.abspath("./main.py") → /home/user/project/main.py
    os.path.splitext(path) 分割文件名和擴展名 os.path.splitext("test.txt") → ("test", ".txt")
  • 示例

    import os
    
    # 1. 路徑拼接(跨平台兼容)
    # 錯誤方式:直接用 + 拼接(Windows 用 \,Linux 用 /,易出錯)
    # bad_path = "./data" + "/logs"
    # 正確方式:用 os.path.join
    data_dir = os.path.join(os.getcwd(), "data")
    log_dir = os.path.join(data_dir, "logs")
    print("日誌目錄路徑:", log_dir)
    
    # 2. 目錄創建(不存在則創建)
    if not os.path.exists(log_dir):
        os.makedirs(log_dir)  # 遞歸創建
        print(f"目錄 {log_dir} 創建成功")
    else:
        print(f"目錄 {log_dir} 已存在")
    
    # 3. 遍歷目錄下的所有 .py 文件
    project_dir = os.getcwd()
    py_files = []
    for root, dirs, files in os.walk(project_dir):  # 遞歸遍歷目錄
        for file in files:
            if file.endswith(".py"):  # 篩選 .py 文件
                file_path = os.path.join(root, file)
                py_files.append(file_path)
    
    print(f"\n項目中所有 .py 文件(共 {len(py_files)} 個):")
    for path in py_files:
        print(path)
    
    # 4. 文件重命名(批量修改後綴)        
    current_path=os.path.dirname(os.path.abspath(__file__))
    file_list=["file1.txt","file2.txt","file3.txt"]
    for file in file_list:
        get_check_file_path=os.path.join(current_path,"bac") # 多用os.getpwd()看一下當前路徑
        name,type=os.path.splitext(file)      # "filex",".txt"
        newe_nam=name+".md"   # 改為 .md 後綴
        os.rename(os.path.join(get_check_file_path,file), os.path.join(get_check_file_path,newe_nam))
        print(f"舊文件:{file} --> 新文件:{os.path.join(get_check_file_path,newe_nam)}")
    
  • 獲取「腳本文件所在目錄」

    # 當前在【D:\docker\miscellaneous\python\模塊與包\模塊使用】下使用os.getcwd(),查看只到  D:\docker\miscellaneous\python 怎麼獲取到 D:\docker\miscellaneous\python\模塊與包\模塊使用
    # 
    # 獲取當前腳本文件的絕對路徑
    script_path = os.path.abspath(__file__)
    # 獲取腳本文件所在的目錄(即模塊使用目錄)
    script_dir = os.path.dirname(script_path)
    
    os.chdir(os.path.dirname(os.path.abspath(__file__)))
    print(os.getcwd())
    

2.3、datetime 庫

datetime 庫是 Python 處理時間的核心庫,支持「日期轉換、時間計算、格式化輸出」,比 time 庫更強大、易用。

  • 核心功能與方法

    類 / 方法 功能描述 示例
    datetime.datetime.now() 獲取當前本地時間(datetime 對象) dt.now() → 2025-11-27 10:30:00.123456
    datetime.date.today() 獲取當前日期(date 對象) date.today() → 2025-11-27
    datetime.datetime.strptime(date_str, format) 字符串轉 datetime 對象 strptime("2025-11-27", "%Y-%m-%d") → 2025-11-27 00:00:00
    datetime.datetime.strftime(format) datetime 對象轉字符串 dt.strftime("%Y-%m-%d %H:%M:%S") → "2025-11-27 10:30:00"
    datetime.timedelta(days/hours/minutes/seconds) 時間間隔對象(用於時間計算) timedelta(days=1) → 1 天
    dt1 - dt2 兩個 datetime 對象相減,返回 timedelta dt.now() - dt(2025,1,1) → 330 天...
    dt + timedelta datetime 對象加時間間隔,返回新 datetime dt.now() + timedelta(hours=3) → 3 小時後
    timestamp 將時間轉換為時間戳
    fromtimestamp 將時間戳轉換為時間
    • 時間格式化符號(常用):
      • %Y:4 位年份(如 2025)
      • %m:2 位月份(01-12)
      • %d:2 位日期(01-31)
      • %H:24 小時制(00-23)
      • %M:分鐘(00-59)
      • %S:秒(00-59)
      • %w:星期(0-6,0 是週日)
  • 示例

    from datetime import datetime, date, timedelta
    
    # 1. 獲取當前時間與日期
    current_dt = datetime.now()  # 含時分秒毫秒
    current_date = date.today()  # 僅日期
    print("當前完整時間:", current_dt)
    print("當前日期:", current_date)
    print("當前小時:", current_dt.hour)
    print("當前星期:", current_dt.weekday())  # 0=週一,6=週日
    
    # 2. 時間格式化(datetime → 字符串)
    formatted_dt = current_dt.strftime("%Y-%m-%d %H:%M:%S")
    print("格式化時間:", formatted_dt)  # → 2025-11-27 10:35:22
    
    # 3. 字符串轉時間(字符串 → datetime)
    time_str = "2025-12-01 12:00:00"
    parsed_dt = datetime.strptime(time_str, "%Y-%m-%d %H:%M:%S")
    print("解析後的時間:", parsed_dt)
    print("解析後的年份:", parsed_dt.year)
    
    # 4. 時間計算(加減時間間隔)
    # 3天后的時間
    three_days_later = current_dt + timedelta(days=3)
    print("3天后:", three_days_later.strftime("%Y-%m-%d"))
    
    # 2小時30分鐘前的時間
    two_hours_ago = current_dt - timedelta(hours=2, minutes=30)
    print("2小時30分鐘前:", two_hours_ago.strftime("%H:%M:%S"))
    
    # 計算兩個日期的差值
    date1 = date(2025, 1, 1)
    date2 = date(2025, 11, 27)
    delta = date2 - date1
    print("兩個日期相差:", delta.days, "天")
    
    # 5. 函數執行計時(統計代碼運行時間)
    def test_func():
        sum(range(1, 1000000))
    
    start_time = datetime.now()
    test_func()
    end_time = datetime.now()
    duration = (end_time - start_time).total_seconds()  # 耗時(秒)
    print(f"函數執行耗時:{duration:.4f} 秒")
    
    # 時間戳轉換
    print(dt.datetime.now().timestamp())  # 1764573102.217211
    print(dt.datetime.fromtimestamp(1764573102.217211))
    

2.4、json 庫

JSON 是前後端交互、數據存儲的常用格式,json 庫支持「JSON 字符串 → Python 對象」(解析)和「Python 對象 → JSON 字符串」(生成)。

  • 核心映射關係(Python ↔ JSON)

    Python 類型 JSON 類型
    dict object(對象)
    list/tuple array(數組)
    str string(字符串)
    int/float number(數字)
    True true
    False false
    None null
  • 核心方法

    功能描述 方法 示例
    Python 對象 → JSON 字符串(indent 格式化輸出) json.dumps(obj, ensure_ascii=False, indent=2) dumps({"name":"小明"}, ensure_ascii=False) → '{"name":"小明"}'
    JSON 字符串 → Python 對象 json.loads(json_str) loads('{"name":"小明"}') → {"name":"小明"}
    Python 對象 → JSON 文件(fp 是文件對象) json.dump(obj, fp, ensure_ascii=False, indent=2) dump(data, open("data.json", "w"))
    JSON 文件 → Python 對象 json.load(fp) load(open("data.json", "r")) → data
  • 實戰

    import json
    
    # 1. Python 對象 → JSON 字符串(生成)
    data = {
        "name": "小明",
        "age": 20,
        "gender": "男",
        "is_student": True,
        "hobbies": ["籃球", "音樂", "旅行"],
        "address": {
            "city": "上海",
            "district": "浦東新區"
        },
        "score": None
    }
    
    # dumps 生成 JSON 字符串(ensure_ascii=False 保留中文,indent=2 格式化)
    json_str = json.dumps(data, ensure_ascii=False, indent=2)
    print("JSON 字符串:")
    print(json_str)
    
    # 2. JSON 字符串 → Python 對象(解析)
    parsed_data = json.loads(json_str)
    print("\n解析後的 Python 對象:")
    print(type(parsed_data))  # → <class 'dict'>
    print("姓名:", parsed_data["name"])
    print("愛好:", parsed_data["hobbies"][0])
    
    # 3. Python 對象 → JSON 文件(寫入文件)
    current_dir= os.path.dirname(os.path.abspath(__file__))
    with open(f"{os.path.join(current_dir, 'data.json')}", 'w', encoding='utf-8') as f:
        json.dump(data, f, ensure_ascii=False, indent=2)
    print(f"數據已保存到 {current_dir}")
    
    # 4. JSON 文件 → Python 對象(讀取文件)
    with open(f"{os.path.join(current_dir, 'data.json')}", 'r', encoding='utf-8') as f:
        loaded_data = json.load(f)
    print("\n從文件讀取的 JSON 數據:")
    print(loaded_data["address"]["city"])  # → 上海
    
    # 5. 處理複雜 JSON 數據(嵌套解析)
    complex_json = '''
    {
      "code": 200,
      "message": "success",
      "data": {
        "total": 2,
        "users": [
          {"id": 1, "name": "小紅", "age": 18},
          {"id": 2, "name": "小李", "age": 19}
        ]
      }
    }
    '''
    result = json.loads(complex_json)
    if result["code"] == 200:
        users = result["data"]["users"]
        print("\n用户列表:")
        for user in users:
            print(f"ID:{user['id']},姓名:{user['name']}")
    

2.5、collections

collections 庫提供了比內置數據結構(list/dict/set/tuple)更強大的擴展類型,解決了內置結構的諸多痛點(如字典缺省值、有序字典、計數統計等)。

  • 核心類型與用法

    1. defaultdict:帶默認值的字典

      • 痛點:內置 dict 訪問不存在的鍵會報錯,需用 get(key, default) 或判斷鍵是否存在;

      • 解決方案:defaultdict 初始化時指定「默認值類型 / 函數」,訪問不存在的鍵時自動生成默認值。

        from collections import defaultdict
        
        # 示例1:默認值為列表(用於分組)
        student_scores = [
            ("小明", "數學", 90),
            ("小明", "英語", 85),
            ("小紅", "數學", 95),
            ("小紅", "英語", 88)
        ]
        
        # defaultdict(list):不存在的鍵默認生成空列表
        score_dict = defaultdict(list)
        for name, subject, score in student_scores:
            score_dict[name].append((subject, score))  # 無需判斷 name 是否存在
        
        print("學生成績分組:")
        for name, scores in score_dict.items():
            print(f"{name}:{scores}")
        # 輸出:
        # 小明:[('數學', 90), ('英語', 85)]
        # 小紅:[('數學', 95), ('英語', 88)]
        
        # 示例2:默認值為整數(用於計數)
        word_count = defaultdict(int)
        words = ["apple", "banana", "apple", "cherry", "banana", "apple"]
        for word in words:
            # defaultdict(<class 'int'>, {'apple': 3, 'banana': 2, 'cherry': 1})
            word_count[word] += 1  # 不存在的鍵默認值為 0,直接累加
        
        print("\n單詞計數:", dict(word_count))  # → {'apple':3, 'banana':2, 'cherry':1}
        
  1. Counter:計數統計工具

    • 功能:專門用於「可迭代對象的元素計數」,比 defaultdict(int) 更簡潔、功能更強。

      from collections import Counter
      
      # 示例1:字符串字符計數
      s = "abracadabra"
      char_count = Counter(s)
      print("字符計數:", char_count)  # → Counter({'a':5, 'b':2, 'r':2, 'c':1, 'd':1})
      
      # 示例2:列表元素計數
      nums = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
      num_count = Counter(nums)
      print("數字計數:", num_count)  # → Counter({4:4, 3:3, 2:2, 1:1})
      
      # 示例3:獲取Top N元素(常用場景)
      top2 = num_count.most_common(2)  # 獲取出現次數最多的2個元素
      print("出現次數最多的2個數字:", top2)  # → [(4,4), (3,3)]
      
      # 示例4:計數器運算(交集/並集/差集)
      c1 = Counter([1,2,3,3])
      c2 = Counter([3,4,4,5])
      print("交集(共同元素的最小計數):", c1 & c2)  # → Counter({3:1})
      print("並集(所有元素的最大計數):", c1 | c2)  # → Counter({1:1,2:1,3:2,4:2,5:1})
      print("差集(c1有但c2沒有的元素):", c1 - c2)  # → Counter({1:1,2:1,3:1})
      
  2. deque:雙端隊列(高效增刪)

    • 痛點:內置 list 是動態數組,頭部增刪元素(insert(0)/pop(0))效率低(時間複雜度 O (n));

    • 解決方案:deque 是雙端隊列,頭部 / 尾部增刪元素效率極高(時間複雜度 O (1)),支持最大長度限制。

      from collections import deque
      
      # 示例1:基礎操作(頭部/尾部增刪)
      dq = deque([1, 2, 3])
      dq.append(4)  # 尾部添加 → deque([1,2,3,4])
      dq.appendleft(0)  # 頭部添加 → deque([0,1,2,3,4])
      dq.pop()  # 尾部刪除 → 4 → deque([0,1,2,3])
      dq.popleft()  # 頭部刪除 → 0 → deque([1,2,3])
      print("雙端隊列:", dq)
      
      # 示例2:最大長度限制(超出則自動刪除另一端元素)
      limited_dq = deque(maxlen=3)  # 最大長度3
      limited_dq.append(1)
      limited_dq.append(2)
      limited_dq.append(3)
      print("限制長度3的隊列:", limited_dq)  # → deque([1,2,3], maxlen=3)
      limited_dq.append(4)  # 超出長度,刪除頭部元素1
      print("添加4後:", limited_dq)  # → deque([2,3,4], maxlen=3)
      
      # 示例3:高效滑動窗口(常用場景)
      def sliding_window(nums, k):
          dq = deque()
          result = []
          for i, num in enumerate(nums):
              # 移除窗口外的元素(索引小於 i-k+1 的元素)
              while dq and dq[0] < i - k + 1:
                  dq.popleft()
              # 移除隊列中比當前元素小的元素(維護隊列遞減)
              while dq and nums[dq[-1]] < num:
                  dq.pop()
              dq.append(i)
              # 窗口大小達到 k 後,記錄最大值(隊列頭部)
              if i >= k - 1:
                  result.append(nums[dq[0]])
          return result
      
      nums = [1, 3, -1, -3, 5, 3, 6, 7]
      k = 3
      print("滑動窗口最大值:", sliding_window(nums, k))  # → [3,3,5,5,6,7]
      

三、綜合實戰

  • 日誌收集工具(os+datetime+json+collections)

    """
    功能:收集指定目錄下的日誌文件,解析錯誤日誌,統計錯誤類型並保存為 JSON 報告
    技術點:os 目錄遍歷、datetime 時間處理、json 數據生成、collections.Counter 計數
    """
    import os
    import json
    from datetime import datetime
    from collections import Counter
    
    def collect_error_logs(log_dir, output_file):
        # 1. 驗證日誌目錄是否存在
        if not os.path.isdir(log_dir):
            print(f"錯誤:目錄 {log_dir} 不存在")
            return
    
        # 2. 遍歷目錄下的所有 .log 文件
        error_records = []
        error_types = []
        for root, dirs, files in os.walk(log_dir):
            for file in files:
                if file.endswith(".log"):
                    log_file_path = os.path.join(root, file)
                    print(f"正在解析日誌文件:{log_file_path}")
    
                    # 3. 讀取日誌文件,篩選錯誤日誌(假設錯誤日誌以 ERROR: 開頭)
                    with open(log_file_path, "r", encoding="utf-8", errors="ignore") as f:
                        for line_num, line in enumerate(f, start=1):
                            line = line.strip()
                            if line.startswith("ERROR:"):
                                # 解析日誌時間(假設日誌格式:[2025-11-27 10:00:00] ERROR: ...)
                                if "[" in line and "]" in line:
                                    time_str = line.split("]")[0].strip("[")
                                    try:
                                        log_time = datetime.strptime(time_str, "%Y-%m-%d %H:%M:%S")
                                    except ValueError:
                                        log_time = None
                                else:
                                    log_time = None
    
                                # 記錄錯誤詳情
                                error_info = {
                                    "file": log_file_path,
                                    "line": line_num,
                                    "time": log_time.strftime("%Y-%m-%d %H:%M:%S") if log_time else "未知",
                                    "message": line
                                }
                                error_records.append(error_info)
    
                                # 提取錯誤類型(假設錯誤格式:ERROR: 類型: 描述)
                                if ": " in line[6:]:  # 跳過 "ERROR:" 前綴
                                    error_type = line[6:].split(": ")[0].strip()
                                    error_types.append(error_type)
    
        # 4. 統計錯誤類型
        error_count = Counter(error_types) if error_types else {}
    
        # 5. 生成報告數據
        report = {
            "report_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
            "log_dir": log_dir,
            "total_error_count": len(error_records),
            "error_type_statistics": dict(error_count),
            "error_details": error_records
        }
    
        # 6. 保存報告為 JSON 文件
        with open(output_file, "w", encoding="utf-8") as f:
            json.dump(report, f, ensure_ascii=False, indent=2)
    
        print(f"\n日誌收集完成!共發現 {len(error_records)} 條錯誤,報告已保存至:{output_file}")
    
    # 執行日誌收集
    if __name__ == "__main__":
        # 日誌目錄(可替換為實際目錄)
        target_log_dir = "./logs"
        # 輸出報告文件
        output_json = "error_report.json"
        # 執行收集
        collect_error_logs(target_log_dir, output_json)
    

四、易錯點總結

  1. 模塊命名衝突:自定義模塊名與標準庫(如 os.pyjson.py)或第三方庫同名,導致導入錯誤(解決方案:修改自定義模塊名);
  2. 路徑拼接錯誤:直接用 + 拼接路徑(如 "./data" + "/logs"),不兼容 Windows/Linux 系統(解決方案:用 os.path.join);
  3. JSON 中文亂碼:json.dump 時未指定 ensure_ascii=False,導致中文被轉義為 Unicode 編碼(解決方案:添加 ensure_ascii=False);
  4. datetime 格式化錯誤:混用格式化符號(如 %Y 寫成 %y%H 寫成 %h),導致解析 / 格式化失敗(解決方案:熟記常用格式化符號);
  5. dequelist 混淆:用 list 進行頭部高頻增刪操作,導致效率低下(解決方案:改用 collections.deque);
  6. 模塊導入路徑問題:自定義模塊不在當前目錄,且未添加到 sys.path,導致導入失敗(解決方案:sys.path.append(模塊目錄));
  7. defaultdict 默認值類型錯誤:初始化時指定錯誤的默認值類型(如需要列表卻指定 int),導致後續操作報錯(解決方案:根據場景選擇默認值類型)。

通過本手冊的學習,你已經掌握了 Python 模塊與包的核心用法,以及高頻標準庫的實戰技巧。這些知識點是 Python 開發的基礎,後續學習 Web 框架(如 Flask/Django)、數據分析(如 Pandas)、自動化測試等內容時,都會基於模塊與包的思想擴展。建議多結合實際項目練習(如工具腳本開發、數據處理),加深對模塊複用、代碼組織的理解,提高開發效率!