最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

入門初學者短期內(nèi)快速掌握Python的經(jīng)典全面教程(專家學習筆記)

 更新時間:2026年01月02日 10:45:29   作者:張彥峰ZYF  
本文從工程實踐視角出發(fā),對Python基礎知識進行了系統(tǒng)梳理與總結(jié),內(nèi)容涵蓋運行環(huán)境、基礎語法、控制流、函數(shù)、字符串處理以及列表、字典、集合等常用數(shù)據(jù)結(jié)構,并結(jié)合可運行示例,幫助讀者建立清晰、連貫的語言認知體系,適合初學者入門,為后續(xù)學習與實際應用打下穩(wěn)定基礎

本博客將自己初步學習Python過程中的階段性整理與沉淀。難免存在理解不夠嚴謹或表述不夠完善之處,歡迎各位讀者在評論區(qū)留言指正、交流探討,這對我和后續(xù)讀者都會非常有價值。

同時說明一下:從當前基礎學習和實踐驗證來看,當前準備的這些分享內(nèi)容,確實是可以在一天半的時間內(nèi)就可以快速學習完成并可以理解的,希望對我們彼此都有所收獲?。。?/p>

一、快速了解 Python 和 環(huán)境準備

(一)Python 快速介紹

Python 是一種 簡潔、強大、易讀 的編程語言,廣泛應用于 Web 開發(fā)、數(shù)據(jù)分析、人工智能、自動化運維領域。它由 Guido van Rossum 在 1991 年設計,因其清晰的語法和強大的生態(tài)系統(tǒng),迅速成為全球最受歡迎的編程語言之一。

2017 年底Stack Overflow 發(fā)布的數(shù)據(jù)顯示,Python 已經(jīng)超越 JavaScript 成為了該平臺上提問流量最多的編程語言。

(二)Jupyter Notebook:從夢想到行業(yè)標配

Jupyter Notebook 的誕生源于創(chuàng)始人 Fernando Pérez一個大膽的想法:打造一個能整合 Julia(Ju)、Python(Py)和 R(ter) 這三種科學計算語言的通用計算平臺。但目前Jupyter 早已超越最初的設想,成為一個支持幾乎所有編程語言的多功能計算環(huán)境。

2017 年起,北美頂尖高校紛紛全面擁抱 Jupyter Notebook:

  • 學術界:斯坦福的 CS231N《計算機視覺與神經(jīng)網(wǎng)絡》 課程2017 年便完全遷移到 Jupyter Notebook、UC Berkeley 的 《數(shù)據(jù)科學基礎》 課程也在同年改用 Jupyter 作為唯一的作業(yè)平臺。
  • 工業(yè)界: Facebook盡管大型后端開發(fā)仍依賴傳統(tǒng) IDE,但幾乎所有 內(nèi)部分析、機器學習訓練和數(shù)據(jù)探索 都基于 Jupyter Notebook 運行。同時 Google 的 AI Research 部門 Google Brain,也是清一色地全部使用 Jupyter Notebook(改進定制版,叫 Google Colab)。

(三)Mac 上安裝 Python 和 Jupyter Notebook 的步驟

步驟命令說明
1. 安裝 Homebrew/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"Mac 的包管理工具(如果未安裝)
2. 安裝 Python 3brew install python安裝最新的 Python 3
3. 驗證 Python 版本python3 --version確保安裝成功,顯示 Python 3.x.x
4. 安裝 Jupyter Notebookpip3 install jupyter通過 pip3 安裝 Jupyter
5. 檢查 Jupyter 是否可用jupyter --version確保 Jupyter 已正確安裝
6. 啟動 Jupyter Notebookjupyter notebook打開 Jupyter Notebook,瀏覽器自動打開

這樣,我們就可以在 Mac 上使用 Jupyter Notebook 進行 Python 開發(fā)了!

備注:

  • 如果你不習慣也可以直接idea,畢竟這么多年習慣了java開發(fā),我就是兩個都安裝了,無所謂!
  • 如果不想安裝也可以在線使用:Jupyter 官方在線工具

二、Python 基礎:變量、數(shù)據(jù)類型與輸入輸出

Python 以其 簡潔、易讀 的語法受到歡迎,而理解變量、數(shù)據(jù)類型和輸入輸出是學習 Python 的第一步。這部分內(nèi)容構成了 Python 編程的基石。這部分代碼我寫的時候都是直接在idea中,網(wǎng)絡版本有時很慢。Jupyter 官方在線工具

(一)變量:數(shù)據(jù)的存儲與引用

變量(Variable是用于存儲數(shù)據(jù)的容器,在 Python 中變量不需聲明類型,直接賦值即可創(chuàng)建。

1. 變量的定義與賦值

x = 10  # 整數(shù)變量
name = "Alice"  # 字符串變量
pi = 3.14159  # 浮點數(shù)變量
is_python_fun = True  # 布爾變量

Python 是動態(tài)類型語言,變量的類型是根據(jù)賦值內(nèi)容自動推導的。

2. 變量命名規(guī)則

  • 變量名必須 以字母或下劃線(_)開頭,不能以數(shù)字開頭。

  • 變量名只能包含 字母、數(shù)字和下劃線,不能包含空格或特殊符號。

  • 變量名區(qū)分大小寫(ageAge 是不同的變量)。

  • 推薦使用 小寫字母+下劃線snake_case)風格,如 user_name,符合 Python 代碼規(guī)范(PEP 8)。

示例:正確與錯誤的變量命名

valid_name = "OK"  # 正確
_valid_123 = 42  # 正確
2nd_value = "wrong"  # ? 錯誤:不能以數(shù)字開頭
user-name = "error"  # ? 錯誤:不能包含 `-`

(二)數(shù)據(jù)類型(Data Types)

Python 具有豐富的數(shù)據(jù)類型,主要包括:

數(shù)據(jù)類型示例說明
整數(shù)(int)x = 42存儲整數(shù),如 10, -5, 1000
浮點數(shù)(float)pi = 3.14存儲小數(shù),如 3.1415, -0.5
字符串(str)name = "ZYF"存儲文本,如 "hello"
布爾值(bool)is_valid = True只有 TrueFalse
列表(list)nums = [1, 2, 3]有序可變的集合
元組(tuple)colors = ('red', 'blue')有序不可變的集合
字典(dict)person = {"name": "Alice", "age": 25}鍵值對存儲
集合(set)unique_nums = {1, 2, 3}無序不重復元素集合

Python 提供 type() 函數(shù)來查看變量的數(shù)據(jù)類型:

x = 42
print(type(x))  # 輸出:<class 'int'>

Python 允許不同類型之間的轉(zhuǎn)換:

age = "25"  
age = int(age)  # 將字符串轉(zhuǎn)換為整數(shù)
pi = 3.14
pi_str = str(pi)  # 將浮點數(shù)轉(zhuǎn)換為字符串

(三)輸入與輸出(Input & Output)

1. 標準輸入(input)

input() 用于從用戶獲取輸入,所有輸入默認是 字符串類型

name = input("請輸入你的名字: ")
print("你好,", name)

如果需要數(shù)值類型,需要進行 類型轉(zhuǎn)換

age = int(input("請輸入你的年齡: "))  # 輸入默認是字符串,需要轉(zhuǎn)換成整數(shù)
print("你明年就", age + 1, "歲了!")

基本驗證:

2. 標準輸出(print)

print() 用于向控制臺輸出內(nèi)容:

name = "Alice"
age = 25
print("姓名:", name, "年齡:", age)  # 多個參數(shù)用逗號分隔

格式化輸出(推薦使用 f-string,Python 3.6+ 支持):

print(f"姓名: {name}, 年齡: {age}") # 推薦的寫法

? 小練習題

嘗試自己編寫代碼練習以下問題:

  1. 定義一個變量 temperature,存儲 36.6,并使用 print() 輸出 "體溫: 36.6 攝氏度"

  2. 編寫一個程序,提示用戶輸入姓名和年齡,并打印 "你好,XX!你今年 YY 歲"(其中 XXYY 由用戶輸入)。

Python 的變量、數(shù)據(jù)類型和輸入輸出構成了編程的基礎,熟練掌握這些概念后,就可以進行更復雜的邏輯編寫了!

三、控制流:讓代碼具備決策能力

在編程中,控制流 決定了代碼的執(zhí)行順序,使程序能夠做出決策(條件判斷),或重復執(zhí)行任務(循環(huán))。通過 布爾值、邏輯運算、if 語句、for 和 while 循環(huán),我們可以讓 Python 代碼變得更加智能和高效。這部分我會總結(jié)下這些關鍵概念,其是構建更具邏輯性程序的基礎。

(一)布爾值與邏輯判斷

在 Python 中,布爾值(Boolean) 是控制程序邏輯的基礎。它用于 條件判斷、循環(huán)控制和邏輯運算,讓代碼具備決策能力。

1. 布爾值(Boolean)

布爾值只有兩個取值:

True  # 代表 "真"
False  # 代表 "假"

布爾值本質(zhì)上是整數(shù)的特殊形式,其中:

True == 1  # 結(jié)果為 True
False == 0  # 結(jié)果為 True
布爾值的基本使用
is_python_fun = True
is_raining = False

print(is_python_fun)  # 輸出:True
print(type(is_python_fun))  # 輸出:<class 'bool'>

2. 比較運算符(Comparison Operators)

比較運算符用于比較兩個值,返回 TrueFalse。

運算符含義示例結(jié)果
==等于5 == 5True
!=不等于5 != 3True
>大于10 > 3True
<小于2 < 8True
>=大于等于5 >= 5True
<=小于等于3 <= 2False
代碼示例
a = 10
b = 5

print(a > b)   # True
print(a == b)  # False
print(a != b)  # True

3. 布爾運算符(Boolean Operators)

Python 提供了 andornot 三種邏輯運算符,用于組合多個布爾表達式。

