入門初學者短期內(nèi)快速掌握Python的經(jīng)典全面教程(專家學習筆記)
本博客將自己初步學習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 3 | brew install python | 安裝最新的 Python 3 |
| 3. 驗證 Python 版本 | python3 --version | 確保安裝成功,顯示 Python 3.x.x |
| 4. 安裝 Jupyter Notebook | pip3 install jupyter | 通過 pip3 安裝 Jupyter |
| 5. 檢查 Jupyter 是否可用 | jupyter --version | 確保 Jupyter 已正確安裝 |
| 6. 啟動 Jupyter Notebook | jupyter 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ū)分大小寫(
age和Age是不同的變量)。推薦使用 小寫字母+下劃線(
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 | 只有 True 或 False |
| 列表(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}") # 推薦的寫法? 小練習題
嘗試自己編寫代碼練習以下問題:
定義一個變量
temperature,存儲36.6,并使用print()輸出"體溫: 36.6 攝氏度"。編寫一個程序,提示用戶輸入姓名和年齡,并打印
"你好,XX!你今年 YY 歲"(其中XX和YY由用戶輸入)。
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)
比較運算符用于比較兩個值,返回 True 或 False。
| 運算符 | 含義 | 示例 | 結(jié)果 |
|---|---|---|---|
== | 等于 | 5 == 5 | True |
!= | 不等于 | 5 != 3 | True |
> | 大于 | 10 > 3 | True |
< | 小于 | 2 < 8 | True |
>= | 大于等于 | 5 >= 5 | True |
<= | 小于等于 | 3 <= 2 | False |
代碼示例
a = 10 b = 5 print(a > b) # True print(a == b) # False print(a != b) # True
3. 布爾運算符(Boolean Operators)
Python 提供了 and、or 和 not 三種邏輯運算符,用于組合多個布爾表達式。
| 運算符 | 含義 | 示例 | 結(jié)果 |
|---|---|---|---|
and | 邏輯與(都為 True 時才為 True) | True and False | False |
or | 邏輯或(只要一個為 True 就是 True) | True or False | True |
not | 邏輯非(取反) | not True | False |
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 Truenot (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、elif 和 else 關鍵字來實現(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),配合控制語句(如 break、continue)可以構建出豐富的循環(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-1range(start, end):start 到 end-1range(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 可以與 for 或 while 循環(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ù)是 a 和 b,它們會被加在一起并返回結(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ù) a 和 b 的位置決定了它們的意義。當調(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ù):a 和 b。我們調(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ù)時,age 和 name 的順序不再重要,關鍵字參數(shù)通過指定 age=25 和 name="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 None | return / 無 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, gotstr
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
| 字符 | p | y | t | h | o | n |
|---|---|---|---|---|---|---|
| 索引 | 0 | 1 | 2 | 3 | 4 | 5 |
?? 負向索引(從 -1 開始,表示從右往左)
s = "python" print(s[-1]) # n print(s[-2]) # o print(s[-6]) # p
| 字符 | p | y | t | h | o | n |
|---|---|---|---|---|---|---|
| 索引 | -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
此時:
a與b指向 同一個 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 ]
a和b是兩個不同的列表對象但它們內(nèi)部的
L1、L2指向同一個子列表對象
淺拷貝的典型“坑”
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 必須是不可變類型:
合法:
str、int、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)類型:合法元素:
int、float、str、tuple;非法元素:list、dict、set
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 對應類型 |
|---|---|
| object | dict |
| array | list |
| string | str |
| number | int / float |
| boolean | bool |
| null | None |
也正因如此,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> |
|---|---|
| order | Order(聚合根) |
| user | User |
| profile | UserProfile |
| items | OrderItem |
| pricing | Pricing |
| discounts | Discount |
| payment | Payment |
| transactions | PaymentTransaction |
原則:
只要一個子結(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é)構化建模的工程工具。
它解決的核心問題是:
| 問題 | 原生 Class | dataclass |
|---|---|---|
| 字段聲明 | 分散在 __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):
sessioncommitsave()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)遞歸比對兩個目錄的方法,本文通過實例代碼給大家介紹的非常詳細,大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-05-05
Python中ArcPy柵格裁剪柵格(批量對齊柵格圖像范圍并統(tǒng)一行數(shù)與列數(shù))
本文介紹基于Python中ArcPy模塊,實現(xiàn)基于柵格圖像批量裁剪柵格圖像,同時對齊各個柵格圖像的空間范圍,統(tǒng)一其各自行數(shù)與列數(shù)的方法,本文通過實例代碼給大家介紹的非常詳細,需要的朋友可以參考下2023-02-02
詳解python中靜態(tài)方法staticmethod用法
本文主要介紹了python中靜態(tài)方法staticmethod用法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-07-07
python Hypothesis生成和執(zhí)行大量的測試用例
Hypothesis是一個基于屬性的測試(property-based testing)庫,它能夠幫助我們生成和執(zhí)行大量的測試用例,與傳統(tǒng)的單元測試相比,屬性測試更加靈活和全面,能夠發(fā)現(xiàn)更多的邊界情況和潛在的錯誤2024-01-01