運算符含義示例結(jié)果
and邏輯與(都為 True 時才為 TrueTrue and FalseFalse
or邏輯或(只要一個為 True 就是 TrueTrue or FalseTrue
not邏輯非(取反)not TrueFalse
3.1and邏輯與
x = 5
y = 10
print(x > 0 and y > 5)  # True,因為兩個條件都成立
print(x > 0 and y < 5)  # False,因第二個條件不成立
3.2or邏輯或
x = 5
y = 10
print(x > 0 or y < 5)  # True,只要有一個條件為 True 即可
print(x < 0 or y < 5)  # False,兩個條件都為 False
3.3not邏輯非
is_python_fun = True
print(not is_python_fun)  # False,因為取反了

4. 混合布爾運算(優(yōu)先級)

運算符的 優(yōu)先級 從高到低依次為:not(最高)、and、or(最低)

知道黃曉明的“鬧太套”英文梗,這里直接記成“鬧安套”就好了

print(True or False and False)  
# 等價于 True or (False and False) → True or False → True

print(not True or False)  
# 等價于 (not True) or False → False or False → False

5. 布爾值與其他數(shù)據(jù)類型的轉(zhuǎn)換

在 Python 中,所有數(shù)據(jù)類型 都可以轉(zhuǎn)換為布爾值:

  • 以下情況視為 False

    • 0(整數(shù) 0)

    • 0.0(浮點數(shù) 0)

    • ""(空字符串)

    • [](空列表)

    • {}(空字典)

    • None(特殊值,表示“空”)

  • 其他情況均為 True。

5.1 使用bool()進行類型轉(zhuǎn)換
print(bool(0))       # False
print(bool(""))      # False
print(bool([]))      # False
print(bool(42))      # True
print(bool("hello")) # True
5.2 在if語句中使用
name = "Alice"

if name:  # 相當于 if bool(name) == True
    print("名字有效")  
else:
    print("名字為空")

輸出:

名字有效

? 小練習題

練習 1:布爾運算

判斷以下表達式的結(jié)果:

  • True and False or True

  • not (False or True)

  • (10 > 5) and (3 != 3)

練習 2:用戶輸入比較

讓用戶輸入兩個數(shù)字,比較它們的大小,并輸出 "第一個數(shù)字更大""第二個數(shù)字更大"。

# 提示:使用 input() 和 if 語句

布爾值和邏輯判斷是 條件判斷和循環(huán) 的基礎,熟練掌握它們后,代碼將更加智能化! ??

(二)?? 條件判斷(if語句)

在編程中,我們經(jīng)常需要根據(jù)不同條件來執(zhí)行不同的代碼。這就要用到 條件判斷語句(if statement)。Python 中使用 if、elifelse 關鍵字來實現(xiàn)條件分支。

1. 基本 if 語句

語法結(jié)構:

if 條件:
    語句塊

? 當“條件”為 True 時,語句塊才會被執(zhí)行。

示例:

age = 20

if age >= 18:
    print("你已經(jīng)成年了")

輸出:

你已經(jīng)成年了

2. if-else 結(jié)構(兩分支選擇)

用于處理“要么這樣,要么那樣”的情況。

語法結(jié)構:

if 條件:
    語句塊1
else:
    語句塊2

示例:

temperature = 15

if temperature > 20:
    print("北京天氣今天很暖和")
else:
    print("北京天氣今天有點冷")

輸出:

北京天氣今天有點冷

3. if-elif-else 結(jié)構(多分支選擇)

用于處理多個條件判斷的情況(相當于“多項選擇”)。

語法結(jié)構:

if 條件1:
    語句塊1
elif 條件2:
    語句塊2
elif 條件3:
    語句塊3
else:
    默認語句塊

示例:

score = 85

if score >= 90:
    print("優(yōu)秀")
elif score >= 80:
    print("良好")
elif score >= 60:
    print("及格")
else:
    print("不及格")

輸出:

良好

?? elif 是 "else if" 的縮寫。Python 中沒有 switch 語句,if-elif-else 是推薦的替代方案。

4. 嵌套 if 語句

嵌套 指的是在一個 if 塊內(nèi)部再寫 if 判斷??梢杂脕肀硎靖鼜碗s的邏輯結(jié)構。

示例:

age = 25
is_student = True

if age < 30:
    if is_student:
        print("你是年輕的學生")
    else:
        print("你是年輕的上班族")

輸出:

你是年輕的學生

?? 注意縮進層級,Python 是靠縮進來識別代碼塊的!

5. 條件表達式(三元運算符)

Python 支持一種簡潔的寫法:在一行中完成 if-else 判斷。

語法:

變量 = 值1 if 條件 else 值2

示例:

age = 16
status = "成年" if age >= 18 else "未成年"
print(status)

輸出:

未成年

適合用于 根據(jù)條件選擇一個值賦給變量 的情況。

小結(jié)一下吧

類型場景示例
if只有一個條件
if-else兩種可能,二選一
if-elif-else多種情況,依次判斷
嵌套 if條件套條件,多層判斷
三元表達式簡潔地賦值,適合一行判斷

? 小練習題

練習 1:分數(shù)等級判斷器

讓用戶輸入一個 0~100 的整數(shù),判斷其屬于哪個等級:

  • 90 以上:優(yōu)秀

  • 80~89:良好

  • 70~79:中等

  • 60~69:及格

  • 低于 60:不及格

  • 其他情況提示“輸入有誤”

練習 2:三角形合法性判斷

輸入三條邊的長度,判斷是否能組成一個三角形(任意兩邊之和大于第三邊),并進一步判斷:

  • 是等邊三角形

  • 是等腰三角形

  • 是普通三角形

  • 否則輸出“不合法的三角形”

練習 3:模擬 ATM 登錄與權限檢查(嵌套)

假設用戶名為 admin,密碼為 8888,登錄成功后再檢查是否為管理員(管理員輸入 "yes" 才能繼續(xù)操作)。

練習 4:三元運算小測試

輸入一個數(shù)字,輸出 "正數(shù)"、"負數(shù)""零"用三元運算符 實現(xiàn)。

(三)循環(huán)(Loops)

在編程中,我們常常需要重復執(zhí)行某些操作,比如遍歷列表、處理每一行數(shù)據(jù)、執(zhí)行某個動作直到滿足條件等等。Python 提供了兩種主要的循環(huán)結(jié)構:while 循環(huán)和 for 循環(huán)配合控制語句(如 breakcontinue可以構建出豐富的循環(huán)邏輯。

1. while循環(huán)(基于條件重復執(zhí)行)

? 基本語法
while 條件表達式:
    循環(huán)體
  • 每次循環(huán)前都會檢查“條件表達式”的值;

  • 條件為 True → 執(zhí)行循環(huán)體;

  • 條件為 False → 結(jié)束循環(huán)。

?? 示例:打印 1 到 5 的數(shù)字
i = 1
while i <= 5:
    print(i)
    i += 1
??break語句(提前終止循環(huán))

break 用于立即跳出整個循環(huán)結(jié)構,不管循環(huán)條件是否還為 True

i = 1
while True:
    print(i)
    if i == 3:
        break
    i += 1

輸出:1, 2, 3,然后退出循環(huán)

??continue語句(跳過當前迭代)

continue 用于跳過本次循環(huán)中剩下的語句,直接進入下一次判斷。

i = 0
while i < 5:
    i += 1
    if i == 3:
        continue
    print(i)

輸出:1, 2, 4, 5(跳過了 3)

2.for循環(huán)(用于遍歷序列)

? 基本語法
for 變量 in 可迭代對象:
    循環(huán)體

可迭代對象包括:字符串、列表、字典、集合、元組等。

?? 遍歷字符串
for ch in "hello":
    print(ch)
?? 遍歷列表
fruits = ['apple', 'banana', 'orange']
for fruit in fruits:
    print(fruit)
?? 遍歷字典
info = {"name": "Tom", "age": 20}
for key in info:
    print(key, "=>", info[key])

或使用 .items() 遍歷鍵值對:

for key, value in info.items():
    print(f"{key}: {value}")
?? 遍歷集合
s = {"apple", "banana", "cherry"}
for item in s:
    print(item)
??range()函數(shù)與數(shù)值循環(huán)
for i in range(1, 6):
    print(i)
  • range(n):0 到 n-1

  • range(start, end):start 到 end-1

  • range(start, end, step):按步長生成

??enumerate()結(jié)合索引遍歷

想同時獲取元素和下標時使用 enumerate()

colors = ['red', 'green', 'blue']
for index, color in enumerate(colors):
    print(f"{index}: {color}")

3. 循環(huán)控制語句

?break:提前終止整個循環(huán)

通常與 if 配合使用,用于在滿足某個條件時立即退出循環(huán)。

for i in range(1, 10):
    if i == 5:
        break
    print(i)
?continue:跳過當前迭代

用于跳過某些不符合條件的值。

for i in range(1, 6):
    if i % 2 == 0:
        continue
    print(i)  # 輸出 1 3 5(跳過偶數(shù))
?else語句在循環(huán)中的作用

else 可以與 forwhile 循環(huán)一起使用:

  • 當循環(huán)沒有被 break 中斷時,else 中的語句會執(zhí)行。

    for i in range(1, 5):
        if i == 10:
            break
    else:
        print("未被 break,循環(huán)正常結(jié)束")
    

    這在處理搜索類問題時特別有用:

    nums = [1, 3, 5, 7]
    target = 4
    for num in nums:
        if num == target:
            print("找到目標")
            break
    else:
        print("未找到目標")
    

小結(jié)一下吧

循環(huán)類型用途特點
while條件控制循環(huán)不確定次數(shù)時使用
for遍歷序列更簡潔,適合固定結(jié)構
break跳出循環(huán)終止整個循環(huán)體
continue跳過本次迭代繼續(xù)下一輪
else循環(huán)結(jié)構補充僅在循環(huán)未被 break時執(zhí)行

? 小練習題

?? 練習題 1:打印 1~100 中所有能被 7 整除的數(shù)
?? 練習題 2:使用while計算從 1 累加到 n 的和(n 由用戶輸入)
?? 練習題 3:找出列表中第一個大于 50 的元素,并輸出其值和索引
?? 練習題 4:輸出 1~30 中除了能被 3 整除的數(shù)(使用 continue)
?? 練習題 5:統(tǒng)計一段字符串中元音字母的個數(shù)(不區(qū)分大小寫)
?? 練習題 6:使用for和else實現(xiàn)一個猜數(shù)字小游戲

四、函數(shù)與相關基礎知識:讓代碼會“思考”的魔法工具

在編程的世界里,函數(shù)就像是程序的“積木”:它們能把一段可復用的操作封裝起來,想用就調(diào)用,修改也方便,堪稱優(yōu)雅代碼的起點。

無論是打印一行文字,計算一個數(shù)列的和,還是訓練一個 AI 模型,本質(zhì)上你做的都是“定義功能 + 調(diào)用功能” —— 這正是函數(shù)的使命。

(一)函數(shù)基礎

1. 什么是函數(shù)?為什么要使用函數(shù)?

在編程中,函數(shù)是一個非常重要的概念,它可以被理解為“功能塊”,用來封裝一段代碼,供其他地方調(diào)用。通過函數(shù),開發(fā)者可以:

  • 提高代碼復用性:避免重復寫相同的代碼,簡化開發(fā)和維護。

  • 增強可讀性:將復雜的任務拆解成小的、獨立的單元,便于理解。

  • 分隔邏輯:函數(shù)讓代碼的邏輯結(jié)構更加清晰和模塊化,有助于團隊協(xié)作開發(fā)。

例如,我們可以定義一個函數(shù)來計算兩個數(shù)字的和,而不需要每次都重復寫加法的操作。只要定義一次,后續(xù)就可以隨時調(diào)用。

2. 使用def定義函數(shù)

在 Python 中,函數(shù)是通過 def 關鍵字來定義的。它的基本語法如下:

def function_name(parameters):
    # 函數(shù)體
    return result
  • def 是 Python 中定義函數(shù)的關鍵字

  • function_name 是你給函數(shù)命名的名稱,符合命名規(guī)則

  • parameters 是函數(shù)的輸入(可以沒有)

  • return 是返回結(jié)果的關鍵字(如果不返回任何值,則默認為 None

示例:一個簡單的加法函數(shù)
def add(a, b):
    return a + b

# 調(diào)用函數(shù)
result = add(3, 5)
print(result)  # 輸出: 8

這里我們定義了一個 add 函數(shù),輸入?yún)?shù)是 ab,它們會被加在一起并返回結(jié)果。

3. 函數(shù)的調(diào)用和執(zhí)行流程

定義函數(shù)后,調(diào)用函數(shù)就能執(zhí)行該函數(shù)的代碼。Python 會根據(jù)函數(shù)調(diào)用的順序進入函數(shù)體,并執(zhí)行其中的代碼。

  • 當函數(shù)被調(diào)用時,程序會暫停當前位置,跳轉(zhuǎn)到函數(shù)體執(zhí)行代碼,直到遇到 return 語句(或者函數(shù)執(zhí)行完畢)才返回。

  • 如果沒有 return 語句,則返回 None。

示例:簡單的函數(shù)調(diào)用與返回值
def greet(name):
    return f"Hello, {name}!"

message = greet("Alice")
print(message)  # 輸出: Hello, Alice!

這里的 greet 函數(shù)通過 return 語句返回了一個字符串,調(diào)用時傳入了參數(shù) "Alice",最終返回 "Hello, Alice!"。

4.print()與return的區(qū)別與使用場景

在 Python 中,print()return 都用于輸出數(shù)據(jù),但它們有顯著的不同:

  • print() 用于將信息輸出到控制臺,主要用于調(diào)試、輸出中間結(jié)果或與用戶交互。

  • return 用于函數(shù)的輸出,它將值返回給調(diào)用者,可以被其他代碼再次使用。

示例:print()和return對比
# 使用 print()
def greet_print(name):
    print(f"Hello, {name}!")

greet_print("Alice")  # 輸出: Hello, Alice!

# 使用 return
def greet_return(name):
    return f"Hello, {name}!"

message = greet_return("Alice")
print(message)  # 輸出: Hello, Alice!
  • greet_print 使用 print() 輸出值,但無法把它傳遞給其他部分的代碼。

  • greet_return 使用 return 返回結(jié)果,這個返回值可以在代碼的其他地方使用或存儲。

小結(jié)一下吧

  • 函數(shù)是代碼復用、模塊化的核心工具。

  • 使用 def 定義函數(shù),return 返回值。

  • print() 用于輸出調(diào)試信息,return 用于返回計算結(jié)果。

(二)函數(shù)參數(shù)

函數(shù)參數(shù)是函數(shù)接收外部輸入的方式。理解和掌握函數(shù)參數(shù)的使用,不僅能幫助你編寫更靈活的代碼,還能讓你的程序更具擴展性和可維護性。

1. 位置參數(shù)

位置參數(shù)是最常見的函數(shù)參數(shù)類型,它是指參數(shù)傳遞時位置的順序決定了每個參數(shù)的含義。

例如,在函數(shù)定義時,參數(shù) ab 的位置決定了它們的意義。當調(diào)用函數(shù)時,傳遞的參數(shù)值會根據(jù)位置匹配到相應的參數(shù)。

示例:位置參數(shù)
def add(a, b):
    return a + b

result = add(3, 5)  # 位置參數(shù):3 被賦值給 a,5 被賦值給 b
print(result)  # 輸出: 8

這里的 add 函數(shù)有兩個位置參數(shù):ab。我們調(diào)用 add(3, 5) 時,3 會賦值給 a,5 會賦值給 b,最終返回它們的和。

2. 關鍵字參數(shù)

關鍵字參數(shù)允許你在調(diào)用函數(shù)時顯式地指定每個參數(shù)的名稱。這樣可以不關心參數(shù)的順序,只需要知道參數(shù)名。

示例:關鍵字參數(shù)
def greet(name, age):
    return f"Hello, {name}! You are {age} years old."

message = greet(age=25, name="Alice")  # 參數(shù)順序不重要
print(message)  # 輸出: Hello, Alice! You are 25 years old.

在調(diào)用 greet 函數(shù)時,agename 的順序不再重要,關鍵字參數(shù)通過指定 age=25name="Alice" 來傳遞值。

3. 默認參數(shù)

默認參數(shù)是指在定義函數(shù)時,為某些參數(shù)提供默認值。如果調(diào)用時沒有提供這些參數(shù)的值,Python 會使用默認值。

示例:默認參數(shù)
def greet(name, age=18):  # age 有默認值
    return f"Hello, {name}! You are {age} years old."

message1 = greet("Alice")  # 調(diào)用時沒有提供 age,使用默認值
message2 = greet("Bob", 30)  # 調(diào)用時提供了 age,覆蓋默認值

print(message1)  # 輸出: Hello, Alice! You are 18 years old.
print(message2)  # 輸出: Hello, Bob! You are 30 years old.

greet 函數(shù)中,age 有默認值 18。如果調(diào)用時沒有傳入 age,就會使用默認值;如果傳入了 age,則會覆蓋默認值。

4. 可變參數(shù):*args與**kwargs

有時候我們不知道函數(shù)需要接收多少個參數(shù),這時可以使用 可變參數(shù)

  • *args 用于接收位置參數(shù),它將接收多余的位置參數(shù)并將其打包成一個元組。

  • **kwargs 用于接收關鍵字參數(shù),它將接收多余的關鍵字參數(shù)并將其打包成一個字典。

示例:*args和**kwargs
def example(*args, **kwargs):
    print("args:", args)
    print("kwargs:", kwargs)

# 調(diào)用函數(shù)時傳入不同數(shù)量的參數(shù)
example(1, 2, 3, name="Alice", age=25)

# 輸出:
# args: (1, 2, 3)
# kwargs: {'name': 'Alice', 'age': 25}
  • *args 將所有位置參數(shù)(1, 2, 3)打包成一個元組 (1, 2, 3)。

  • **kwargs 將所有關鍵字參數(shù)(name="Alice", age=25)打包成一個字典 {'name': 'Alice', 'age': 25}

5. 參數(shù)順序規(guī)范

當一個函數(shù)同時使用位置參數(shù)、默認參數(shù)和可變參數(shù)時,有一定的順序規(guī)范,必須遵循以下順序:

  • 位置參數(shù)

  • 默認參數(shù)

  • *args

  • **kwargs

示例:參數(shù)順序
def function(a, b=2, *args, c, **kwargs):
    print(a, b, args, c, kwargs)

# 調(diào)用時,按照順序傳遞參數(shù)
function(1, c=3, d=4, e=5)
# 輸出: 1 2 () 3 {'d': 4, 'e': 5}
  • a 是位置參數(shù),必須最先提供。

  • b 是默認參數(shù),如果不提供則使用默認值。

  • *args 用于接收多余的所有位置參數(shù)。

  • c 是一個關鍵字參數(shù),調(diào)用時必須顯式指定。

  • **kwargs 用于接收多余的所有關鍵字參數(shù)。

小結(jié)一下吧

  • 位置參數(shù):根據(jù)參數(shù)順序傳遞值。

  • 關鍵字參數(shù):顯式指定參數(shù)名和值。

  • 默認參數(shù):函數(shù)定義時為參數(shù)提供默認值。

  • 可變參數(shù):*args 用于接收多位置參數(shù),**kwargs 用于接收多關鍵字參數(shù)。

  • 參數(shù)順序:位置參數(shù) > 默認參數(shù) > *args > **kwargs

(三)函數(shù)返回值

在 Python 中,函數(shù)不僅可以執(zhí)行某些操作,還可以將結(jié)果“返回”給調(diào)用者。這就是 返回值(Return Value) 的概念。

通過 return 語句,函數(shù)可以把處理的結(jié)果交給外部使用。如果函數(shù)沒有 return,那它默認返回的是 None。

1. 使用return返回結(jié)果

基本語法:

def function_name(...):
    ...
    return result

示例:

def square(x):
    return x * x

result = square(5)
print(result)  # 輸出: 25

函數(shù) square 返回的是 x 的平方,調(diào)用后我們可以拿到這個結(jié)果并繼續(xù)使用。

2. 返回多個值(元組)

Python 支持從一個函數(shù)中返回多個值,這些值實際上被打包成一個元組返回。

示例:

def get_name_and_age():
    name = "Alice"
    age = 30
    return name, age

n, a = get_name_and_age()
print(n)  # Alice
print(a)  # 30

多值返回的本質(zhì)是:return name, age 等價于 return (name, age),然后通過拆包語法接收。

3. 函數(shù)無返回值時的表現(xiàn)

如果函數(shù)中沒有 return 語句,或者只是 return 而沒有值,那默認返回的是 None。

示例:

def say_hello():
    print("Hello!")

result = say_hello()
print(result)  # 輸出: None

這個函數(shù) say_hello() 雖然做了事情(打?。?,但沒有 return,因此返回值是 None。

4. 提前終止函數(shù)執(zhí)行

return 不僅能返回值,還能用來提前終止函數(shù)的執(zhí)行

示例:

def divide(a, b):
    if b == 0:
        return "除數(shù)不能為 0"
    return a / b

print(divide(10, 0))  # 輸出: 除數(shù)不能為 0
print(divide(10, 2))  # 輸出: 5.0

b 是 0 時,函數(shù)遇到第一個 return 后立即終止執(zhí)行,不會繼續(xù)往下運行。

5. 將返回值作為表達式使用

函數(shù)返回值可以被用在其他表達式或函數(shù)中,像這樣:

def add(a, b):
    return a + b

print(add(2, 3) * 10)  # 輸出: 50

add(2, 3) 會返回 5,然后再與 10 相乘。

小結(jié)一下吧

內(nèi)容示例返回值說明
返回單個值return x返回一個對象
返回多個值return x, y返回一個元組
無 return 或 return Nonereturn / 無 return返回 None
提前結(jié)束函數(shù)if ...: return ...直接退出函數(shù)
返回值可以參與表達式add(1, 2) * 3函數(shù)結(jié)果用于計算

(四)函數(shù)返回值類型注解(Type Hint / Type Annotation)

1. Python 3 引入的類型注解(Type Hints)

先用一句話理解:

def add(a: int, b: int) -> int:
    return a + b

?? -> int 的意思是:

這個函數(shù)“設計上”應該返回一個 int

不是強制,只是“聲明”。這是 給“人”和“工具”看的,不是給 Python 解釋器強制執(zhí)行的。

注意Python 不會強制檢查!下面的代碼 是合法的

def add(a: int, b: int) -> int:
    return "not a number"

Python 不會報錯。?類型注解的作用在于:

  • IDE(PyCharm)

  • 靜態(tài)檢查工具(mypy、pyright)

  • 閱讀代碼的人(包括未來的你)

2. 為什么現(xiàn)在的 Python 項目都強烈推薦用?

2.1 PyCharm 會變得非常聰明

def foo() -> dict[str, int]:
    return {"a": 1}

你輸入:

result = foo()
result["a"].

PyCharm 會自動提示:?? 這是 int,有哪些方法

2.2 提前發(fā)現(xiàn) bug(不用等運行)

def get_age() -> int:
    return "18"

PyCharm / mypy 會直接警告你:

Expected int, got str

3. 常見的返回值寫法(你一定會遇到)

3.1 返回多個類型(Union)

from typing import Union

def parse(s: str) -> Union[int, None]:
    if s.isdigit():
        return int(s)
    return None

Python 3.10+ 更推薦:

def parse(s: str) -> int | None:
    ...

3.2 返回列表 / 字典

def get_names() -> list[str]:
    return ["Alice", "Bob"]

def get_scores() -> dict[str, int]:
    return {"math": 90}

3.3 返回自定義對象

class User:
    ...

def get_user() -> User:
    return User()

五、字符串操作模塊

在 Python 中,字符串(str)是最常用、最重要的數(shù)據(jù)類型之一。無論你是在處理用戶輸入、讀取文件、構建網(wǎng)頁內(nèi)容、分析文本數(shù)據(jù),幾乎都繞不開對字符串的處理。

現(xiàn)在我們總結(jié)掌握 Python 字符串的各種操作方法,從最基本的創(chuàng)建與訪問,到復雜的格式化,我們需要學會如何清洗、切割、替換、判斷和重組字符串,并為后續(xù)的數(shù)據(jù)處理與文本分析打下堅實基礎。

(一)字符串基礎

在 Python 中,字符串(str)是用來表示文本的數(shù)據(jù)類型。本部分介紹字符串的創(chuàng)建方式、基本特性、訪問技巧以及常見的基本操作。

1. 字符串的定義與創(chuàng)建

字符串可以用 單引號 '、雙引號 "三引號 ''' / """ 括起來。

# 單引號
s1 = 'hello'

# 雙引號
s2 = "world"

# 三引號(支持多行)
s3 = '''This is
a multi-line
string.'''

?? Python 中單引號和雙引號作用相同,主要用于避免轉(zhuǎn)義沖突。

2. 字符串是不可變對象

字符串是 不可變的(immutable):創(chuàng)建后無法修改,只能重新賦值。

s = "hello"
# s[0] = 'H'  # ? 錯誤!字符串不能直接修改
s = "Hello"   # ? 只能重新賦值

3. 字符串的索引與切片

字符串可以看作字符的序列,可以通過索引或切片訪問其部分內(nèi)容。

s = "Python"

# 索引(從 0 開始)
print(s[0])   # P
print(s[-1])  # n(最后一個字符)

# 切片 [start:end:step]
print(s[0:2])     # Py(不包括 end)
print(s[::2])     # Pto(每隔1個)
print(s[::-1])    # nohytP(反轉(zhuǎn)字符串)

? 切片非常強大,是字符串處理中不可或缺的工具。

4. 字符串的連接與重復

# 拼接字符串
a = "Hello"
b = "World"
c = a + " " + b
print(c)  # Hello World

# 重復字符串
print("ha" * 3)   # hahaha

5. 字符串的成員運算

s = "python"
print("p" in s)      # True
print("z" not in s)  # True

6. 字符串與類型轉(zhuǎn)換

num = 123
text = str(num)  # 數(shù)字轉(zhuǎn)字符串
print("數(shù)字是:" + text)

# 也可以使用 f-string(推薦)
print(f"數(shù)字是:{num}")

小結(jié)一下吧

操作類型常用方法 / 語法
創(chuàng)建字符串'abc', "abc", '''abc'''
索引s[0], s[-1]
切片s[1:4], s[::-1]
拼接與重復+, *
判斷是否存在in, not in
類型轉(zhuǎn)換str(x), f"{x}"

(二)字符串常見操作方法

Python 的字符串類型(str)內(nèi)建了大量實用的方法,幫助我們完成查找、替換、對齊、大小寫轉(zhuǎn)換、格式化等各類文本處理任務。本節(jié)將系統(tǒng)講解所有主流、實用的方法,并配合用例說明。

1. 大小寫轉(zhuǎn)換

方法作用
.lower()轉(zhuǎn)為小寫
.upper()轉(zhuǎn)為大寫
.capitalize()首字母大寫,其余小寫
.title()每個單詞首字母大寫
.swapcase()大小寫互換
s = "hello World"
print(s.lower())       # hello world
print(s.upper())       # HELLO WORLD
print(s.capitalize())  # Hello world
print(s.title())       # Hello World
print(s.swapcase())    # HELLO wORLD

2. 查找與判斷

方法功能
.find(sub)找到子串首次出現(xiàn)的位置(找不到返回 -1)
.rfind(sub)從右側(cè)開始查找
.index(sub)與 find 類似,但找不到拋出異常
.startswith(prefix)是否以某前綴開頭
.endswith(suffix)是否以某后綴結(jié)尾
.in判斷子串是否存在
s = "hello python"
print(s.find("py"))       # 6
print(s.startswith("he")) # True
print(s.endswith("on"))   # True
print("py" in s)          # True

3. 刪除空白符與字符清洗

方法功能
.strip()刪除兩端空白符
.lstrip()刪除左側(cè)空白符
.rstrip()刪除右側(cè)空白符
.replace(old, new)替換子串
s = "  hello world  "
print(s.strip())     # "hello world"

s2 = "python,java,c"
print(s2.replace(",", " | "))  # python | java | c

4. 字符串對齊與填充

方法說明
.center(width, char)居中填充
.ljust(width, char)左對齊填充
.rjust(width, char)右對齊填充
.zfill(width)用 0 填充左側(cè)數(shù)字部分
print("hi".center(10, "-"))  # ----hi----
print("hi".ljust(10, "."))   # hi........
print("hi".rjust(10, "*"))   # ********hi
print("42".zfill(5))         # 00042

5. 拆分與連接

方法功能
.split(sep)拆分為列表
.rsplit(sep)從右拆分
.splitlines()拆分多行字符串
'sep'.join(list)用分隔符連接列表為字符串
s = "apple,banana,grape"
print(s.split(","))         # ['apple', 'banana', 'grape']

lines = "line1\nline2\nline3"
print(lines.splitlines())   # ['line1', 'line2', 'line3']

words = ['one', 'two', 'three']
print("-".join(words))      # one-two-three

6. 內(nèi)容判斷類方法(返回布爾值)

方法判斷類型
.isalpha()是否全字母
.isdigit()是否全數(shù)字
.isalnum()是否全是字母或數(shù)字
.isspace()是否全是空白符
.isupper()是否全為大寫
.islower()是否全為小寫
.istitle()是否符合標題規(guī)范(首字母大寫)
print("abc".isalpha())     # True
print("123".isdigit())     # True
print("abc123".isalnum())  # True
print("   ".isspace())     # True

7. 高級字符串格式化(f-string)

name = "Alice"
age = 30

# 推薦方式:f-string(Python 3.6+)
print(f"{name} is {age} years old.")  # Alice is 30 years old

# 老式:format()
print("{} is {} years old.".format(name, age))

# 占位對齊控制
print(f"|{name:^10}|{age:>3}|")  # 居中+右對齊:|  Alice   | 30|

8. 轉(zhuǎn)義字符與原始字符串

字符含義
\n換行
\t制表符
\\反斜杠
r""原始字符串,不轉(zhuǎn)義
print("hello\nworld")     # 換行
print(r"c:\new\folder")   # c:\new\folder

9. 其他實用技巧

  • 長字符串拼接:

    s = (
        "This is a very long string "
        "split across multiple lines "
        "but still valid."
    )
    
  • 字符串比較支持 <, >, == 等字典序?qū)Ρ龋?/p>

    print("apple" < "banana")  # True

小結(jié):常用字符串方法分類對照表

類型常用方法
查找判斷find(), startswith(), in
修改清洗strip(), replace()
大小寫處理lower(), capitalize()
對齊填充center(), zfill()
格式化f"", format()
判斷內(nèi)容isdigit(), isalpha()
分割拼接split(), join()
其他len(), 轉(zhuǎn)義、比較等

(三)字符串切片與索引

1. 字符串索引(正向索引 / 負向索引)

Python 字符串是序列類型,每個字符都有對應的索引位置。我們可以通過索引訪問字符串中的單個字符。

?? 正向索引(從 0 開始)
s = "python"
print(s[0])  # p
print(s[1])  # y
print(s[5])  # n
字符python
索引012345
?? 負向索引(從 -1 開始,表示從右往左)
s = "python"
print(s[-1])  # n
print(s[-2])  # o
print(s[-6])  # p
字符python
索引-6-5-4-3-2-1

注意

  • 超出索引范圍(如 s[10])會拋出 IndexError。

  • 字符串是 不可變對象,不能通過索引修改某個字符。

2. 字符串切片([start:stop:step])

切片(slice)是從字符串中提取子串的一種方式,語法格式為:

s[start : stop : step]
  • start:起始索引(包含)

  • stop:終止索引(不包含)

  • step:步長(默認為 1)

基礎切片
s = "Hello, Python!"

print(s[0:5])   # Hello
print(s[7:13])  # Python
print(s[:5])    # Hello(從頭開始)
print(s[7:])    # Python!(直到結(jié)尾)
使用負數(shù)索引切片
s = "abcdefg"
print(s[-4:-1])  # def
print(s[-7:-4])  # abc
添加步長(step)
s = "0123456789"
print(s[::2])     # 02468(每兩個字符取一個)
print(s[1::3])    # 147(從索引 1 開始,每隔 3 個?。?
反向切片(步長為負數(shù))
s = "abcdef"
print(s[::-1])   # fedcba(字符串反轉(zhuǎn))
print(s[-1:-7:-1]) # fedcba(等同上行)
切片邊界記憶口訣
  • 包頭不包尾:起始位置包含,結(jié)束位置不包含。

  • 步長方向一致:正數(shù)步長從左到右,負數(shù)步長從右到左。

  • 索引可以為負:負索引從末尾向前數(shù)。

3. 字符串的遍歷

遍歷字符串可以逐個訪問其字符,常用于統(tǒng)計、查找、生成新字符串等任務。

基礎遍歷
s = "hello"
for c in s:
    print(c)

輸出:

h
e
l
l
o
帶索引遍歷(推薦:使用 enumerate)
s = "hello"
for index, char in enumerate(s):
    print(f"{index} -> {char}")

輸出:

0 -> h
1 -> e
2 -> l
3 -> l
4 -> o

經(jīng)典應用場景小結(jié)

場景示例
提取子串s[3:7]
字符串反轉(zhuǎn)s[::-1]
判斷回文s == s[::-1]
截取前綴/后綴s[:3]s[-3:]
每隔一個字符取s[::2]

(四)字符串格式化

Python 提供了三種主要的字符串格式化方式:

  • % 占位符格式化(經(jīng)典寫法)

  • str.format() 方法格式化(兼容寫法)

  • f-string 格式化(推薦方式,Python 3.6+)

1.%占位符格式化(C 風格)

這是最早期的格式化方式,語法類似于 C 語言:

name = "Alice"
age = 25
print("My name is %s and I am %d years old." % (name, age))
占位符含義
%s字符串
%d整數(shù)
%f浮點數(shù)(默認小數(shù)點后 6 位)
%.2f浮點數(shù)保留 2 位小數(shù)

缺點:可讀性差、容易出錯,不推薦用于新代碼。

2.str.format()方法格式化

引入于 Python 2.7 / 3.0,支持位置參數(shù)、關鍵字參數(shù),更靈活:

name = "Alice"
age = 25
print("My name is {} and I am {} years old.".format(name, age))
?? 支持位置參數(shù) / 關鍵字參數(shù)
print("Hello, {0}. You are {1}.".format("Bob", 30))
print("Hello, {name}. You are {age}.".format(name="Bob", age=30))
?? 支持格式控制
pi = 3.1415926
print("Pi is {:.2f}".format(pi))  # Pi is 3.14

缺點:寫法較冗長,推薦 f-string 替代。

3.f-string 格式化(Python 3.6+,推薦?)

最現(xiàn)代、最簡潔的格式化方式,代碼更清晰,推薦作為首選寫法。

name = "Alice"
age = 25
print(f"My name is {name} and I am {age} years old.")
?? 支持表達式
a = 5
b = 3
print(f"{a} +  = {a + b}")
?? 支持格式化控制
pi = 3.1415926
print(f"Pi rounded to 2 digits: {pi:.2f}")
?? 與函數(shù)、數(shù)據(jù)結(jié)構結(jié)合
user = {"name": "Bob", "score": 88}
print(f"{user['name']} scored {user['score']}")

三種方式對比

特性% 格式化str.format()f-string
可讀性?????
功能強大一般?????
寫法簡潔一般????
推薦程度? 不推薦? 過渡用法??? 首選

小結(jié)一下吧

  • 新代碼推薦 f-string,語法簡潔、表達能力強。

  • str.format() 適用于兼容舊版本 Python。

  • % 占位符方式適合了解,不建議用于正式項目中。

六、列表、字典與集合 —— Python 中的數(shù)據(jù)組織能力

(一)為什么需要“數(shù)據(jù)結(jié)構”

在前面的章節(jié)中,我們已經(jīng)學習了 變量、基本數(shù)據(jù)類型、控制流和函數(shù)以及字符串。這些知識可以幫助我們描述一個值、處理一次邏輯、完成一個功能

但在真實的程序中,我們面對的往往不是“一個值”,而是:

  • 一組數(shù)據(jù)

  • 多條記錄

  • 多個對象

  • 一批狀態(tài)或配置項

這正是 “數(shù)據(jù)結(jié)構”存在的意義。

1. 單個變量的局限性

先看一個最簡單的例子。如果我們只需要保存一個人的名字,用一個變量就足夠:

name = "張彥峰"

但如果現(xiàn)在要保存 10 個、100 個、甚至更多名字 呢?你顯然不可能這樣寫:

name1 = "盧政伯" name2 = "呂鴻昌" name3 = "秦學磊"

這種寫法存在明顯問題:

  • 變量數(shù)量不可控

  • 無法方便地進行循環(huán)處理

  • 代碼幾乎不可維護

這時,我們需要一種方式,把“一組相關的數(shù)據(jù)”組織在一起。

2. 從“一個值”到“一組值”

繼續(xù)剛才的例子,如果我們希望把多個名字放在一起,Python 提供了 列表(list) 這樣的數(shù)據(jù)結(jié)構:

names = ["張彥峰","盧政伯","呂鴻昌","秦學磊"]

這樣做的好處是:

  • 所有名字屬于同一個整體

  • 可以通過循環(huán)統(tǒng)一處理

  • 可以按順序訪問、修改、刪除

這一步,本質(zhì)上是從:“一個變量保存一個值”升級為:“一個變量保存一組有結(jié)構的數(shù)據(jù)”

3. 一條記錄 vs 多條記錄

再看一個更貼近實際開發(fā)的例子。假設我們要表示一個用戶的信息:

user_name = "張彥峰" user_age = 18 user_email = "zyf@alibaba.com"

這種寫法的問題在于:

  • 信息是分散的

  • 很難整體傳遞或管理

  • 字段之間缺乏明確的“歸屬關系”

這時,更合理的做法是使用 字典(dict)

user = {
    "name": "張彥峰",
    "age": 18,
    "email": "zyf@alibaba.com"
}

字典的特點是:

  • 通過 key(鍵) 來訪問數(shù)據(jù)

  • 每個字段都有清晰的含義

  • 非常適合描述“一條記錄”

如果現(xiàn)在有 多條用戶記錄,我們就可以把多個字典放進一個列表中:

users = [
    {"name": "張彥峰", "age": 18},
    {"name": "張琴", "age": 18}
]

你可以看到:數(shù)據(jù)結(jié)構是可以組合使用的,這正是后面處理嵌套數(shù)據(jù)(如 JSON)的基礎。

4. 最常用的幾種數(shù)據(jù)結(jié)構

在本章中,我們將系統(tǒng)學習 Python 中最常用的幾種數(shù)據(jù)結(jié)構:

  • 列表(list):用于存儲有序、可變的一組數(shù)據(jù)

  • 字典(dict):用于存儲鍵值映射關系

  • 集合(set):用于去重和集合運算

  • 元組(tuple):用于表示不可變的數(shù)據(jù)組合

通過這一章,你將逐步建立起這樣的能力:

根據(jù)問題特點,選擇合適的數(shù)據(jù)結(jié)構,并高效地操作它們

這也是后續(xù)學習 嵌套結(jié)構、JSON 數(shù)據(jù)解析、配置處理 的必要基礎。

(二)列表(List):有序數(shù)據(jù)的容器

列表是 Python 中最常用且強大的數(shù)據(jù)結(jié)構之一,廣泛用于存儲有序、可變的數(shù)據(jù)。作為一個容器類型,它不僅能存儲多種數(shù)據(jù)類型,還能高效支持數(shù)據(jù)的添加、刪除、修改和訪問。掌握列表的使用是理解 Python 數(shù)據(jù)處理能力的重要基礎。

1. 列表的基本概念

列表(list)是一個有序的容器,可以存儲任意類型的數(shù)據(jù),包括整數(shù)、字符串、布爾值,甚至是其他列表。列表的核心特點包括:

  • 有序性:列表中的元素是按順序排列的,每個元素都有一個對應的索引,索引從 0 開始。

  • 可變性:列表是可變的,可以在原地修改列表的內(nèi)容,例如添加、刪除或更新元素。

  • 支持多種數(shù)據(jù)類型:列表可以包含不同類型的元素,甚至可以存儲其他容器類型(如列表、字典等)。

# 示例:包含整數(shù)的列表
numbers = [1, 2, 3, 4, 5]

# 示例:包含不同數(shù)據(jù)類型的列表
info = ["Alice", 18, True, 3.14, ["nested", "list"]]

關鍵點與字符串(str)類似,列表也支持通過索引訪問和切片操作,但字符串是不可變的,而列表可以直接修改。

2. 列表的創(chuàng)建與訪問

創(chuàng)建列表

列表的創(chuàng)建非常簡便,可以通過方括號 [] 來定義??梢詣?chuàng)建空列表、包含多個元素的列表,或是包含混合類型元素的列表。

# 空列表
empty_list = []

# 含有多個整數(shù)的列表
numbers = [1, 2, 3, 4, 5]

# 含有不同類型的元素的列表
mixed = [1, "Alice", True, 3.14]
訪問列表元素

通過索引訪問列表中的元素,索引從 0 開始。列表還支持負索引,允許從列表的末尾開始訪問元素。

numbers = [10, 20, 30, 40]

# 正向索引
print(numbers[0])  # 10
print(numbers[3])  # 40

# 負向索引
print(numbers[-1])  # 40
print(numbers[-2])  # 30

此外,列表支持切片操作,可以通過指定起始和結(jié)束索引來獲取子列表。

# 切片示例
print(numbers[1:3])  # [20, 30]
print(numbers[:2])   # [10, 20]
print(numbers[2:])   # [30, 40]

注意:切片操作返回的是新列表,原列表內(nèi)容不受影響。

3. 列表的常用修改操作

列表是可變的,意味著可以在原地修改其內(nèi)容。常見的修改操作包括添加元素、刪除元素修改元素

添加元素
  • append():將元素添加到列表的末尾。

  • insert():將元素插入到指定的索引位置。

  • extend():批量追加

# 示例:添加元素
nums = [1, 2, 3]
nums.append(4)  # 在末尾添加元素
nums.insert(1, 1.5)  # 在索引 1 處插入元素
nums.extend([3, 4])   # [1, 2, 3, 4]

print(nums)  # 輸出: [1, 1.5, 2, 3, 4, 3, 4]
刪除元素
  • remove():刪除第一個匹配到的元素。

  • pop():刪除并返回指定索引位置的元素(默認刪除最后一個元素)。

  • del:根據(jù)索引刪除元素。

  • clear():清空列表

# 示例:刪除元素
nums.remove(1.5)  # 刪除元素 1.5
popped_element = nums.pop()  # 刪除并返回最后一個元素
del nums[0]  # 刪除索引 0 處的元素

print(nums)  # 輸出: [2, 3, 4, 3]
修改元素

通過索引可以直接修改列表中的元素:

nums[0] = 10  # 將索引 0 處的元素修改為 10
print(nums)    # 輸出: [10, 3]

4. 列表的遍歷與循環(huán)配合

遍歷列表元素

遍歷列表元素時,最常用的是 for 循環(huán)??梢灾苯颖闅v列表的每個元素,或者使用 range() 函數(shù)配合索引來遍歷列表。

# 直接遍歷元素
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
    print(fruit)  # 輸出每個水果

# 使用索引遍歷
for i in range(len(fruits)):
    print(i, fruits[i])  # 輸出索引和值

# 使用 enumerate 獲取索引和值
for idx, fruit in enumerate(fruits):
    print(idx, fruit)  # 輸出索引和值

應用場景

  • 只關心值:直接遍歷元素。

  • 需要索引:使用 range()enumerate()。

5. 列表的常用內(nèi)置操作與函數(shù)

Python 提供了豐富的內(nèi)置函數(shù)和方法來操作列表。以下是一些常用操作:

  • len():返回列表的長度。

  • in:檢查元素是否存在于列表中。

  • count():統(tǒng)計元素在列表中出現(xiàn)的次數(shù)。

  • index():查找元素首次出現(xiàn)的位置。

  • sort():原地排序。

  • sorted():返回一個新排序的列表。

  • reverse():原地反轉(zhuǎn)列表。

nums = [4, 2, 7, 1]

print(len(nums))     # 輸出: 4
print(2 in nums)     # 輸出: True
print(nums.count(2)) # 輸出: 1
print(nums.index(7)) # 輸出: 2

nums.sort()          # 原地排序
sorted_nums = sorted(nums)  # 返回新列表
nums.reverse()       # 原地反轉(zhuǎn)

注意sort()reverse() 會改變原列表,而 sorted() 返回新列表。

6. 列表推導式(List Comprehension)

列表推導式是 Python 中非常強大且簡潔的語法,它允許在一行代碼內(nèi)創(chuàng)建一個新的列表。相比于傳統(tǒng)的 for 循環(huán),列表推導式更加簡潔且執(zhí)行效率高。

# 基本語法:生成平方數(shù)列表
squares = [x**2 for x in range(5)]
print(squares)  # 輸出: [0, 1, 4, 9, 16]

# 帶條件的推導式:生成偶數(shù)的平方數(shù)列表
even_squares = [x**2 for x in range(5) if x % 2 == 0]
print(even_squares)  # 輸出: [0, 4, 16]

列表推導式的優(yōu)勢:

  • 簡潔性:可以用一行代碼替代多行。

  • 可讀性:語法清晰、易懂。

  • 性能:避免了手動使用 append()。

7. 淺拷貝(Shallow Copy)與深拷貝(Deep Copy)

在 Python 中,理解淺拷貝與深拷貝的前提,是理解一個核心事實:

Python 中的變量,本質(zhì)上保存的是對象的引用(reference),而不是對象本身。

因此,“拷貝”并不等價于“生成一個完全獨立的新對象”,是否真正獨立,取決于拷貝的層級。

7.1 對象、引用與容器的關系模型

先從一個最小示例理解引用關系:

a = [1, 2, 3]
b = a

此時:

  • ab 指向 同一個 list 對象

  • a 的任何修改,都會體現(xiàn)在 b

a[0] = 100
print(b)  # [100, 2, 3]

這不是拷貝,而是 引用綁定(aliasing)。

7.2 淺拷貝(Shallow Copy)

淺拷貝的定義:創(chuàng)建一個新的容器對象,但容器中保存的元素仍然是對原對象中元素的引用。

換句話說:

  • 外層容器是新的

  • 內(nèi)層對象是共享的

常見的淺拷貝方式

以下方式都會產(chǎn)生淺拷貝:

b = a.copy()
b = a[:]
b = list(a)

淺拷貝的行為示意

a = [[1, 2], [3, 4]]
b = a.copy()

內(nèi)存關系可以抽象為:

a ──? list ──? [ L1 , L2 ]
b ──? list ──? [ L1 , L2 ]
  • ab 是兩個不同的列表對象

  • 但它們內(nèi)部的 L1L2 指向同一個子列表對象

淺拷貝的典型“坑”

a = [[1, 2], [3, 4]]
b = a.copy()

b[0][0] = 100
print(a)  # [[100, 2], [3, 4]]

原因分析:

  • b[0]a[0] 指向同一子列表

  • 修改子列表,會影響所有引用它的容器

淺拷貝何時是安全的

列表中包含 不可變對象,后續(xù)操作只涉及 整體替換,不修改內(nèi)部對象

a = [1, 2, 3, "abc"]
b = a.copy()

b[0] = 100  # 不影響 a

print(a) # [1, 2, 3, 'abc']
print(b) # [100, 2, 3, 'abc']
7.3 深拷貝(Deep Copy)

深拷貝的定義:遞歸地復制對象本身以及其內(nèi)部引用的所有子對象,生成完全獨立的對象樹。

特點:

  • 外層容器獨立

  • 內(nèi)層對象也完全獨立

  • 修改任何層級都不會相互影響

深拷貝的標準方式

import copy

b = copy.deepcopy(a)

深拷貝的行為示意

a = [[1, 2], [3, 4]]
b = copy.deepcopy(a)

內(nèi)存模型:

a ──? list ──? [ L1 , L2 ]
b ──? list ──? [ L1' , L2' ]
  • L1 ≠ L1'

  • L2 ≠ L2'

深拷貝示例驗證

a = [[1, 2], [3, 4]]
b = copy.deepcopy(a)

b[0][0] = 100
print(a)  # [[1, 2], [3, 4]]
7.4 淺拷貝 vs 深拷貝的核心對比
維度淺拷貝深拷貝
外層容器新對象新對象
內(nèi)層對象共享引用完全獨立
性能相對較低
內(nèi)存占用
修改風險高(嵌套結(jié)構)極低

8. list * n與淺拷貝的本質(zhì)關系

a = [[0]] * 3

等價于:

sub = [0]
a = [sub, sub, sub]

因此:

a[0][0] = 1
print(a)  # [[1], [1], [1]]

這是淺拷貝的一種極端形式:

  • 外層列表新建

  • 內(nèi)層對象全部指向同一個引用

正確構造獨立子列表的方式

a = [[0] for _ in range(3)]

9. 列表的常見坑

淺拷貝問題

當使用 * 運算符復制包含可變元素的列表時,可能會發(fā)生意外的引用問題。例如:

a = [[1, 2]] * 3
a[0][0] = 100
print(a)  # 輸出: [[100, 2], [100, 2], [100, 2]]

原因:所有子列表都引用了同一個內(nèi)存地址,修改一個元素會影響所有子列表??梢允褂?copy.deepcopy() 來避免這種問題。

遍歷時修改列表

直接在遍歷列表時修改列表,可能會導致不預期的結(jié)果。例如:

nums = [1, 2, 3, 4]
for n in nums:
    if n % 2 == 0:
        nums.remove(n)  # 刪除偶數(shù)元素
print(nums)  # 輸出: [1, 3]

解決辦法:遍歷列表的副本,如 nums[:],或者使用列表推導式來過濾元素。

# 解決方法:遍歷副本
for n in nums[:]:
    if n % 2 == 0:
        nums.remove(n)

小結(jié)一下吧

  • 列表是 有序、可變 的數(shù)據(jù)容器,是 Python 數(shù)據(jù)結(jié)構的核心之一

  • 支持索引訪問、切片操作、原地修改和高效遍歷

  • 提供大量內(nèi)置方法,配合列表推導式可以寫出高效、優(yōu)雅的代碼

  • 常見風險點主要集中在:

    • 淺拷貝與引用共享

    • 遍歷過程中修改列表

    • 誤用 list * n 構造嵌套結(jié)構

熟練掌握列表,將為后續(xù)學習字典、集合、嵌套數(shù)據(jù)結(jié)構以及 JSON / 數(shù)據(jù)分析場景打下堅實基礎。

(三)字典(dict):鍵值映射的數(shù)據(jù)結(jié)構

字典(dict)是 Python 中最核心、使用頻率極高的一種內(nèi)置數(shù)據(jù)結(jié)構,用于存儲 鍵值對(key-value)映射關系。它通過 key 直接定位 value,而不是像列表那樣依賴下標位置,因此在表達“記錄型數(shù)據(jù)”“配置數(shù)據(jù)”“映射關系”時具有不可替代的優(yōu)勢。

從底層實現(xiàn)角度看,Python 字典基于 哈希表(Hash Table) 實現(xiàn),在絕大多數(shù)場景下,其查找、插入、刪除操作的時間復雜度都接近 O(1)。

1. 字典的設計思想

為什么需要字典?

列表適合解決以下問題:

  • 數(shù)據(jù) 有明確順序

  • 主要通過 位置(索引) 訪問

但在很多真實業(yè)務中,我們更關心的是:

  • “這個人的 年齡 是多少?”

  • “這個配置項 timeout 對應的值是多少?”

此時,如果仍然依賴下標訪問:

  • 可讀性差

  • 容易出錯

  • 不利于擴展和維護

字典的核心思想是:

用有意義的 key,直接映射到對應的 value

對比示例

# 使用列表表示用戶信息(語義不清晰)
user_list = ["Alice", 18, "alice@example.com"]

# 使用字典表示用戶信息(結(jié)構清晰)
user_dict = {
    "name": "Alice",
    "age": 18,
    "email": "alice@example.com"
}

字典的優(yōu)勢

  • 字段含義清晰,代碼自解釋

  • 不依賴順序,結(jié)構穩(wěn)定

  • 便于新增、刪除字段

  • 非常貼近 JSON / 配置文件 / 數(shù)據(jù)庫記錄的結(jié)構

2. 字典的基本使用

創(chuàng)建字典
# 使用花括號(最常見)
user = {"name": "Alice", "age": 18}

# 使用 dict 構造函數(shù)
user2 = dict(name="Bob", age=20)

# 從鍵值對列表創(chuàng)建
pairs = [("name", "Charlie"), ("age", 22)]
user3 = dict(pairs)
訪問 value
print(user["name"])        # Alice
print(user.get("age"))     # 18
重要約束說明
  • key 必須唯一:后定義的 key 會覆蓋之前的值

  • key 必須是不可變類型

    • 合法:strint、float、tuple

    • 非法:list、dict、set

# 合法
d = {(1, 2): "ok"}

# 非法(會拋出 TypeError)
d = {[1, 2]: "error"}

3. 字典的增刪改查(CRUD)

新增 / 修改(統(tǒng)一語法)
user["email"] = "alice@example.com"  # 新增
user["age"] = 19                       # 修改

字典不會區(qū)分“新增”和“修改”,是否存在 key 決定行為。

刪除元素
# 刪除指定 key
del user["email"]

# 刪除并返回 value
age = user.pop("age")
# 指定默認值,避免 KeyError
age = user.pop("age", None)
查詢
user["name"]                 # 不存在會拋 KeyError
user.get("email")             # 不存在返回 None
user.get("email", "N/A")     # 返回默認值
是否存在某個 key
"name" in user      # True / False
"email" not in user # True / False

4. 字典的遍歷方式

遍歷 key(默認行為)
for key in user:
    print(key, user[key])
遍歷 value
for value in user.values():
    print(value)
遍歷 key-value 對(最常用)
for key, value in user.items():
    print(key, value)
遍歷時的注意事項
  • 遍歷過程中 不建議修改字典結(jié)構(增刪 key)

  • 若需要修改,可先遍歷 list(user.keys())

5. 字典的常用方法與典型模式

常用方法速覽
user.keys()        # 所有 key(視圖對象)
user.values()      # 所有 value
user.items()       # (key, value) 對
user.clear()       # 清空字典
user.copy()        # 淺拷貝
setdefault:安全設置默認值
user.setdefault("age", 18)

等價于:

if "age" not in user:
    user["age"] = 18
update:批量更新
user.update({"email": "alice@example.com", "age": 20})
典型模式一:計數(shù)器
words = ["apple", "banana", "apple", "cherry"]
counter = {}

for word in words:
    counter[word] = counter.get(word, 0) + 1

print(counter)
典型模式二:分組
students = [
    ("Alice", "A"),
    ("Bob", "B"),
    ("Charlie", "A")
]

groups = {}
for name, grade in students:
    groups.setdefault(grade, []).append(name)

print(groups) #{'A': ['Alice', 'Charlie'], 'B': ['Bob']}

6. 字典的拷貝與可變性

淺拷貝(Shallow Copy)
d1 = {"a": [1, 2]}
d2 = d1.copy()

d2["a"].append(3)
print(d1)  # {'a': [1, 2, 3]}

淺拷貝只復制“引用”,不會復制內(nèi)部的可變對象。

深拷貝(Deep Copy)
import copy

d1 = {"a": [1, 2]}
d2 = copy.deepcopy(d1)

d2["a"].append(3)
print(d1)  # {'a': [1, 2]}

7. 字典與列表的組合(復雜結(jié)構建模)

列表中放字典
users = [
    {"name": "Alice", "age": 18},
    {"name": "Bob", "age": 20}
]

for user in users:
    print(user["name"], user["age"])
字典中放列表
grades = {
    "Alice": [90, 95, 88],
    "Bob": [75, 80, 82]
}

for name, scores in grades.items():
    avg = sum(scores) / len(scores)
    print(name, avg)
多層嵌套字典
users = {
    "Alice": {"age": 18, "email": "alice@example.com"},
    "Bob": {"age": 20, "email": "bob@example.com"}
}

print(users["Alice"]["email"])

小結(jié)一下吧

  • 字典是 鍵值映射容器,核心優(yōu)勢是按 key 快速訪問

  • 基于哈希表實現(xiàn),查找效率高

  • 支持完整的增刪改查操作

  • 提供豐富的方法與常見編程模式

  • 可與列表自由組合,構建任意復雜數(shù)據(jù)結(jié)構

熟練掌握字典,是后續(xù)學習 JSON 處理、配置管理、Web 開發(fā)、數(shù)據(jù)分析 的關鍵基礎。

(四)集合(set):去重與集合運算

集合(set)是 Python 中用于存儲唯一元素并支持數(shù)學集合運算的一種內(nèi)置數(shù)據(jù)結(jié)構。其核心價值在于:

  • 天然去重

  • 高效的成員判斷(O(1) 平均時間復雜度)

  • 直觀表達集合關系(交集、并集、差集等)

在實際開發(fā)中,集合常用于數(shù)據(jù)清洗、權限控制、標簽計算、關系判斷等場景。

1. 什么是集合(set)

集合的概念來源于數(shù)學中的集合:一組不重復的元素構成的整體。

# 使用大括號創(chuàng)建集合
fruits = {"apple", "banana", "cherry"}
print(fruits)
# 輸出順序不固定,例如:{'banana', 'apple', 'cherry'}

# 使用 set() 構造函數(shù)
nums = set([1, 2, 3, 2, 1])
print(nums)  # {1, 2, 3},自動去重

核心特性

  • 無序(unordered)不支持索引和切片操作;元素順序不穩(wěn)定,每次打印結(jié)果可能不同

  • 元素唯一(unique)相同元素只會保留一份,適合用于去重、排重邏輯

  • 成員判斷高效x in set 的時間復雜度為 O(1),明顯快于列表的 O(n)

  • 僅支持可哈希(hashable)類型合法元素:intfloat、str、tuple;非法元素:list、dictset

s = {(1, 2), "abc", 10}   # 合法
# s = {[1, 2], 3}         # TypeError: unhashable type: 'list'

2. 集合的創(chuàng)建方式

# 空集合(注意不能用 {})
empty_set = set()

# 從列表 / 元組 / 字符串創(chuàng)建
set([1, 2, 2, 3])
set(("a", "b", "a"))
set("hello")   # {'h', 'e', 'l', 'o'}

?? {} 表示空字典,而不是空集合。

3. 集合的基本操作

添加元素
nums = {1, 2, 3}
nums.add(4)
print(nums)  # {1, 2, 3, 4}
  • add():一次只能添加一個元素

刪除元素
nums.remove(2)    # 元素不存在會拋 KeyError
nums.discard(5)   # 元素不存在不會報錯
popped = nums.pop()  # 隨機刪除并返回一個元素
nums.clear()      # 清空集合

對比說明

方法元素不存在時使用建議
remove拋異常確保元素一定存在
discard不報錯更安全,推薦
pop隨機刪除不依賴具體元素
成員判斷
nums = {1, 2, 3}
print(2 in nums)       # True
print(5 not in nums)  # True

集合是做“是否存在”判斷的首選結(jié)構。

4. 集合運算(重點)

集合支持與數(shù)學集合一致的運算語義。

a = {1, 2, 3}
b = {3, 4, 5}
并集(Union)
print(a | b)
print(a.union(b))
# {1, 2, 3, 4, 5}
交集(Intersection)
print(a & b)
print(a.intersection(b))
# {3}
差集(Difference)
print(a - b)
print(a.difference(b))
# {1, 2}
對稱差集(Symmetric Difference)
print(a ^ b)
print(a.symmetric_difference(b))
# {1, 2, 4, 5}

5. 集合關系判斷

a = {1, 2}
b = {1, 2, 3}
print(a.issubset(b))      # True  子集
print(b.issuperset(a))   # True  超集
print(a.isdisjoint({4})) # True  是否無交集

常用于:權限校驗、條件覆蓋判斷。

6. 可變集合與不可變集合

set(可變)
  • 支持 add / remove

  • 不能作為字典的 key

frozenset(不可變)
fs = frozenset([1, 2, 3])
  • 一旦創(chuàng)建不可修改

  • 可作為字典 key 或集合元素

  • 常用于配置、常量集合

7. 典型應用場景

去重
nums = [1, 2, 2, 3, 4, 4]
unique_nums = list(set(nums))
權限 / 標簽判斷
user_roles = {"admin", "editor"}
required_roles = {"editor", "viewer"}

if user_roles & required_roles:
    print("有權限")
查找共同元素
team_a = {"Alice", "Bob", "Charlie"}
team_b = {"Bob", "David"}

common = team_a & team_b
數(shù)據(jù)差異分析
old_users = {1, 2, 3}
new_users = {2, 3, 4}

lost = old_users - new_users   # 流失用戶
added = new_users - old_users  # 新增用戶

8. 與列表、字典的對比

結(jié)構是否有序是否可重復核心用途
list順序數(shù)據(jù)
dict是(3.7+)key 不可重復映射關系
set去重 / 關系計算

小結(jié)一下吧

  • 集合是 無序、不重復 的數(shù)據(jù)結(jié)構

  • 成員判斷和集合運算效率極高

  • 核心能力:

    • 去重

    • 并 / 交 / 差 / 對稱差

    • 子集 / 超集判斷

  • 是處理“關系型數(shù)據(jù)”和“唯一性約束”的利器

掌握集合后,你可以用更簡潔、更高效的方式解決大量實際問題,為后續(xù)復雜數(shù)據(jù)結(jié)構和算法學習打下堅實基礎。

(五)元組(tuple):不可變序列

元組(tuple)是 Python 中的一種有序、不可變的序列類型。它在語法和使用方式上與列表(list)非常相似,但核心差異在于:一旦創(chuàng)建,元組的結(jié)構不能被修改

在實際開發(fā)中,元組常用于:

  • 表示固定含義的數(shù)據(jù)組合

  • 作為函數(shù)的多返回值

  • 作為字典的 key

  • 在某些場景下,替代列表以提升安全性和性能

1. 元組的基本概念

元組的核心特性

  • 有序(Ordered)元素按順序存儲,可以通過索引訪問

  • 不可變(Immutable)元組創(chuàng)建后,不能修改、添加、刪除元素

  • 可包含任意類型支持混合類型,支持嵌套結(jié)構

point = (10, 20)
info = ("Alice", 18, True, ["Python", "Go"])

元素訪問

print(point[0])   # 10
print(info[1])    # 18
print(info[-1])   # ['Python', 'Go']

元組 vs 列表(核心對比)

特性列表 list元組 tuple
是否可變可變不可變
是否有序
是否可作為 dict key
使用場景動態(tài)數(shù)據(jù)固定數(shù)據(jù)
語法[ ]( )

2. 創(chuàng)建元組的多種方式

使用圓括號(最常見)
t = (1, 2, 3)
省略圓括號(語法層面支持)
t = 1, 2, 3

? 常用于函數(shù)返回多個值或簡單賦值場景
? 不建議初學階段頻繁使用,容易降低可讀性

單元素元組(非常重要)
single = (5,)     # 正確
single2 = (5)     # 錯誤,這是整數(shù)

?? 結(jié)論是否為元組,關鍵不在于括號,而在于 逗號

使用tuple()構造函數(shù)
nums = [1, 2, 3]
chars = "abc"

print(tuple(nums))   # (1, 2, 3)
print(tuple(chars))  # ('a', 'b', 'c')

3. 元組的索引、切片與遍歷

索引訪問
t = (10, 20, 30, 40)

print(t[0])    # 10
print(t[-1])   # 40
切片操作
print(t[1:3])  # (20, 30)
print(t[:2])   # (10, 20)

注意

  • 切片返回的是 新元組

  • 原元組不會發(fā)生任何變化

遍歷元組
for item in t:
    print(item)

4. 元組的不可變性(核心理解)

不允許的操作
t = (1, 2, 3)

# t[0] = 10        # TypeError
# t.append(4)     # AttributeError
# del t[1]         # TypeError
元組中包含可變對象的情況(重點)
t = (1, [2, 3])
t[1].append(4)

print(t)  # (1, [2, 3, 4])

如何理解?

  • 元組不可變:指的是
    ?? t[1] 這個“引用”不能被替換

  • 列表可變
    ?? 列表內(nèi)部的內(nèi)容仍然可以修改

?? 一句話總結(jié):

元組保證的是“結(jié)構不變”,而不是“內(nèi)容絕對不變”

5. 元組解包(非常重要的能力)

基本解包
point = (10, 20)
x, y = point

print(x, y)  # 10 20
解包與函數(shù)返回值
def get_min_max(nums):
    return min(nums), max(nums)

min_val, max_val = get_min_max([3, 7, 1, 9])
print(min_val, max_val) # 1 9
使用*進行擴展解包
a, *b = (1, 2, 3, 4)
print(a)  # 1
print(b)  # [2, 3, 4]

6. 元組的常見應用場景

作為字典的 key
location = {}
location[(10, 20)] = "Home"

print(location)

原因:

  • 字典 key 必須是 不可變類型

  • 列表不能作為 key,元組可以

函數(shù)返回多個值(Pythonic 寫法)
def user_info():
    return "Alice", 18, True

name, age, active = user_info()
表示“業(yè)務含義固定”的數(shù)據(jù)
HOST = "localhost"
PORT = 8080
CONFIG = (HOST, PORT)

?? 語義層面表達:

“這組數(shù)據(jù)不應該被修改”

7. 元組的常用方法與內(nèi)置函數(shù)

元組方法非常少,這是其設計的一部分:

t = (1, 2, 2, 3)

print(t.count(2))   # 2
print(t.index(3))   # 3

常配合使用的內(nèi)置函數(shù):

len(t)
max(t)
min(t)
sum(t)

8. 元組與列表的深入對比

維度列表元組
內(nèi)存占用較高較低
創(chuàng)建速度較慢較快
安全性易被修改更安全
可讀性偏數(shù)據(jù)容器偏結(jié)構表達

小結(jié)一下吧

  • 元組是 不可變的有序序列

  • 與列表相似,但語義更偏向 “固定結(jié)構”

  • 常見用途:

    • 函數(shù)多返回值

    • 字典 key

    • 不可修改的配置數(shù)據(jù)

  • 支持:

    • 索引、切片、遍歷

    • 解包(非常重要)

(六)總結(jié):如何選擇合適的數(shù)據(jù)結(jié)構

? 至此,你已經(jīng)系統(tǒng)掌握 Python 的四大基礎數(shù)據(jù)結(jié)構::

  • 列表(list):有序、可變的序列

  • 字典(dict):鍵值映射

  • 集合(set):無序、不重復

  • 元組(tuple):不可變的序列

每種數(shù)據(jù)結(jié)構都有自己的特點和適用場景,選擇合適的數(shù)據(jù)結(jié)構能夠讓程序更高效、更易維護、更易理解。

1. 數(shù)據(jù)結(jié)構選擇對比表

數(shù)據(jù)結(jié)構特性使用場景注意事項
列表 list有序,可變,可包含任意類型保存順序數(shù)據(jù),循環(huán)處理,多次增刪改遍歷修改時要小心;切片返回新列表
字典 dict鍵值映射,key 唯一,可變記錄型數(shù)據(jù)(用戶信息、配置、狀態(tài)映射),快速查找key 必須不可變;get 可提供默認值
集合 set無序,不重復,高效成員判斷去重、集合運算、權限判斷、標簽判斷無索引;遍歷順序不可控
元組 tuple有序,不可變,可包含任意類型固定數(shù)據(jù)、函數(shù)多值返回、字典 key內(nèi)部可變對象仍可修改;不可修改元素

2. 如何選擇數(shù)據(jù)結(jié)構

選擇數(shù)據(jù)結(jié)構可以按以下幾個維度:

1?? 是否需要順序
  • 是 → 列表或元組

  • 否 → 集合或字典

2?? 是否需要唯一性
  • 是 → 集合

  • 否 → 列表或元組

3?? 是否需要通過名字訪問
  • 是 → 字典

  • 否 → 列表或集合

4?? 是否需要可變性
  • 可變 → 列表、字典、集合

  • 不可變 → 元組、不可變字典(擴展應用)

3. 常見組合場景

在實際開發(fā)中,這些數(shù)據(jù)結(jié)構經(jīng)常組合使用:

場景數(shù)據(jù)結(jié)構組合示例
多條記錄,每條記錄有多個字段列表 + 字典users = [{"name": "Alice", "age":18}, {"name": "Bob", "age":20}]
字典中某字段有多個值字典 + 列表grades = {"Alice":[90,95], "Bob":[80,82]}
去重的列表列表 + 集合unique_nums = list(set(nums))
函數(shù)返回多個值元組min_val, max_val = get_min_max([3,7,1,9])

4. 選用原則總結(jié)

  • 順序性優(yōu)先 → 列表/元組

  • 鍵值訪問優(yōu)先 → 字典

  • 唯一性 / 集合運算 → 集合

  • 數(shù)據(jù)固定不變 → 元組

  • 復雜嵌套 → 根據(jù)組合場景選擇最合適的容器

?? 核心思想:
數(shù)據(jù)結(jié)構是工具,目的是高效組織和操作數(shù)據(jù)。
不要只記語法,要根據(jù)問題特性選擇最合適的數(shù)據(jù)結(jié)構。

七、結(jié)構化數(shù)據(jù):Python 中的數(shù)據(jù)組織與處理

(一)為什么需要結(jié)構化數(shù)據(jù)建模

在前面的章節(jié)中,我們已經(jīng)學習了 Python 提供的基礎數(shù)據(jù)結(jié)構:列表(list)、字典(dict)、集合(set)和元組(tuple)。
這些數(shù)據(jù)結(jié)構在表達簡單數(shù)據(jù)時非常高效,但當我們開始處理真實世界中的業(yè)務數(shù)據(jù)時,很快就會發(fā)現(xiàn):僅靠基礎數(shù)據(jù)結(jié)構,往往難以支撐復雜數(shù)據(jù)的長期演進與工程化使用。

結(jié)構化數(shù)據(jù)建模,正是為了解決這一問題而出現(xiàn)的。

1. 現(xiàn)實世界數(shù)據(jù)的天然復雜性

現(xiàn)實中的數(shù)據(jù)幾乎從來不是“單值”的,而是具有以下典型特征:

  • 多字段(Multi-attribute)一個用戶不僅有名字,還包含年齡、郵箱、狀態(tài)、注冊時間等多個屬性;一個訂單不僅有金額,還包含商品列表、支付方式、物流信息等

  • 層級關系(Hierarchical)用戶包含地址信息;訂單包含多個商品;商品又包含規(guī)格、價格、庫存等子結(jié)構

  • 實體之間存在關聯(lián)一對多:一個用戶對應多個訂單;多對一:多個訂單屬于同一個商家;多對多:用戶與標簽、商品與分類

  • 狀態(tài)與行為并存數(shù)據(jù)不僅是“靜態(tài)描述”,還會涉及狀態(tài)變化(如訂單狀態(tài)流轉(zhuǎn)),以及業(yè)務行為(如校驗、計算、轉(zhuǎn)換)

這些特征決定了:現(xiàn)實世界的數(shù)據(jù),本質(zhì)上是結(jié)構化、層級化、并且語義明確的。

2. 基礎數(shù)據(jù)結(jié)構的能力邊界

Python 的 list 和 dict 是非常強大的工具,但它們的設計初衷是通用容器,而不是“領域模型”。

以字典為例:

  • 字典可以存任意鍵值對

  • 但它并不關心:

    • 這個字段是否必須存在

    • 這個字段應該是什么類型

    • 不同字段之間是否存在約束關系

隨著業(yè)務復雜度的上升,單純使用 dict 會逐漸暴露出問題:

  • 結(jié)構不透明字段依賴“約定”而非“定義”,閱讀代碼時無法一眼看出數(shù)據(jù)結(jié)構

  • 缺乏約束鍵名拼寫錯誤只能在運行時報錯,類型錯誤難以及早發(fā)現(xiàn)

  • 可維護性下降字段增加或調(diào)整會波及大量代碼,缺乏統(tǒng)一的數(shù)據(jù)入口

  • 業(yè)務語義缺失data["status"] == 1 本身無法說明業(yè)務含義,需要額外注釋或上下文才能理解

這意味著:基礎數(shù)據(jù)結(jié)構更適合“存數(shù)據(jù)”,但并不適合“表達數(shù)據(jù)含義”。

3. 從“數(shù)據(jù)容器”到“數(shù)據(jù)模型”的轉(zhuǎn)變

當系統(tǒng)規(guī)模逐漸擴大時,我們需要的不再只是一個“能裝東西的容器”,而是一個明確表達業(yè)務含義的數(shù)據(jù)模型(Data Model)。

數(shù)據(jù)模型關注的不僅是“數(shù)據(jù)長什么樣”,還包括:

  • 字段的業(yè)務語義

  • 字段之間的結(jié)構關系

  • 數(shù)據(jù)的合法性規(guī)則

  • 數(shù)據(jù)可支持的操作與行為

這種轉(zhuǎn)變,本質(zhì)上是:從“如何存數(shù)據(jù)”,升級為“如何描述現(xiàn)實世界中的對象”。

4. Python 在結(jié)構化數(shù)據(jù)建模上的天然優(yōu)勢

Python 之所以適合結(jié)構化數(shù)據(jù)建模,主要得益于以下能力:

  • 靈活的基礎數(shù)據(jù)結(jié)構(list / dict)

  • 完整的面向?qū)ο篌w系(Class)

  • 強大的類型注解支持

  • 內(nèi)建 JSON 處理能力

  • dataclass 等高級建模工具

這些能力,使得 Python 可以自然地完成從:原始數(shù)據(jù) → 半結(jié)構化數(shù)據(jù) → 領域模型 → 工程化數(shù)據(jù)體系的逐層演進。

小結(jié)一下吧

  • 現(xiàn)實世界的數(shù)據(jù)天然是結(jié)構化的

  • 基礎數(shù)據(jù)結(jié)構適合存儲,但不適合長期建模

  • 結(jié)構化數(shù)據(jù)建模是代碼工程化的必經(jīng)之路

  • Python 提供了從簡單到復雜的完整建模能力

在接下來的學習中,我們將從嵌套數(shù)據(jù)結(jié)構開始,逐步引入 JSON 處理,最終過渡到 基于 Class 的結(jié)構化數(shù)據(jù)建模,構建可維護、可擴展的 Python 數(shù)據(jù)體系。

(二)Python 中的嵌套結(jié)構化數(shù)據(jù)

在明確了為什么需要結(jié)構化數(shù)據(jù)建模之后,我們首先要面對的是:如何在 Python 中表達“多字段 + 多層級”的數(shù)據(jù)結(jié)構

在不引入面向?qū)ο笾埃琍ython 最直接、最常見的做法,就是使用嵌套的數(shù)據(jù)結(jié)構——即在 list 或 dict 中再包含 list 或 dict。

嵌套結(jié)構,是 Python 邁向結(jié)構化數(shù)據(jù)處理的第一步。

1. 嵌套結(jié)構化數(shù)據(jù)的基本思想

所謂嵌套結(jié)構,本質(zhì)上是:用 dict 表達“對象”,用 list 表達“集合”,并通過層級組合還原現(xiàn)實關系。

這種思想非常直觀,也幾乎不需要額外語法成本,因此被廣泛用于:

  • 接口返回數(shù)據(jù)

  • 配置文件

  • 臨時數(shù)據(jù)組織

  • JSON 原始載體

2. 字典嵌套字典:表達對象的層級屬性

適用場景:一個對象內(nèi)部存在子結(jié)構

user = {
    "id": 1001,
    "name": "Alice",
    "profile": {
        "age": 28,
        "email": "alice@example.com",
        "address": {
            "city": "Beijing",
            "zipcode": "100000"
        }
    }
}

結(jié)構理解

  • user:整體對象

  • profile:用戶的擴展屬性

  • address:更細粒度的子結(jié)構

這種結(jié)構清晰地反映了現(xiàn)實語義:地址不屬于用戶本身,而屬于用戶的資料信息。

訪問方式

city = user["profile"]["address"]["city"]

此時你已經(jīng)可以感受到第一個問題:

  • 訪問路徑依賴結(jié)構穩(wěn)定

  • 任意一層缺失,都會導致運行期錯誤

3. 字典嵌套列表:表達一對多關系

適用場景:一個主體擁有多個子對象

order = {
    "order_id": "ORD-001",
    "user_id": 1001,
    "items": [
        {"sku": "SKU-1", "price": 100, "quantity": 2},
        {"sku": "SKU-2", "price": 50, "quantity": 1}
    ]
}

結(jié)構理解

  • order 是訂單對象

  • items 是訂單下的商品集合

  • 每個商品仍然是一個“對象”

典型處理邏輯

total_amount = 0
for item in order["items"]:
    total_amount += item["price"] * item["quantity"]

此時一個非常關鍵的變化已經(jīng)出現(xiàn):業(yè)務計算邏輯,開始直接寫在“嵌套結(jié)構遍歷”之中

這是后續(xù)引入 Class 建模的重要動機。

4. 列表嵌套字典:同構對象的集合

適用場景:多個結(jié)構相同的對象

users = [
    {"id": 1, "name": "Alice", "active": True},
    {"id": 2, "name": "Bob", "active": False},
    {"id": 3, "name": "Charlie", "active": True}
]

遍歷與篩選

active_users = []
for user in users:
    if user["active"]:
        active_users.append(user)

這種結(jié)構在接口返回數(shù)據(jù)中極為常見,但它也暴露了嵌套結(jié)構的本質(zhì)問題之一:

  • 字段完全依賴字符串約定

  • 沒有任何顯式結(jié)構定義

  • 錯誤只能在運行期發(fā)現(xiàn)

5. 多層混合嵌套:真實系統(tǒng)中的常態(tài)

在真實系統(tǒng)中,嵌套結(jié)構往往是多種形式的組合:

response = {
    "code": 0,
    "data": {
        "user": {
            "id": 1001,
            "orders": [
                {
                    "order_id": "ORD-001",
                    "items": [
                        {"sku": "SKU-1", "price": 100}
                    ]
                }
            ]
        }
    }
}

訪問路徑示例

sku = response["data"]["user"]["orders"][0]["items"][0]["sku"]

此類代碼的特征非常明顯:

  • 訪問鏈路極長

  • 強依賴數(shù)據(jù)結(jié)構細節(jié)

  • 可讀性和可維護性迅速下降

6. 防御式訪問:必要但有限的改進

為了避免異常,開發(fā)中常使用防御式寫法:

user = response.get("data", {}).get("user", {})
orders = user.get("orders", [])

if orders:
    first_order = orders[0]

這種方式可以:

  • 降低運行期錯誤概率

  • 提高代碼健壯性

但需要清醒認識到:防御式訪問解決的是“不崩潰”,而不是“結(jié)構合理”。

7. 嵌套結(jié)構的工程性問題總結(jié)

通過以上示例,可以清晰看到嵌套結(jié)構在工程中的局限:

  • 結(jié)構定義分散:數(shù)據(jù)結(jié)構存在于代碼路徑中,而非集中定義

  • 業(yè)務語義缺失:字段只是字符串,無法承載規(guī)則和含義

  • 強耦合:結(jié)構變更會影響大量訪問代碼

  • 邏輯與數(shù)據(jù)混雜:業(yè)務計算被迫寫在遍歷和索引中

當代碼中大量出現(xiàn)如下形式時:

data["a"]["b"][0]["c"]["d"]

通常意味著:嵌套結(jié)構已經(jīng)達到了可維護性的上限。

8. 嵌套結(jié)構在整體體系中的正確定位

嵌套 dict / list 并不是“錯誤做法”,而是階段性工具

使用場景評價
原始 JSON 承載合適
臨時數(shù)據(jù)處理合適
腳本 / Demo合適
核心業(yè)務模型不合適
長期維護系統(tǒng)不合適

它更適合作為:數(shù)據(jù)的“中間形態(tài)”,而非最終模型。

小結(jié)一下吧

  • 嵌套結(jié)構是 Python 表達復雜數(shù)據(jù)的基礎方式

  • 它通過 dict + list 組合還原現(xiàn)實關系

  • 隨著層級加深,維護成本迅速上升

  • 這正是引入 JSON 規(guī)范與 Class 建模的直接動因

接著我們將進入 半結(jié)構化數(shù)據(jù):JSON 在 Python 中的處理,你會發(fā)現(xiàn):JSON 的便利性,并沒有從根本上解決嵌套結(jié)構的問題,而只是讓它“標準化”了。

(三)半結(jié)構化數(shù)據(jù):JSON 在 Python 中的處理

在上一節(jié)中,我們已經(jīng)看到:通過 list 與 dict 的嵌套,Python 可以完整表達復雜數(shù)據(jù)結(jié)構,但可維護性迅速下降。

在真實工程中,這類嵌套結(jié)構往往并不是“手寫”的,而是來自:

  • HTTP 接口返回

  • 配置文件

  • 消息隊列

  • 日志或存儲系統(tǒng)

這些數(shù)據(jù)最常見的載體形式,就是 JSON(JavaScript Object Notation)。

1. 什么是半結(jié)構化數(shù)據(jù)

從數(shù)據(jù)組織角度看,數(shù)據(jù)大致可以分為三類:

  • 非結(jié)構化數(shù)據(jù):文本、圖片、音頻

  • 結(jié)構化數(shù)據(jù):表結(jié)構、強約束模型

  • 半結(jié)構化數(shù)據(jù):結(jié)構存在,但約束較弱

JSON 正是典型的半結(jié)構化數(shù)據(jù)格式,其特點是:

  • 結(jié)構清晰(層級、鍵值)

  • 可嵌套

  • 無強類型約束

  • 字段可選、可變

這使得 JSON 非常適合數(shù)據(jù)交換,但不適合直接作為業(yè)務模型。

2. JSON 的數(shù)據(jù)模型與 Python 的映射關系

JSON 本身支持的數(shù)據(jù)類型非常有限:

JSON 類型Python 對應類型
objectdict
arraylist
stringstr
numberint / float
booleanbool
nullNone

也正因如此,JSON 在 Python 中的本質(zhì)就是:嵌套的 dict 與 list

換句話說:JSON 并沒有解決嵌套結(jié)構的問題,只是把它“標準化”了。

3. Python 中的 JSON 解析(反序列化)

Python 內(nèi)置 json 模塊,用于 JSON 與 Python 對象之間的轉(zhuǎn)換。

import json

json_str = '''
{
    "id": 1001,
    "name": "Alice",
    "active": true,
    "roles": ["admin", "editor"]
}
'''

data = json.loads(json_str)

解析后:

  • data 是一個 dict

  • 所有字段完全不受約束

  • 訪問方式與普通嵌套結(jié)構一致

name = data["name"]
roles = data["roles"]

4. 從文件加載 JSON 數(shù)據(jù)

JSON 文件是配置與數(shù)據(jù)交換的常見形式(這里暫時先理解,后續(xù)這部分會在新博客單獨講解):

import json

with open("config.json", "r", encoding="utf-8") as f:
    config = json.load(f)

此時你獲得的是:

  • 一個完全動態(tài)的嵌套結(jié)構

  • 所有字段都只能“運行期驗證”

5. JSON 的典型嵌套結(jié)構示例

考慮一個真實接口返回示例:

response = {
    "code": 0,
    "message": "success",
    "data": {
        "user": {
            "id": 1001,
            "name": "Alice",
            "orders": [
                {
                    "order_id": "ORD-001",
                    "items": [
                        {"sku": "SKU-1", "price": 100, "quantity": 2}
                    ]
                }
            ]
        }
    }
}

業(yè)務代碼往往會這樣寫:

orders = response["data"]["user"]["orders"]
first_item_price = orders[0]["items"][0]["price"]

到這里,你應該已經(jīng)非常熟悉這種訪問模式——它與嵌套結(jié)構沒有任何本質(zhì)區(qū)別。

6. JSON 帶來的“結(jié)構假象”

JSON 的一個常見誤區(qū)是:“有格式 ≠ 有模型”

雖然 JSON 看起來“結(jié)構清晰”,但它存在以下天然問題:

  • 字段完全不受約束缺字段不會報錯,多字段也不會報錯

  • 類型不可靠price 可能是數(shù)字,也可能是字符串,錯誤只能在運行期暴露

  • 業(yè)務語義缺失status = 1 的含義無法自解釋,需要依賴外部文檔或注釋

  • 結(jié)構變更極具破壞性任意字段調(diào)整都會影響訪問鏈

JSON 解決的是“數(shù)據(jù)如何傳輸”,而不是“數(shù)據(jù)如何使用。

7. 防御式 JSON 解析的常見寫法

為了避免運行期異常,代碼中常見如下寫法:

data = response.get("data", {})
user = data.get("user", {})
orders = user.get("orders", [])

if orders:
    order_id = orders[0].get("order_id")

這種寫法與上面講的嵌套方式依舊沒啥區(qū)別,更重要的是:仍然沒有一個“明確的數(shù)據(jù)模型”。

8. JSON 在工程體系中的正確角色

在成熟系統(tǒng)中,JSON 的定位應當非常明確:

角色是否合適
網(wǎng)絡傳輸格式非常合適
配置文件合適
接口輸入 / 輸出合適
業(yè)務內(nèi)部模型不合適
核心領域?qū)ο?/span>不合適

JSON 更適合作為:系統(tǒng)邊界上的數(shù)據(jù)格式,而非系統(tǒng)內(nèi)部的結(jié)構表達。

系統(tǒng)引入結(jié)構化建模的階段,Python 給出的答案是:

  • Class

  • dataclass

  • 明確的數(shù)據(jù)模型定義

  • JSON ↔ Model 的轉(zhuǎn)換邊界

小結(jié)一下吧

  • JSON 是典型的半結(jié)構化數(shù)據(jù)格式

  • 在 Python 中,JSON 本質(zhì)仍是嵌套 dict / list

  • JSON 適合傳輸,不適合直接承載業(yè)務模型

  • 防御式解析無法從根本上解決結(jié)構問題

  • 這直接引出了:為什么必須使用 Class 進行結(jié)構化建模

(四)面向?qū)ο蟮慕Y(jié)構化建模:Class 的引入

在前面的講解中無論哪一步,數(shù)據(jù)始終以同一種形態(tài)存在:dict,只是內(nèi)容變“干凈”了而已。

接下來將通過一組連續(xù)示例說明:為什么必須引入 Class,以及 Class 在工程中應該如何使用。

1. 問題起點:業(yè)務邏輯正在“侵蝕”數(shù)據(jù)結(jié)構

先看一個非常真實的場景,接口返回訂單數(shù)據(jù):

order_data = {
    "order_id": "ORD-001",
    "price": "100",
    "quantity": 2
}

業(yè)務中需要計算訂單金額,代碼往往這樣寫:

total_amount = int(order_data["price"]) * order_data["quantity"]

這段代碼沒有語法問題,但存在嚴重的工程隱患

  • 類型轉(zhuǎn)換是“臨時的”

  • 規(guī)則是“隱含的”

  • 任意地方都可以重復這段邏輯

此時系統(tǒng)出現(xiàn)了第一個危險信號:業(yè)務規(guī)則開始散落在 dict 操作中

2. 第一次建模:用 Class 固定結(jié)構與類型

我們引入最基礎的 Class,僅做一件事:把“字段定義”和“類型規(guī)則”集中到一個地方

class Order:
    def __init__(self, order_id, price, quantity):
        self.order_id = order_id
        self.price = int(price)
        self.quantity = int(quantity)

此時發(fā)生了三件非常重要的變化:

  • 結(jié)構集中Order 明確有哪些字段

  • 類型前置類型轉(zhuǎn)換只發(fā)生一次

  • 使用成本下降后續(xù)代碼不再關心字段細節(jié)

業(yè)務代碼變?yōu)椋?/p>

order = Order("ORD-001", "100", 2)

3. 第二次建模:讓業(yè)務行為回歸模型

現(xiàn)在再看金額計算邏輯。如果繼續(xù)寫在外部:

total = order.price * order.quantity

雖然比 dict 好,但語義仍然分散。正確的工程做法是:只要邏輯“屬于對象”,就應進入對象本身

class Order:
    def __init__(self, order_id, price, quantity):
        self.order_id = order_id
        self.price = int(price)
        self.quantity = int(quantity)

    def total_amount(self):
        return self.price * self.quantity

此時:

  • 金額計算的業(yè)務含義被明確命名

  • 外部代碼無需關心實現(xiàn)細節(jié)

total = order.total_amount()

4. 工程規(guī)范一:Class 不是“數(shù)據(jù)殼”,而是“業(yè)務單元”

到這里,可以明確一個重要規(guī)范

一個 Class 不應該只是 dict 的替代品,而應該是一個“可用對象”。

如果一個 Class:

  • 只有屬性

  • 沒有任何方法

那它的價值是非常有限的。

5. 第三次建模:讓 Class 成為解析與清洗的邊界

回到真實輸入數(shù)據(jù)的問題。接口返回的往往是 不可信 JSON

raw_data = {
    "order_id": "ORD-001",
    "price": None,
    "quantity": "2"
}

工程上正確的做法是:讓 Class 成為“不可信數(shù)據(jù) → 可信對象”的邊界

class Order:
    def __init__(self, data: dict):
        self.order_id = data.get("order_id")
        self.price = self._to_int(data.get("price"), default=0)
        self.quantity = self._to_int(data.get("quantity"), default=1)

    def _to_int(self, value, default=0):
        try:
            return int(value)
        except (TypeError, ValueError):
            return default

此時:

  • 所有防御邏輯被“封裝”

  • 外部世界不再處理臟數(shù)據(jù)

  • 構造完成的對象即“可用對象”

6. 工程規(guī)范二:業(yè)務代碼只接觸“可信對象”

正確的調(diào)用方式應當是:

order = Order(raw_data)
total = order.total_amount()

而不是:

# ? 不推薦
total = int(raw_data["price"]) * int(raw_data["quantity"])

規(guī)范總結(jié):

解析、清洗、校驗,必須發(fā)生在模型內(nèi)部
業(yè)務代碼不應再做任何字段判斷

7. 第四次建模:用對象組合替代嵌套結(jié)構

考慮一個更真實的訂單結(jié)構:

raw_order = {
    "order_id": "ORD-001",
    "items": [
        {"sku": "SKU-1", "price": "100"},
        {"sku": "SKU-2", "price": "50"}
    ]
}

如果繼續(xù)使用嵌套 dict:

total = 0
for item in raw_order["items"]:
    total += int(item["price"])

正確的建模方式是:用對象組合替代嵌套結(jié)構

class OrderItem:
    def __init__(self, data):
        self.sku = data.get("sku")
        self.price = int(data.get("price", 0))

class Order:
    def __init__(self, data):
        self.order_id = data.get("order_id")
        self.items = [OrderItem(item) for item in data.get("items", [])]

    def total_amount(self):
        return sum(item.price for item in self.items)

此時,結(jié)構發(fā)生了質(zhì)變:

  • 嵌套 dict → 對象關系

  • 遍歷邏輯 → 模型內(nèi)部能力

8. 工程規(guī)范三:嵌套數(shù)據(jù) ≠ 嵌套 dict,而是“對象層級”

這是結(jié)構化建模中非常重要的一條規(guī)范

嵌套關系應通過“對象組合”表達,而不是嵌套 dict 訪問路徑。

一旦遵循這條規(guī)范:

  • 訪問路徑顯著變短

  • 代碼可讀性成倍提升

  • 結(jié)構演進成本大幅下降

小結(jié)一下吧

通過示例可以總結(jié)出 Class 建模的核心工程規(guī)范:

  • Class 是模型,不是數(shù)據(jù)殼

  • 結(jié)構、語義、行為必須統(tǒng)一

  • 解析與清洗是模型的職責

  • 業(yè)務代碼只操作可信對象

  • 嵌套關系用對象組合表達

到這里,你已經(jīng)完成了:

從“操作數(shù)據(jù)” → “使用模型” 的關鍵轉(zhuǎn)變

(五)復雜對象組合與領域建模

在真實系統(tǒng)中,所謂“復雜數(shù)據(jù)”,并不僅僅是 層級多,而是同時具備:

  • 多層嵌套結(jié)構

  • 不同子結(jié)構承擔不同職責

  • 局部規(guī)則 + 全局規(guī)則并存

  • 數(shù)據(jù)來自不可信邊界(接口 / MQ / DB)

這一節(jié),我們用一個 接近真實電商/交易系統(tǒng)的數(shù)據(jù)模型,完整展示 Python 中的復雜領域建模方式。

1. 原始輸入:近真實系統(tǒng)級 JSON 結(jié)構

這是一個 近真實工程中常見復雜度 的訂單數(shù)據(jù)(已適度抽象):

raw_order = {
    "order_id": "ORD-9001",
    "user": {
        "id": "U-1001",
        "profile": {
            "name": "Alice",
            "level": "VIP"
        }
    },
    "items": [
        {
            "sku": "SKU-1",
            "pricing": {
                "unit_price": "100",
                "currency": "CNY"
            },
            "quantity": 2,
            "discounts": [
                {"type": "PROMOTION", "amount": "10"},
                {"type": "VIP", "amount": "5"}
            ]
        }
    ],
    "payment": {
        "method": "CREDIT_CARD",
        "transactions": [
            {"tx_id": "TX-1", "amount": "185"},
            {"tx_id": "TX-2", "amount": "10"}
        ]
    }
}

特點:

  • 最深層級:5 層

  • 同時包含:列表嵌套 + 對象嵌套

  • 金額、規(guī)則、行為全部混在 JSON 中

如果直接用 dict 操作,這類代碼幾乎不可維護。

2. 第一步:識別領域與聚合邊界(不是拆字段)

復雜建模的第一步不是寫類,而是劃分領域?qū)ο?/strong>。

從業(yè)務語義出發(fā):

JSON 片段領域?qū)ο?/th>
orderOrder(聚合根)
userUser
profileUserProfile
itemsOrderItem
pricingPricing
discountsDiscount
paymentPayment
transactionsPaymentTransaction

原則:

只要一個子結(jié)構有“獨立業(yè)務含義”,就值得一個 Class。

3. 底層值對象(Value Object)建模

Discount(最小業(yè)務單元)

class Discount:
    def __init__(self, data):
        self.type = data.get("type")
        self.amount = int(data.get("amount", 0))

Pricing(價格不是一個字段,而是一組規(guī)則)

class Pricing:
    def __init__(self, data):
        self.unit_price = int(data.get("unit_price", 0))
        self.currency = data.get("currency")

    def total(self, quantity):
        return self.unit_price * quantity

4. OrderItem:多層對象的“局部聚合”

class OrderItem:
    def __init__(self, data):
        self.sku = data.get("sku")
        self.quantity = int(data.get("quantity", 1))

        self.pricing = Pricing(data.get("pricing", {}))
        self.discounts = [
            Discount(d) for d in data.get("discounts", [])
        ]

    def discount_amount(self):
        return sum(d.amount for d in self.discounts)

    def subtotal(self):
        return self.pricing.total(self.quantity) - self.discount_amount()

注意這里已經(jīng)出現(xiàn)了領域行為協(xié)同

  • 折扣規(guī)則不在 Order

  • 價格規(guī)則不在 Order

  • OrderItem 自洽完成金額計算

5. 用戶領域:嵌套對象中的語義建模

class UserProfile:
    def __init__(self, data):
        self.name = data.get("name")
        self.level = data.get("level")

    def is_vip(self):
        return self.level == "VIP"


class User:
    def __init__(self, data):
        self.user_id = data.get("id")
        self.profile = UserProfile(data.get("profile", {}))

6. 支付領域:獨立聚合,不混入訂單邏輯

class PaymentTransaction:
    def __init__(self, data):
        self.tx_id = data.get("tx_id")
        self.amount = int(data.get("amount", 0))

class Payment:
    def __init__(self, data):
        self.method = data.get("method")
        self.transactions = [
            PaymentTransaction(tx)
            for tx in data.get("transactions", [])
        ]

    def paid_amount(self):
        return sum(tx.amount for tx in self.transactions)

7. Order:真正的“領域聚合根”

class Order:
    def __init__(self, data):
        self.order_id = data.get("order_id")

        self.user = User(data.get("user", {}))
        self.items = [OrderItem(i) for i in data.get("items", [])]
        self.payment = Payment(data.get("payment", {}))

    def order_amount(self):
        return sum(item.subtotal() for item in self.items)

    def is_fully_paid(self):
        return self.payment.paid_amount() >= self.order_amount()

注意:

  • Order 不參與任何底層計算

  • Order 只做“聚合協(xié)調(diào)”

  • 各領域職責清晰、不交叉

8. 工程級規(guī)范總結(jié)(復雜場景)

這一示例隱含了一套非常重要的工程規(guī)范

規(guī)范一:不要讓聚合根“變胖”
  • 金額計算下沉到 OrderItem

  • 折扣規(guī)則不寫在 Order

規(guī)范二:多層嵌套 ≠ 多層 dict
  • 每一層都是對象

  • 每一層都有行為

規(guī)范三:領域隔離
  • Payment 不知道 OrderItem 的存在

  • Order 不知道 Discount 的細節(jié)

規(guī)范四:結(jié)構變化可控
  • JSON 結(jié)構變化只影響局部 Class

這一節(jié)完成的不是“示例升級”,而是復雜度躍遷

  • 從 2 層嵌套 → 5 層嵌套

  • 從數(shù)據(jù)組合 → 領域協(xié)作

  • 從“能跑” → “可演進、可維護”

你現(xiàn)在已經(jīng)具備:用 Python Class 構建真實業(yè)務領域模型的能力

(六)JSON ↔ Class 的雙向轉(zhuǎn)換:邊界層與 DTO 設計

在 (五) 中,我們已經(jīng)構建了一套復雜、內(nèi)聚、可演進的領域模型。但此時如果直接將這些 Class 用在接口層或存儲層,會立即遇到新的問題:

  • 接口層需要 JSON

  • MQ / RPC 需要可序列化結(jié)構

  • 數(shù)據(jù)庫存儲結(jié)構與領域模型不一致

  • 外部系統(tǒng)字段經(jīng)常變動

這引出了一個非常重要的工程問題領域模型不應直接暴露在系統(tǒng)邊界。

1. 為什么不能讓領域模型“裸奔”到邊界

一個常見但危險的做法是:

json.dumps(order.__dict__)

這種方式存在嚴重問題:

  • 結(jié)構不可控:私有字段、內(nèi)部狀態(tài)一并暴露

  • 語義污染:內(nèi)部對象結(jié)構被外部依賴

  • 變更風險極高:內(nèi)部模型調(diào)整會破壞接口

  • 無法做版本治理:接口字段無法演進

工程結(jié)論:領域模型 ≠ 接口數(shù)據(jù)模型

2. 邊界層的核心職責

在工程上,通常需要一個邊界層(Boundary Layer),它負責:

  • JSON → DTO

  • DTO → Domain Model

  • Domain Model → DTO

  • DTO → JSON

其中,DTO(Data Transfer Object) 是核心中介。

3. DTO 的設計原則(非常重要)

DTO 與領域模型的關系,應遵循以下原則:

  • 只包含數(shù)據(jù),不包含業(yè)務行為

  • 結(jié)構扁平,面向接口需求

  • 允許字段冗余或命名不一致

  • 變化頻率遠高于領域模型

  • 邊界轉(zhuǎn)換集中化

    一個成熟系統(tǒng)中,應當遵循:

    所有 JSON ↔ Domain 的轉(zhuǎn)換,都集中在邊界層完成

    而不是:Controller 中拼 dict; Service 中解析字段; Model 中關心接口格式

3.1 示例:為 Order 定義輸入 DTO

接口輸入 JSON:

{
  "order_id": "ORD-9001",
  "user_id": "U-1001",
  "items": [
    {
      "sku": "SKU-1",
      "unit_price": "100",
      "quantity": 2
    }
  ]
}

對應 DTO:

class OrderCreateDTO:
    def __init__(self, data):
        self.order_id = data.get("order_id")
        self.user_id = data.get("user_id")
        self.items = data.get("items", [])

DTO 的特點:

  • 不做復雜解析

  • 不包含嵌套對象建模

  • 只服務接口需求

3.2 DTO → Domain Model(反序列化邊界)

將 DTO 轉(zhuǎn)換為領域模型,是邊界層的核心工作之一。

class OrderFactory:
    @staticmethod
    def from_create_dto(dto: OrderCreateDTO):
        raw = {
            "order_id": dto.order_id,
            "user": {"id": dto.user_id},
            "items": [
                {
                    "sku": item["sku"],
                    "pricing": {"unit_price": item["unit_price"]},
                    "quantity": item["quantity"],
                    "discounts": []
                }
                for item in dto.items
            ]
        }
        return Order(raw)

注意幾點:

  • DTO 不知道領域模型

  • 領域模型不依賴 DTO

  • 轉(zhuǎn)換邏輯集中在 Factory / Assembler 中

3.3 Domain Model → DTO(序列化邊界)

對外輸出時,同樣不能直接暴露領域模型。

class OrderResponseDTO:
    def __init__(self, order: Order):
        self.order_id = order.order_id
        self.total_amount = order.order_amount()
        self.paid = order.is_fully_paid()

再由 DTO 轉(zhuǎn)為 JSON:

response = json.dumps(order_response_dto.__dict__)

3.4. 復雜結(jié)構下的 DTO 拆分策略

當結(jié)構進一步復雜時,應避免:

class BigDTO:
    ...

而采用:

  • OrderDTO

  • ItemDTO

  • PaymentDTO

再由 Assembler 負責組合。

3.5 防腐層(Anti-Corruption Layer)視角

在對接外部系統(tǒng)時,DTO 還承擔著一個更重要的角色:

防止外部模型“污染”內(nèi)部領域模型

字段改名、結(jié)構變更、類型異常,都被限制在 DTO 層。

小結(jié)一下吧

通過本節(jié),你應該建立起以下清晰認知:

  • 領域模型只服務領域邏輯

  • DTO 是系統(tǒng)邊界的語言

  • JSON 永遠不應直接進入領域模型

  • Factory / Assembler 是關鍵角色

  • 邊界清晰,系統(tǒng)才能長期演進

(七)使用 dataclass 與類型系統(tǒng)增強結(jié)構化建模

在前面的分享中,我們已經(jīng)用“原生 Class”完成了復雜領域建模。但你可能已經(jīng)感受到幾個現(xiàn)實問題:

  • __init__ 代碼大量重復

  • 字段類型只能靠約定

  • 對象結(jié)構難以一眼看清

  • 重構時缺乏工具輔助

這正是 dataclass 與類型系統(tǒng) 登場的時機。

1. 為什么在復雜建模階段引入 dataclass

dataclass 并不是“語法糖”,而是結(jié)構化建模的工程工具。

它解決的核心問題是:

問題原生 Classdataclass
字段聲明分散在 __init__集中聲明
類型表達隱式顯式
可讀性中等
維護成本

工程結(jié)論:當模型成為系統(tǒng)核心資產(chǎn)時,必須使用 dataclass 或等價機制。

2. 從原生 Class 到 dataclass:逐步演進

先看之前寫的的一個典型類:

class Discount:
    def __init__(self, data):
        self.type = data.get("type")
        self.amount = int(data.get("amount", 0))

使用 dataclass 重構后:

from dataclasses import dataclass

@dataclass
class Discount:
    type: str
    amount: int

但這只是第一步,真實工程不會直接這樣寫。

3. dataclass 中的構造邊界:__post_init__

在領域模型中:

  • 字段是“結(jié)構”

  • 校驗、轉(zhuǎn)換是“規(guī)則”

dataclass 提供 __post_init__ 來承載規(guī)則。

from dataclasses import dataclass

@dataclass
class Discount:
    type: str
    amount: int

    def __post_init__(self):
        self.amount = int(self.amount)

規(guī)范:類型轉(zhuǎn)換、校驗邏輯應放在 __post_init__,而不是外部代碼。

4. 復雜對象中的 dataclass 組合

重構 Pricing:

from dataclasses import dataclass

@dataclass
class Pricing:
    unit_price: int
    currency: str = "CNY"

    def total(self, quantity: int) -> int:
        return self.unit_price * quantity

OrderItem:

from dataclasses import dataclass, field
from typing import List

@dataclass
class OrderItem:
    sku: str
    pricing: Pricing
    quantity: int = 1
    discounts: List[Discount] = field(default_factory=list)

    def subtotal(self) -> int:
        discount = sum(d.amount for d in self.discounts)
        return self.pricing.total(self.quantity) - discount

此時,模型結(jié)構已經(jīng)一眼可讀。

5. 類型系統(tǒng)帶來的“隱性收益”

引入類型標注后,產(chǎn)生的收益包括:

  • IDE 自動補全

  • 靜態(tài)檢查(mypy / pyright)

  • 重構安全性

  • 模型即文檔

例如:

def calculate_total(items: List[OrderItem]) -> int:
    ...

類型本身就表達了設計意圖

6. dataclass 與不可變建模(高級用法)

在部分領域中(如支付、賬務),對象應當是不可變的。

@dataclass(frozen=True)
class PaymentTransaction:
    tx_id: str
    amount: int

不可變對象的工程意義:

  • 防止狀態(tài)被隨意修改

  • 更容易推理

  • 更適合并發(fā)場景

7. dataclass ≠ DTO:職責仍然要分清

一個常見誤區(qū)是:“既然 dataclass 很方便,那 DTO 也用它吧?”

可以,但要遵守原則:

對象是否可用 dataclass是否包含行為
DTO可以不應該
Domain Model強烈推薦必須

關鍵點不是工具,而是職責。

8. 工程規(guī)范:領域模型的現(xiàn)代 Python 寫法

綜合前面內(nèi)容,可以形成一套明確規(guī)范:

  • 領域模型使用 dataclass

  • 字段必須有類型

  • 規(guī)則寫在方法或 __post_init__

  • 嵌套關系通過類型表達

  • 不可變對象優(yōu)先用于關鍵領域

小結(jié)一下吧

通過 dataclass 與類型系統(tǒng):

  • 模型從“能用”變?yōu)?ldquo;可靠”

  • 結(jié)構從“隱式”變?yōu)?ldquo;顯式”

  • 重構從“危險”變?yōu)?ldquo;可控”

(八)領域模型與數(shù)據(jù)庫模型的邊界:ORM 與持久化設計

前面整體學習了解了:

  • 復雜領域建模

  • 明確的邊界與 DTO

  • dataclass + 類型系統(tǒng)增強

系統(tǒng)幾乎不可避免地會進入一個危險階段:為了“省事”,開始讓領域模型向數(shù)據(jù)庫結(jié)構妥協(xié)。

這一節(jié)的目標,是明確劃清領域模型與持久化模型的邊界。

1. 一個常見但致命的誤區(qū)

很多系統(tǒng)會出現(xiàn)如下代碼風格:

class Order(Base):
    __tablename__ = "orders"

    id = Column(String, primary_key=True)
    total_amount = Column(Integer)

看似優(yōu)雅,實際上隱藏著幾個問題:

  • 領域模型被 ORM 污染

  • 數(shù)據(jù)庫結(jié)構決定了領域結(jié)構

  • 業(yè)務規(guī)則被擠出模型

工程結(jié)論:ORM Model ≠ Domain Model

2. 三種模型的職責劃分(必須牢記)

在成熟系統(tǒng)中,通常存在三類模型:

模型類型關注點變化頻率
DTO接口 / 邊界
Domain Model業(yè)務規(guī)則
Persistence Model(ORM)表結(jié)構

它們解決的是完全不同的問題

3. 領域模型為什么不應該“繼承 ORM”

原因并不抽象:

  • 數(shù)據(jù)庫字段不是業(yè)務語言

  • ORM 強制扁平化結(jié)構

  • 懶加載/會話污染領域行為

  • 測試復雜度急劇上升

領域模型應當:

  • 與數(shù)據(jù)庫無關

  • 可以脫離 ORM 獨立運行與測試

4. 正確的工程結(jié)構示意

一個合理的工程分層應當是:

領域模型永遠不直接操作數(shù)據(jù)庫。

5. ORM Model:只做“表的映射”

以 SQLAlchemy 為例(僅作為概念說明):

class OrderORM(Base):
    __tablename__ = "orders"

    order_id = Column(String, primary_key=True)
    total_amount = Column(Integer)

特點:

  • 結(jié)構與表一一對應

  • 沒有業(yè)務行為

  • 允許妥協(xié)命名

6. Repository:連接領域與持久化的橋梁

Repository 是最關鍵、但最容易被忽略的一層

class OrderRepository:
    def save(self, order: Order):
        raise NotImplementedError

    def get(self, order_id: str) -> Order:
        raise NotImplementedError

領域?qū)又灰蕾?接口,而不是實現(xiàn)。

7. ORM → Domain 的裝配(反序列化)

class OrderRepositoryImpl(OrderRepository):
    def get(self, order_id: str) -> Order:
        orm = self.session.query(OrderORM).get(order_id)

        raw = {
            "order_id": orm.order_id,
            "items": self._load_items(orm),
            "payment": self._load_payment(orm)
        }

        return Order(raw)

注意:

  • ORM 結(jié)構被“翻譯”

  • Domain Model 完全不知道 ORM 的存在

8. Domain → ORM 的持久化(序列化)

def save(self, order: Order):
    orm = OrderORM(
        order_id=order.order_id,
        total_amount=order.order_amount()
    )
    self.session.add(orm)

即使結(jié)構重復,也要接受。重復是隔離的代價,也是穩(wěn)定性的來源。

9. 工程規(guī)范:持久化永遠是“外部關心的事”

領域模型中 絕對不應出現(xiàn)

  • session

  • commit

  • save()

  • ORM 注解

如果你在領域模型中看到這些,說明:領域已經(jīng)被侵蝕。

小結(jié)一下吧

通過本節(jié),你應當形成以下堅定認知:

  • 領域模型不為數(shù)據(jù)庫服務

  • ORM 只是技術實現(xiàn)

  • Repository 隔離變化

  • 結(jié)構重復是合理且必要的

  • 領域模型必須可以脫離數(shù)據(jù)庫獨立存在

(九)校驗、異常與領域約束建模

現(xiàn)在我們已經(jīng)解決了:

  • 復雜結(jié)構如何建模

  • 邊界如何隔離

  • 如何工程化增強模型

  • 如何與數(shù)據(jù)庫解耦

但到目前為止,仍有一個問題被刻意回避了:如果數(shù)據(jù)是“非法的”,怎么辦?

現(xiàn)實系統(tǒng)中,非法數(shù)據(jù)是常態(tài),而不是例外

1. 一個常見但危險的現(xiàn)狀

很多系統(tǒng)對“非法數(shù)據(jù)”的處理方式是:

if price <= 0:
    return None

或者:

try:
    ...
except Exception:
    pass

這些寫法的問題不在于“能不能跑”,而在于:

  • 錯誤被吞掉

  • 規(guī)則被隱式化

  • 系統(tǒng)進入“不可預期狀態(tài)”

工程結(jié)論:校驗不是工具層問題,而是領域模型的職責

2. 什么是“領域約束”(Domain Constraint)

領域約束指的是:

  • 業(yè)務上不允許被破壞的規(guī)則

  • 與技術、存儲、接口無關

  • 一旦違反,系統(tǒng)就不應繼續(xù)執(zhí)行

例如:

  • 訂單金額不能為負

  • 支付金額不能小于 0

  • 已完成訂單不能再次支付

這些規(guī)則 不屬于 Controller,也不屬于 Service,而是:領域模型自身的邊界。

3. 領域異常:用“異常”表達規(guī)則破壞

在領域建模中,異常不是“程序錯誤”,而是:對業(yè)務規(guī)則被破壞的明確聲明

首先,定義領域異?;悾?/p>

class DomainError(Exception):
    pass

然后為關鍵規(guī)則定義具體異常:

class InvalidPriceError(DomainError):
    pass

class PaymentAmountError(DomainError):
    pass

class OrderStateError(DomainError):
    pass

規(guī)范:不要在領域中直接拋 ValueError、TypeError。

4. 在模型內(nèi)部執(zhí)行校驗(而不是外部 if)

OrderItem 為例:

from dataclasses import dataclass

@dataclass
class OrderItem:
    sku: str
    quantity: int

    def __post_init__(self):
        if self.quantity <= 0:
            raise InvalidPriceError("quantity must be positive")

此時:

  • 非法對象 根本無法被構造

  • 錯誤在最早階段暴露

5. 行為級校驗:規(guī)則與動作綁定

不是所有校驗都發(fā)生在構造階段。

例如:支付行為。

class Order:
    ...

    def pay(self, amount: int):
        if amount <= 0:
            raise PaymentAmountError("payment must be positive")

        if self.is_fully_paid():
            raise OrderStateError("order already paid")

        self.payment.add_transaction(amount)

關鍵原則:規(guī)則應當與“動作”綁定,而不是與“字段”綁定。

6. 領域狀態(tài)與約束的結(jié)合

復雜系統(tǒng)中,狀態(tài)本身就是約束來源。

class OrderStatus:
    CREATED = "CREATED"
    PAID = "PAID"
    CANCELED = "CANCELED"


class Order:
    ...

    def cancel(self):
        if self.status == OrderStatus.PAID:
            raise OrderStateError("paid order cannot be canceled")

        self.status = OrderStatus.CANCELED

此時:

  • 狀態(tài)轉(zhuǎn)換路徑被嚴格限制

  • 非法流程無法發(fā)生

7. 校驗邏輯的分層原則(非常重要)

一個成熟系統(tǒng)中,校驗應分為三層:

層級校驗內(nèi)容示例
接口層格式、必填JSON 字段是否存在
邊界層基本合法性字符串能否轉(zhuǎn) int
領域?qū)?/td>業(yè)務規(guī)則金額、狀態(tài)、約束

絕對禁止:在 Controller 中寫業(yè)務規(guī)則判斷。

8. 異常如何“向外傳播”

領域異常的傳播路徑應當是:

Controller 的職責不是“判斷規(guī)則”,而是:

try:
    order.pay(amount)
except DomainError as e:
    return error_response(str(e))

9. 工程規(guī)范:失敗是系統(tǒng)能力的一部分

一個系統(tǒng)是否健壯,不取決于:能否處理正常數(shù)據(jù)

而取決于:能否正確拒絕不合法行為

領域異常的價值在于:

  • 規(guī)則顯式

  • 行為可追蹤

  • 錯誤不可忽略

八、總結(jié)

至此,本篇內(nèi)容對 Python 基礎知識進行了一個相對系統(tǒng)的梳理與總結(jié)。

從運行環(huán)境與工具選擇,到變量、控制流、函數(shù)、字符串處理,再到列表、字典、集合等核心數(shù)據(jù)結(jié)構,本博客力求用工程視角 + 可運行示例的方式,期望在較短時間內(nèi)建立起對 Python 編程的整體認知和基本實戰(zhàn)能力。

需要說明的是,這份內(nèi)容同樣也是我在學習 Python 過程中的階段性整理與沉淀。難免存在理解不夠嚴謹或表述不夠完善之處,歡迎各位讀者在評論區(qū)留言指正、交流探討,這對我和后續(xù)讀者都會非常有價值。

如果你能通過本文:

  • 理解 Python 的核心語法思想

  • 看懂并獨立編寫基礎程序

  • 對后續(xù)深入學習(如數(shù)據(jù)處理、Web、自動化或 AI 方向)不再畏懼

那么這篇總結(jié)就達到了它應有的意義。

Python 是一門上手友好、上限極高的語言,但真正的成長來自持續(xù)實踐,而不是一次性閱讀。希望你在未來的學習過程中,多動手、多思考、多調(diào)試,把“會寫”逐步變成“寫得好、寫得穩(wěn)”。

以上就是入門初學者短期內(nèi)快速掌握Python的經(jīng)典全面教程(專家學習筆記)的詳細內(nèi)容,更多關于Python基礎學習總結(jié)的資料請關注腳本之家其它相關文章!

相關文章

  • python filecmp.dircmp實現(xiàn)遞歸比對兩個目錄的方法

    python filecmp.dircmp實現(xiàn)遞歸比對兩個目錄的方法

    這篇文章主要介紹了python filecmp.dircmp實現(xiàn)遞歸比對兩個目錄的方法,本文通過實例代碼給大家介紹的非常詳細,大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-05-05
  • 一篇文章帶你深入學習Python函數(shù)

    一篇文章帶你深入學習Python函數(shù)

    這篇文章主要帶大家深入學習Python函數(shù),具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-01-01
  • Python中ArcPy柵格裁剪柵格(批量對齊柵格圖像范圍并統(tǒng)一行數(shù)與列數(shù))

    Python中ArcPy柵格裁剪柵格(批量對齊柵格圖像范圍并統(tǒng)一行數(shù)與列數(shù))

    本文介紹基于Python中ArcPy模塊,實現(xiàn)基于柵格圖像批量裁剪柵格圖像,同時對齊各個柵格圖像的空間范圍,統(tǒng)一其各自行數(shù)與列數(shù)的方法,本文通過實例代碼給大家介紹的非常詳細,需要的朋友可以參考下
    2023-02-02
  • Python+OpenCV六種實時圖像處理詳細講解

    Python+OpenCV六種實時圖像處理詳細講解

    OpenCV常用的圖像處理為閾值二值化、邊緣檢測、輪廓檢測、高斯濾波、色彩轉(zhuǎn)換、調(diào)節(jié)對比度。本文主要介紹了利用Python和OpenCV對實時圖像進行上述六種操作的詳細講解,感興趣的可以了解一下。
    2021-11-11
  • 詳解python中靜態(tài)方法staticmethod用法

    詳解python中靜態(tài)方法staticmethod用法

    本文主要介紹了python中靜態(tài)方法staticmethod用法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-07-07
  • python Hypothesis生成和執(zhí)行大量的測試用例

    python Hypothesis生成和執(zhí)行大量的測試用例

    Hypothesis是一個基于屬性的測試(property-based testing)庫,它能夠幫助我們生成和執(zhí)行大量的測試用例,與傳統(tǒng)的單元測試相比,屬性測試更加靈活和全面,能夠發(fā)現(xiàn)更多的邊界情況和潛在的錯誤
    2024-01-01
  • python解析.pyd文件的詳細代碼

    python解析.pyd文件的詳細代碼

    這篇文章介紹了python解析.pyd文件的詳細代碼,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考
    2021-12-12
  • Python 生成短8位唯一id實戰(zhàn)教程

    Python 生成短8位唯一id實戰(zhàn)教程

    這篇文章主要介紹了Python 生成短8位唯一id實戰(zhàn)教程,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01
  • 使用Mixin設計模式進行Python編程的方法講解

    使用Mixin設計模式進行Python編程的方法講解

    Mixin模式也可以看作是一種組合模式,綜合多個類的功能來產(chǎn)生一個類而不通過繼承來實現(xiàn),下面就來整理一下使用Mixin設計模式進行Python編程的方法講解:
    2016-06-06
  • python計算方程式根的方法

    python計算方程式根的方法

    這篇文章主要介紹了python計算方程式根的方法,涉及Python數(shù)學運算的相關技巧,需要的朋友可以參考下
    2015-05-05

最新評論

文水县| 博野县| 金门县| 常熟市| 和田县| 乌鲁木齐市| 新建县| 金坛市| 大荔县| 鹤庆县| 内丘县| 易门县| 南投县| 纳雍县| 庐江县| 日土县| 江陵县| 邯郸市| 浦东新区| 天峻县| 德兴市| 修文县| 津市市| 垫江县| 阿拉尔市| 辽阳市| 嘉善县| 丹东市| 双辽市| 沂源县| 贡觉县| 西充县| 柳州市| 大田县| 浦江县| 武陟县| 仙游县| 格尔木市| 郸城县| 鸡西市| 商河县|