第二階段:數據結構與函數

模塊4:常用數據結構 (Organizing Lots of Data)

在前面的模塊中,我們學習了如何使用變量來存儲單個數據,比如一個數字、一個名字或一個布爾值。但很多時候,我們需要處理一組相關的數據,比如班級里所有學生的名字、一本書的所有章節標題、或者一個用戶的各項配置信息。這時,就需要用到數據結構(Data Structures),它們是 Python 中用來組織和存儲多個數據項的方式。

這個模塊我們將學習 Python 中最常用的四種內置數據結構:列表(List)、元組(Tuple)、字典(Dictionary)和集合(Set)。

4.1 列表 (List): 最常用的“數據清單”

列表是 Python 中最常用、最靈活的數據結構。你可以把它想象成一個有序的、可以修改的清單。

  • 有序 (Ordered): 列表中的每個元素都有一個固定的位置(索引),就像排隊一樣,順序很重要。
  • 可變 (Mutable): 你可以在創建列表后,隨時添加、刪除或修改里面的元素。

1. 創建列表

  • 使用方括號 [],元素之間用逗號 , 分隔。
  • 列表可以包含任何類型的元素,甚至混合類型。
  • 創建一個空列表:[]

Python

# 一個包含數字的列表
numbers = [1, 2, 3, 4, 5]
print(numbers)# 一個包含字符串的列表
fruits = ["apple", "banana", "cherry"]
print(fruits)# 一個混合類型的列表
mixed_list = [10, "hello", 3.14, True, "banana"]
print(mixed_list)# 一個空列表
empty_list = []
print(empty_list)

2. 訪問列表元素 (Indexing)

  • 和字符串一樣,通過索引訪問列表中的元素,索引從 0 開始。
  • 也可以使用負數索引,-1 表示最后一個元素,-2 表示倒數第二個,以此類推。

Python

colors = ["red", "green", "blue", "yellow"]first_color = colors[0]  # 'red'
second_color = colors[1] # 'green'
last_color = colors[-1]  # 'yellow'
second_last = colors[-2] # 'blue'print(f"第一個顏色是: {first_color}")
print(f"最后一個顏色是: {last_color}")# 如果索引超出范圍,會報錯 IndexError
# print(colors[4]) # 會導致 IndexError

3. 列表切片 (Slicing)

  • 和字符串一樣,使用 [start:stop:step] 獲取列表的一部分(子列表)。
  • 包含 start 索引處的元素,但不包含 stop 索引處的元素。
  • step 是可選的步長。

Python

numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]# 獲取索引 1 到 4 (不含 4) 的元素
sub_list1 = numbers[1:4]   # [1, 2, 3]
print(sub_list1)# 獲取從索引 5 到末尾的元素
sub_list2 = numbers[5:]    # [5, 6, 7, 8, 9]
print(sub_list2)# 獲取從開頭到索引 3 (不含 3) 的元素
sub_list3 = numbers[:3]    # [0, 1, 2]
print(sub_list3)# 獲取所有元素的一個副本
copy_list = numbers[:]     # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print(copy_list)# 獲取步長為 2 的元素 (隔一個取一個)
step_list = numbers[0:10:2] # [0, 2, 4, 6, 8]
print(step_list)

4. 修改列表元素

因為列表是可變的,你可以直接通過索引來修改元素的值。

Python

my_list = [10, 20, 30, 40]
print(f"原始列表: {my_list}")# 修改索引為 1 的元素
my_list[1] = 25
print(f"修改后列表: {my_list}") # 輸出: [10, 25, 30, 40]

5. 添加元素

  • append(item): 在列表末尾添加一個元素。
  • insert(index, item): 在指定的索引位置插入一個元素,原來的元素及后面的元素會向后移動。

Python

hobbies = ["reading", "swimming"]
print(f"初始愛好: {hobbies}")# 在末尾添加
hobbies.append("coding")
print(f"添加后: {hobbies}") # ['reading', 'swimming', 'coding']# 在索引 1 的位置插入
hobbies.insert(1, "hiking")
print(f"插入后: {hobbies}") # ['reading', 'hiking', 'swimming', 'coding']

6. 刪除元素

  • pop(index): 刪除并返回指定索引位置的元素。如果省略 index,默認刪除并返回最后一個元素。
  • remove(value): 刪除列表中第一個出現的指定。如果值不存在,會報錯 ValueError
  • del 語句:通過索引刪除元素或切片。

Python

items = ["pen", "pencil", "eraser", "ruler", "pencil"]
print(f"原始物品: {items}")# 刪除并獲取最后一個元素
last_item = items.pop()
print(f"被 pop 的元素: {last_item}") # 'pencil'
print(f"pop 后列表: {items}")       # ['pen', 'pencil', 'eraser', 'ruler']# 刪除索引為 1 的元素
removed_item = items.pop(1)
print(f"被 pop(1) 的元素: {removed_item}") # 'pencil'
print(f"pop(1) 后列表: {items}")         # ['pen', 'eraser', 'ruler']# 刪除第一個值為 "eraser" 的元素
items.remove("eraser")
print(f"remove 'eraser' 后列表: {items}") # ['pen', 'ruler']
# 如果 items.remove("notebook") 會報錯 ValueError,因為 "notebook" 不存在# 使用 del 刪除索引為 0 的元素
del items[0]
print(f"del items[0] 后列表: {items}") # ['ruler']# del 也可以刪除切片
numbers = [1, 2, 3, 4, 5, 6]
del numbers[1:4] # 刪除索引 1, 2, 3 的元素
print(f"del 切片后列表: {numbers}") # [1, 5, 6]

7. 常用列表方法

  • sort(): 對列表進行原地排序(直接修改原列表)。默認升序。如果列表元素不能互相比較(如數字和字符串混合),會報錯 TypeError
  • reverse(): 將列表中的元素原地反轉
  • len(list): (這是一個內置函數,不是方法) 返回列表中的元素個數。
  • count(value): 返回列表中某個值出現的次數。
  • index(value): 返回列表中某個值首次出現的索引。如果值不存在,會報錯 ValueError

Python

nums = [5, 1, 4, 2, 3, 1]
chars = ['c', 'a', 'b']
print(f"原始 nums: {nums}")
print(f"原始 chars: {chars}")# 獲取長度
print(f"nums 的長度: {len(nums)}") # 6# 計數
print(f"nums 中 1 出現的次數: {nums.count(1)}") # 2# 查找索引
print(f"nums 中 4 的索引: {nums.index(4)}") # 2# 排序 (原地修改)
nums.sort()
chars.sort()
print(f"排序后 nums: {nums}") # [1, 1, 2, 3, 4, 5]
print(f"排序后 chars: {chars}") # ['a', 'b', 'c']# 降序排序
nums.sort(reverse=True)
print(f"降序排序后 nums: {nums}") # [5, 4, 3, 2, 1, 1]# 反轉 (原地修改)
chars.reverse()
print(f"反轉后 chars: {chars}") # ['c', 'b', 'a']

8. 列表推導式 (List Comprehensions) - 初步認識

列表推導式提供了一種更簡潔、更高效的方式來創建列表,特別是基于現有列表或范圍創建新列表時。

基本語法: [expression for item in iterable if condition]

  • expression: 對 item 進行處理的表達式,結果將是新列表的元素。
  • for item in iterable: 循環遍歷一個可迭代對象(如列表、range() 等)。
  • if condition: (可選) 只有當 conditionTrue 時,item 才會被處理并添加到新列表中。

示例:

Python

# 1. 創建一個 0 到 9 的平方數的列表
squares = []
for x in range(10):squares.append(x**2)
print(f"傳統方法創建平方數列表: {squares}")# 使用列表推導式
squares_comp = [x**2 for x in range(10)]
print(f"列表推導式創建平方數列表: {squares_comp}")# 2. 創建一個 0 到 9 中偶數的列表
evens = []
for x in range(10):if x % 2 == 0:evens.append(x)
print(f"傳統方法創建偶數列表: {evens}")# 使用列表推導式
evens_comp = [x for x in range(10) if x % 2 == 0]
print(f"列表推導式創建偶數列表: {evens_comp}")# 3. 將一個字符串列表中的所有單詞轉為大寫
words = ["hello", "world", "python"]
upper_words = [word.upper() for word in words]
print(f"單詞轉大寫: {upper_words}") # ['HELLO', 'WORLD', 'PYTHON']

列表推導式非常強大且常用,剛開始可能覺得有點抽象,但多練習幾次就會發現它的便利。

4.2 元組 (Tuple): 不可變的“數據清單”

元組和列表非常相似,也是有序的序列。但它們之間有一個關鍵區別:元組是不可變的 (Immutable)。一旦創建,你就不能修改元組中的元素(不能添加、刪除或更改)。

1. 創建元組

  • 使用圓括號 (),元素之間用逗號 , 分隔。
  • 注意: 創建只包含一個元素的元組時,必須在該元素后面加上逗號 ,,否則 Python 會把它當作普通的值。
  • 創建空元組:()
  • 在某些情況下,括號可以省略(比如賦值時),Python 也能識別它是元組。

Python

# 一個包含數字的元組
numbers_tuple = (1, 2, 3)
print(numbers_tuple)# 一個混合類型的元組
mixed_tuple = (10, "hello", 3.14)
print(mixed_tuple)# 創建單元素元組 - 注意逗號!
single_tuple = (99,)
not_a_tuple = (99)
print(f"這是一個元組: {single_tuple}, 類型: {type(single_tuple)}")
print(f"這不是元組: {not_a_tuple}, 類型: {type(not_a_tuple)}") # 這是 int 類型# 空元組
empty_tuple = ()
print(empty_tuple)# 省略括號創建元組
point = 10, 20 # 這也是一個元組 (10, 20)
print(point)
print(type(point))

2. 訪問元組元素 (Indexing & Slicing)

  • 和列表、字符串完全一樣,使用索引 [] 和切片 [:]

Python

my_tuple = ('a', 'b', 'c', 'd', 'e')
print(my_tuple[0])    # 'a'
print(my_tuple[-1])   # 'e'
print(my_tuple[1:3])  # ('b', 'c')

3. 不可變性 (Immutability)

這是元組的核心特性。嘗試修改元組會引發 TypeError

Python

immutable_tuple = (1, 2, 3)
# 下面的代碼會報錯 TypeError: 'tuple' object does not support item assignment
# immutable_tuple[0] = 100# 下面的代碼也會報錯 AttributeError: 'tuple' object has no attribute 'append'
# immutable_tuple.append(4)# 下面的代碼也會報錯 AttributeError: 'tuple' object has no attribute 'remove'
# immutable_tuple.remove(1)

4. 為什么使用元組?

既然列表那么靈活,為什么還需要不可變的元組呢?

  • 性能: 元組通常比列表占用更少的內存,并且在某些操作上(如迭代訪問)可能稍微快一點(盡管差異通常很小)。

  • 安全性/數據保護: 不可變性確保了數據在創建后不會被意外修改,適用于存儲不應改變的數據,如坐標點 (x, y)、RGB顏色值 (r, g, b) 等。

  • 可以作為字典的鍵: 因為元組是不可變的,所以它可以作為字典的鍵(我們馬上會學到字典),而列表不行。

  • 元組解包 (Tuple Unpacking): 可以方便地將元組中的元素賦值給多個變量。

    Python

    coordinates = (10, 20, 30)
    x, y, z = coordinates # 解包
    print(f"x={x}, y={y}, z={z}") # x=10, y=20, z=30
    

4.3 字典 (Dictionary / dict): 鍵值對應的“查找表”

字典是另一種非常有用的數據結構,它存儲的是鍵值對 (Key-Value Pairs)。你可以把它想象成一本真實的字典或電話簿:

  • 鍵 (Key): 就像字典里的單詞或電話簿里的名字,用來查找信息。鍵必須是唯一的、不可變的 (通常使用字符串、數字或元組)。
  • 值 (Value): 就像單詞的釋義或人對應的電話號碼,是與鍵相關聯的數據。值可以是任何數據類型,也可以重復。

字典在 Python 3.7+ 版本中是按插入順序存儲的,但在更早的版本中是無序的。字典查找速度非常快,特別適合需要通過某個唯一標識來快速獲取對應信息的場景。

1. 創建字典

  • 使用花括號 {},鍵值對之間用逗號 , 分隔,鍵和值之間用冒號 : 分隔。
  • 創建空字典:{}

Python

# 一個存儲學生信息的字典
student = {"name": "Alice","age": 20,"major": "Computer Science","is_graduated": False,"courses": ["Math", "Physics", "Programming"] # 值可以是列表
}
print(student)# 一個存儲商品價格的字典
prices = {"apple": 5.5,"banana": 3.0,"orange": 4.5
}
print(prices)# 一個空字典
empty_dict = {}
print(empty_dict)

2. 訪問字典的值

  • 使用放在方括號 [] 中來訪問對應的值。如果鍵不存在,會引發 KeyError
  • 使用 get(key, default=None) 方法訪問值。如果鍵不存在,它會返回 None (或者你指定的 default 值),而不會報錯。這通常是更安全的方式。

Python

student = {"name": "Bob", "age": 22, "major": "Physics"}# 使用方括號訪問
print(f"姓名: {student['name']}") # Bob
print(f"年齡: {student['age']}")   # 22# 嘗試訪問不存在的鍵會報錯 KeyError
# print(student['city'])# 使用 get() 方法訪問
print(f"專業: {student.get('major')}") # Physics
print(f"城市: {student.get('city')}")   # None (鍵不存在,返回 None)
print(f"城市 (帶默認值): {student.get('city', 'Unknown')}") # Unknown (鍵不存在,返回指定的默認值 'Unknown')

3. 添加和修改鍵值對

  • 直接給一個新鍵賦值,就可以添加新的鍵值對。
  • 給一個已存在的鍵賦值,就會修改該鍵對應的值。

Python

student = {"name": "Charlie", "age": 19}
print(f"原始字典: {student}")# 修改 age
student['age'] = 20
print(f"修改年齡后: {student}")# 添加新的鍵值對 city
student['city'] = "London"
print(f"添加城市后: {student}") # {'name': 'Charlie', 'age': 20, 'city': 'London'}

4. 刪除鍵值對

  • pop(key): 刪除指定的鍵值對,并返回對應的值。如果鍵不存在,會報錯 KeyError
  • del 語句:通過鍵刪除鍵值對。如果鍵不存在,也會報錯 KeyError

Python

contact = {"name": "David", "phone": "123-456", "email": "david@example.com"}
print(f"原始聯系人: {contact}")# 刪除 email 并獲取其值
removed_email = contact.pop("email")
print(f"被 pop 的 email: {removed_email}") # david@example.com
print(f"pop email 后: {contact}")       # {'name': 'David', 'phone': '123-456'}# 使用 del 刪除 phone
del contact["phone"]
print(f"del phone 后: {contact}") # {'name': 'David'}# 嘗試刪除不存在的鍵會報錯
# del contact["address"] # KeyError
# contact.pop("city")    # KeyError

5. 常用字典方法

  • keys(): 返回一個包含所有的“視圖對象”(可以像列表一樣遍歷)。
  • values(): 返回一個包含所有的“視圖對象”。
  • items(): 返回一個包含所有**(鍵, 值)**元組對的“視圖對象”。

Python

student = {"name": "Eve", "age": 21, "major": "Biology"}# 獲取所有鍵
keys = student.keys()
print(f"所有鍵: {keys}")      # dict_keys(['name', 'age', 'major'])
print(list(keys))           # 可以轉換為列表 ['name', 'age', 'major']# 獲取所有值
values = student.values()
print(f"所有值: {values}")    # dict_values(['Eve', 21, 'Biology'])
print(list(values))         # 可以轉換為列表 ['Eve', 21, 'Biology']# 獲取所有鍵值對
items = student.items()
print(f"所有項: {items}")      # dict_items([('name', 'Eve'), ('age', 21), ('major', 'Biology')])
print(list(items))          # 可以轉換為列表 [('name', 'Eve'), ('age', 21), ('major', 'Biology')]

6. 遍歷字典

有幾種常用的方式來遍歷字典:

Python

student = {"name": "Frank", "age": 23, "major": "Chemistry"}# 遍歷鍵 (默認方式)
print("\n遍歷鍵:")
for key in student:print(f"鍵: {key}, 值: {student[key]}") # 通過鍵再次訪問值# 遍歷值
print("\n遍歷值:")
for value in student.values():print(value)# 遍歷鍵值對 (推薦方式)
print("\n遍歷鍵值對 (使用 .items()):")
for key, value in student.items(): # 使用元組解包print(f"{key}: {value}")

4.4 集合 (Set): 無序且唯一的“元素包”

集合是一個無序的、包含不重復元素的集合。你可以把它想象成一個袋子,里面裝的東西沒有順序,而且同樣的東西只能裝一個。

集合的主要用途:

  • 去重 (Removing Duplicates): 快速去除列表或其他序列中的重復元素。
  • 成員檢測 (Membership Testing): 快速判斷一個元素是否存在于集合中(比在列表中查找快得多)。
  • 集合運算 (Set Operations): 進行數學上的集合運算,如交集、并集、差集等。

1. 創建集合

  • 使用花括號 {},元素之間用逗號 , 分隔。
  • 注意: 創建空集合必須使用 set() 函數,因為 {} 創建的是空字典!
  • 可以直接從列表或其他可迭代對象創建集合,它會自動去重。

Python

# 創建一個包含數字的集合 (重復的 3 會被忽略)
numbers_set = {1, 2, 3, 4, 3, 2}
print(numbers_set) # 輸出可能是 {1, 2, 3, 4} (順序不固定)# 創建一個包含字符串的集合
fruits_set = {"apple", "banana", "cherry"}
print(fruits_set)# 創建空集合 - 必須用 set()
empty_set = set()
print(empty_set)
print(type(empty_set)) # <class 'set'># 從列表創建集合 (自動去重)
my_list = [1, 1, 2, 3, 4, 4, 4, 5]
my_set_from_list = set(my_list)
print(my_set_from_list) # {1, 2, 3, 4, 5}

2. 無序性

集合不保證元素的順序,所以你不能像列表或元組那樣使用索引來訪問元素。

Python

my_set = {10, 20, 30}
# 下面的代碼會報錯 TypeError: 'set' object is not subscriptable
# print(my_set[0])

3. 唯一性

集合中不允許有重復的元素。如果你嘗試添加一個已存在的元素,集合不會發生任何變化。

4. 添加和刪除元素

  • add(element): 添加一個元素到集合中。如果元素已存在,則什么也不做。
  • remove(element): 從集合中刪除一個元素。如果元素不存在,會引發 KeyError
  • discard(element): 從集合中刪除一個元素。如果元素不存在,它不會報錯,而是什么也不做。通常 discard 更安全。

Python

colors = {"red", "green"}
print(f"原始集合: {colors}")# 添加元素
colors.add("blue")
print(f"添加 blue 后: {colors}")colors.add("red") # 嘗試添加已存在的元素
print(f"再次添加 red 后: {colors}") # 集合不變# 刪除元素
colors.remove("green")
print(f"刪除 green 后: {colors}")# 嘗試 remove 不存在的元素會報錯
# colors.remove("yellow") # KeyError# 使用 discard 刪除存在的元素
colors.discard("blue")
print(f"discard blue 后: {colors}")# 使用 discard 刪除不存在的元素 (不會報錯)
colors.discard("yellow")
print(f"discard yellow 后: {colors}") # 集合不變

5. 集合運算

集合支持標準的數學集合運算:

  • 成員檢測 (in): 判斷元素是否在集合中(非常高效)。
  • 并集 (|union()): 返回包含兩個集合中所有元素的新集合。
  • 交集 (&intersection()): 返回兩個集合中共同存在的元素組成的新集合。
  • 差集 (-difference()): 返回存在于第一個集合但不在第二個集合中的元素組成的新集合。
  • 對稱差集 (^symmetric_difference()): 返回存在于兩個集合中,但不同時存在于兩個集合中的元素(即并集減去交集)。

Python

set_a = {1, 2, 3, 4}
set_b = {3, 4, 5, 6}
print(f"集合 A: {set_a}")
print(f"集合 B: {set_b}")# 成員檢測
print(f"2 在 A 中嗎? {2 in set_a}")  # True
print(f"5 在 A 中嗎? {5 in set_a}")  # False# 并集
union_set = set_a | set_b
# union_set = set_a.union(set_b)
print(f"并集 A | B: {union_set}") # {1, 2, 3, 4, 5, 6}# 交集
intersection_set = set_a & set_b
# intersection_set = set_a.intersection(set_b)
print(f"交集 A & B: {intersection_set}") # {3, 4}# 差集 (A 中有,B 中沒有)
difference_set = set_a - set_b
# difference_set = set_a.difference(set_b)
print(f"差集 A - B: {difference_set}") # {1, 2}# 差集 (B 中有,A 中沒有)
print(f"差集 B - A: {set_b - set_a}") # {5, 6}# 對稱差集 (只在 A 或只在 B 中的元素)
sym_diff_set = set_a ^ set_b
# sym_diff_set = set_a.symmetric_difference(set_b)
print(f"對稱差集 A ^ B: {sym_diff_set}") # {1, 2, 5, 6}

4.5 實踐時間!

練習1:簡單的學生成績管理

  1. 創建一個列表,名為 students。這個列表將用來存儲多個學生的信息。
  2. 列表中的每個元素都是一個字典,代表一個學生。每個學生字典至少包含以下鍵:
    • "name": 學生姓名 (字符串)
    • "grades": 一個包含該學生各科成績(數字)的列表
    • 例如:{"name": "Alice", "grades": [85, 90, 78]}
  3. students 列表中添加至少3個學生的信息。
  4. 編寫代碼,計算并打印出每個學生的平均成績。你需要遍歷 students 列表,對于每個學生字典,再遍歷其 "grades" 列表來計算總分和平均分。
  5. (可選)添加一個新功能:允許用戶輸入學生姓名,然后查找并打印該學生的成績列表和平均分。如果學生不存在,則打印提示信息。

練習2:詞頻統計

  1. 定義一個包含一段文本的字符串變量(比如一句或幾句話)。
  2. 預處理文本:
    • 將文本全部轉換為小寫(使用字符串的 lower() 方法)。
    • (可選,簡化處理)去除標點符號。你可以用 replace() 方法將常見的標點符號(如 ., ,, ?, !)替換為空格或空字符串。
  3. 分詞: 使用字符串的 split() 方法將處理后的文本分割成一個單詞列表。默認情況下,split() 會按空格分割。
  4. 統計詞頻:
    • 創建一個空字典,名為 word_counts,用來存儲每個單詞出現的次數。
    • 遍歷你的單詞列表。
    • 對于列表中的每個單詞:
      • 檢查這個單詞是否已經是 word_counts 字典的
      • 如果是,將該鍵對應的值(計數)加 1。
      • 如果不是,將這個單詞作為新鍵添加到字典中,并將值設為 1。
      • (提示:使用 get(word, 0) 可以很方便地獲取當前計數,如果單詞不存在則返回0,然后加1即可:word_counts[word] = word_counts.get(word, 0) + 1
  5. 遍歷 word_counts 字典,打印出每個單詞及其出現的次數。

模塊5:函數——代碼的復用

在我們之前的編程練習中,你可能已經注意到,有時我們會重復寫幾乎完全一樣的代碼塊。比如,計算平均分的邏輯、打印特定格式信息的代碼等。如果這樣的代碼很多,程序會變得冗長、難以閱讀,而且一旦需要修改這部分邏輯,你就得找到所有重復的地方一一修改,非常麻煩且容易出錯。

函數(Function)就是解決這個問題的利器!它可以讓你把一段具有特定功能的代碼打包起來,給它起一個名字,然后在需要執行這段代碼的任何地方,簡單地“調用”這個名字即可。

5.1 為什么需要函數?(DRY 原則)

使用函數的主要原因是為了遵循 DRY 原則Don't Repeat Yourself(不要重復你自己)。

  • 提高代碼復用性: 定義一次,多次調用。
  • 提高代碼可讀性: 將復雜的任務分解成小的、有明確功能的函數,讓主程序邏輯更清晰。給函數起一個有意義的名字本身就是一種注釋。
  • 提高代碼可維護性: 如果需要修改某項功能的邏輯,只需要修改對應的函數定義即可,所有調用該函數的地方都會自動生效。
  • 方便協作: 不同的開發者可以分工編寫不同的函數模塊。

5.2 定義函數

使用 def 關鍵字來定義一個函數。

基本語法:

Python

def function_name(parameters):"""(可選) 函數文檔字符串 (Docstring) - 解釋函數的作用、參數和返回值。通常用三引號包裹。"""# 函數體 (縮進的代碼塊)# 這里是函數的具體邏輯statement1statement2# ...return value # (可選) 返回一個結果
  • def: 定義函數的關鍵字。
  • function_name: 你給函數起的名字,遵循變量命名規則(snake_case)。
  • (): 函數名后面的圓括號,必須有。
  • parameters: (可選) 括號里的變量名,是函數接收的輸入值(參數),多個參數用逗號分隔。如果沒有參數,括號也是空的 ()
  • :: 圓括號后面必須有冒號。
  • Docstring: (可選但強烈推薦) 一個用三引號 """Docstring goes here""" 包裹的字符串,用于解釋函數的功能。好的文檔字符串對于理解和使用函數至關重要。
  • 函數體: 縮進的代碼塊,包含函數的實際邏輯。
  • return value: (可選) 使用 return 關鍵字將函數的結果(值)發送回調用它的地方。如果函數沒有 return 語句,或者 return 后面沒有值,它默認返回 None

示例:一個簡單的問候函數

Python

def greet():"""打印一句簡單的問候語。"""print("Hello there! Welcome.")def greet_user(name):"""根據提供的名字打印個性化問候語。Args:name: 要問候的人的名字 (字符串)。"""print(f"Hello, {name}! Nice to meet you.")

5.3 調用函數

定義好函數后,你需要調用(Call 或 Invoke)它來執行函數體內的代碼。調用函數的方法是寫出函數名,后面跟上圓括號 (),并在括號內提供必要的參數(Arguments)

Python

# 調用沒有參數的函數
greet() # 輸出: Hello there! Welcome.# 調用有參數的函數,需要提供參數值
greet_user("Alice") # 輸出: Hello, Alice! Nice to meet you.
greet_user("Bob")   # 輸出: Hello, Bob! Nice to meet you.

當程序執行到函數調用時,它會“跳轉”到函數的定義處,執行函數體內的代碼,然后再“跳回”到函數被調用的地方繼續執行。

5.4 參數 (Parameters) 與 實參 (Arguments)

這兩個詞經常互換使用,但嚴格來說:

  • 參數 (Parameters): 定義函數時,寫在圓括號里的變量名(如 greet_user 函數中的 name)。它們是函數內部使用的占位符。
  • 實參 (Arguments): 調用函數時,傳遞給函數的實際值(如 greet_user("Alice") 中的 "Alice")。

Python 支持多種傳遞參數的方式:

1. 位置參數 (Positional Arguments)

最常見的方式。實參會按照它們在調用時出現的順序,依次傳遞給函數定義中的參數。

Python

def describe_pet(animal_type, pet_name):"""顯示寵物的信息。"""print(f"I have a {animal_type}.")print(f"My {animal_type}'s name is {pet_name.title()}.")describe_pet("hamster", "harry") # "hamster" 傳給 animal_type, "harry" 傳給 pet_name
describe_pet("dog", "willie")

注意:位置參數的順序很重要,傳錯了會導致邏輯錯誤。 describe_pet("willie", "dog") 就會輸出錯誤的信息。

2. 關鍵字參數 (Keyword Arguments)

調用函數時,你可以明確指定哪個實參傳遞給哪個參數,使用 參數名=值 的形式。這時,實參的順序就不重要了

Python

describe_pet(animal_type="cat", pet_name="whiskers")
describe_pet(pet_name="goldie", animal_type="fish") # 順序不同,但結果正確

注意:在一個函數調用中,關鍵字參數必須跟在所有位置參數之后。

3. 默認參數值 (Default Parameter Values)

在定義函數時,可以為參數指定一個默認值。如果在調用函數時沒有為該參數提供實參,那么就會使用這個默認值。

Python

def power(base, exponent=2): # exponent 參數默認值為 2"""計算 base 的 exponent 次方。"""result = base ** exponentprint(f"{base} 的 {exponent} 次方是 {result}")power(5)      # 沒有提供 exponent,使用默認值 2。輸出: 5 的 2 次方是 25
power(3, 3)   # 提供了 exponent,使用提供的值 3。輸出: 3 的 3 次方是 27
power(base=4) # 也可以用關鍵字參數調用
power(base=2, exponent=5)

注意:在函數定義中,所有帶默認值的參數必須放在所有不帶默認值的參數之后。

4. 可變參數 (Variable-Length Arguments) - 初步認識

有時你希望函數能接受任意數量的參數。

  • *args (任意數量的位置參數): 在參數名前加一個星號 *。這會將調用時提供的多余的位置參數收集到一個元組 (tuple) 中。參數名通常約定俗成用 args,但也可以用別的名字(如 *numbers)。

    Python

    def make_pizza(size, *toppings):"""概述要制作的比薩。Args:size: 比薩的尺寸。*toppings: 一個包含所有配料的元組。"""print(f"\nMaking a {size}-inch pizza with the following toppings:")if toppings: # 檢查 toppings 元組是否為空for topping in toppings:print(f"- {topping}")else:print("- Plain cheese")make_pizza(12, "mushrooms")
    make_pizza(16, "mushrooms", "green peppers", "extra cheese")
    make_pizza(10) # toppings 會是一個空元組
    
  • **kwargs (任意數量的關鍵字參數): 在參數名前加兩個星號 **。這會將調用時提供的多余的關鍵字參數收集到一個字典 (dict) 中。參數名通常約定俗成用 kwargs,但也可以用別的名字(如 **user_info)。

    Python

    def build_profile(first, last, **user_info):"""創建一個字典,包含我們知道的有關用戶的一切。Args:first: 名。last: 姓。**user_info: 包含其他信息的字典。"""profile = {}profile['first_name'] = firstprofile['last_name'] = lastfor key, value in user_info.items(): # 遍歷 kwargs 字典profile[key] = valuereturn profile # 返回構建好的字典user_profile = build_profile('albert', 'einstein',location='princeton',field='physics')
    print(user_profile)
    # 輸出: {'first_name': 'albert', 'last_name': 'einstein', 'location': 'princeton', 'field': 'physics'}user_profile2 = build_profile('marie', 'curie',field='physics', award='Nobel Prize')
    print(user_profile2)
    

注意:在函數定義中,參數的順序通常是:普通位置參數 -> 默認參數 -> *args -> **kwargs。對于初學者,理解 *args**kwargs 的基本概念(收集多余參數)即可。

5.5 返回值 (Return Values)

函數不僅可以執行操作(比如打印),還可以計算一個結果并將其“返回”給調用它的代碼。這通過 return 語句實現。

  • 當執行到 return 語句時,函數立即停止執行,并將 return 后面的值作為結果返回。
  • 調用函數的地方可以接收這個返回值,通常是賦給一個變量。
  • 如果函數沒有 return 語句,或者 return 后面沒有值,它默認返回特殊值 None
  • 一個函數可以有多個 return 語句(例如在不同的 if 分支里),但只要執行到任何一個 return,函數就會結束。
  • 可以返回任何類型的數據:數字、字符串、列表、字典,甚至另一個函數!
  • 可以一次返回多個值,它們會被自動打包成一個元組

Python

def add(x, y):"""計算兩個數的和并返回結果。"""result = x + yreturn resultsum_result = add(5, 3)
print(f"5 + 3 = {sum_result}") # 輸出: 5 + 3 = 8def get_name_parts(full_name):"""將全名分割成名和姓。"""parts = full_name.split() # 按空格分割if len(parts) >= 2:first_name = parts[0]last_name = " ".join(parts[1:]) # 處理可能有中間名的情況return first_name, last_name # 返回兩個值 (打包成元組)elif len(parts) == 1:return parts[0], None # 如果只有一個部分,姓氏返回 Noneelse:return None, None # 如果輸入為空,都返回 Nonefirst, last = get_name_parts("Albert Einstein")
print(f"First: {first}, Last: {last}") # First: Albert, Last: Einsteinfirst, last = get_name_parts("Marie Curie")
print(f"First: {first}, Last: {last}") # First: Marie, Last: Curiefirst, last = get_name_parts("Madonna")
print(f"First: {first}, Last: {last}") # First: Madonna, Last: Nonedef check_even(number):"""檢查數字是否為偶數。"""if number % 2 == 0:return True # 如果是偶數,返回 True 并結束函數# 如果上面的 if 不滿足,會執行到這里return Falseprint(f"4 是偶數嗎? {check_even(4)}") # True
print(f"7 是偶數嗎? {check_even(7)}") # Falsedef print_and_return_nothing(message):"""打印消息,但不顯式返回值。"""print(message)result_none = print_and_return_nothing("Hello") # 會打印 Hello
print(f"函數返回值: {result_none}")            # 輸出: 函數返回值: None

5.6 函數的作用域 (Scope)

作用域指的是變量能夠被訪問的區域。

  • 局部變量 (Local Variables): 在函數內部定義的變量(包括參數)是局部變量。它們只在函數被調用時創建,在函數執行結束時銷毀。局部變量只能在函數內部訪問,不能在函數外部訪問。

    Python

    def my_function():local_var = 10 # 局部變量print(f"函數內部: {local_var}")my_function() # 輸出: 函數內部: 10
    # 下面這行會報錯 NameError: name 'local_var' is not defined
    # print(f"函數外部: {local_var}")
    
  • 全局變量 (Global Variables): 在所有函數外部定義的變量是全局變量。它們在程序的整個生命周期內都存在。全局變量可以在程序的任何地方(包括函數內部)被讀取。

    Python

    global_var = 100 # 全局變量def read_global():print(f"函數內部讀取全局變量: {global_var}")def try_modify_global():# 試圖直接修改全局變量 (不推薦,且可能產生 UnboundLocalError)# global_var = global_var + 1 # 這會報錯,Python 認為你想創建一個新的局部變量print(f"函數內部嘗試修改前讀取: {global_var}") # 可以讀取read_global() # 輸出: 函數內部讀取全局變量: 100
    try_modify_global()
    print(f"函數外部: {global_var}") # 輸出: 函數外部: 100 (全局變量未被修改)
    
  • 修改全局變量 (global 關鍵字): 如果確實需要在函數內部修改全局變量的值,需要使用 global 關鍵字明確聲明。但通常不推薦這樣做,因為它會破壞函數的封裝性,使代碼更難理解和調試。更好的做法是將需要修改的值作為參數傳入,然后返回修改后的值。

    Python

    count = 0 # 全局變量def increment_global():global count # 聲明要修改的是全局變量 countcount += 1print(f"函數內 count: {count}")increment_global() # 輸出: 函數內 count: 1
    increment_global() # 輸出: 函數內 count: 2
    print(f"函數外 count: {count}") # 輸出: 函數外 count: 2
    

對于初學者,主要理解函數內部定義的變量是局部的,外部無法訪問即可。盡量避免使用 global 關鍵字。

5.7 匿名函數 (lambda) - (可選/簡要了解)

有時你需要一個非常簡單的、只用一次的小函數,lambda 表達式提供了一種快速定義這種匿名函數(沒有名字的函數)的方式。

語法: lambda arguments: expression

  • lambda: 關鍵字。
  • arguments: 和普通函數的參數一樣。
  • :: 分隔符。
  • expression: 一個表達式,它的計算結果就是函數的返回值(不需要 return 關鍵字)。Lambda 函數體只能包含一個表達式。

Python

# 普通函數定義
def add_regular(x, y):return x + y# 等效的 lambda 函數
add_lambda = lambda x, y: x + yprint(add_regular(5, 3)) # 8
print(add_lambda(5, 3))  # 8# 直接使用 lambda
result = (lambda a, b: a * b)(6, 7) # 定義并立即調用
print(result) # 42# lambda 常用于需要傳入簡單函數的地方,比如排序的 key
points = [(1, 2), (3, 1), (5, -4), (0, 8)]
# 按每個元組的第二個元素排序
points.sort(key=lambda point: point[1])
print(points) # [(5, -4), (3, 1), (1, 2), (0, 8)]

Lambda 對于初學者來說不是必需掌握的,了解有這樣一種簡潔寫法即可,當你看到別人代碼里用 lambda 時能大概理解它的意思就行。

5.8 實踐時間!

練習1:將之前的練習改寫成函數形式

  1. 重構閏年判斷器:
    • 定義一個函數 is_leap(year)
    • 它接收一個年份 year 作為參數。
    • 函數體包含之前判斷閏年的邏輯。
    • 函數應該返回 True(如果 year 是閏年)或 False(如果不是)。
    • 在主程序部分,獲取用戶輸入,調用 is_leap() 函數,并根據返回值打印結果。
  2. 重構簡單計算器:
    • 定義一個函數 calculate(num1, num2, operator)
    • 接收兩個數字 num1, num2 和一個代表運算符的字符串 operator ('+', '-', '*', /) 作為參數。
    • 根據 operator 執行相應的計算。
    • 返回計算結果。如果運算符無效或除數為零,可以考慮返回 None 或打印錯誤信息并返回 None
    • 在主程序部分,獲取用戶輸入的兩個數字和運算符,調用 calculate() 函數,并打印結果(如果結果不是 None)。

練習2:編寫工具函數 - 計算平均值

  1. 定義一個函數 calculate_average(numbers)
  2. 它接收一個包含數字的列表 numbers 作為參數。
  3. 函數應該計算并返回列表中所有數字的平均值。
  4. 考慮邊界情況: 如果輸入的列表 numbers 是空的,直接計算平均值會報錯(除以零)。在函數開始時檢查列表是否為空 (if not numbers: 或者 if len(numbers) == 0:),如果為空,可以返回 0 或者 None(并在文檔字符串中說明)。
  5. 測試你的函數:創建一個數字列表,調用 calculate_average() 并打印結果。也測試一下空列表的情況。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/901638.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/901638.shtml
英文地址,請注明出處:http://en.pswp.cn/news/901638.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【C++算法】61.字符串_最長公共前綴

文章目錄 題目鏈接&#xff1a;題目描述&#xff1a;解法C 算法代碼&#xff1a;解釋 題目鏈接&#xff1a; 14. 最長公共前綴 題目描述&#xff1a; 解法 解法一&#xff1a;兩兩比較 先算前兩個字符串的最長公共前綴&#xff0c;然后拿這個最長公共前綴和后面一個來比較&…

JVM 調優不再難:AI 工具自動生成內存優化方案

在 Java 應用程序的開發與運行過程中&#xff0c;Java 虛擬機&#xff08;JVM&#xff09;的性能調優一直是一項極具挑戰性的任務&#xff0c;尤其是內存優化方面。不合適的 JVM 內存配置可能會導致應用程序出現性能瓶頸&#xff0c;甚至頻繁拋出內存溢出異常&#xff0c;影響業…

紛析云開源財務軟件:企業財務數字化轉型的靈活解決方案

紛析云是一家專注于開源財務軟件研發的公司&#xff0c;自2018年成立以來&#xff0c;始終以“開源開放”為核心理念&#xff0c;致力于通過技術創新助力企業實現財務管理的數字化與智能化轉型。其開源財務軟件憑借高擴展性、靈活部署和全面的功能模塊&#xff0c;成為眾多企業…

【數字圖像處理】數字圖像空間域增強(3)

圖像銳化 圖像細節增強 圖像輪廓&#xff1a;灰度值陡然變化的部分 空間變化&#xff1a;計算灰度變化程度 圖像微分法&#xff1a;微分計算灰度梯度突變的速率 一階微分&#xff1a;單向差值 二階微分&#xff1a;雙向插值 一階微分濾波 1&#xff1a;梯度法 梯度&#xff1…

基于Linux的ffmpeg python的關鍵幀抽取

1.FFmpeg的環境配置 首先強調&#xff0c;ffmpeg-python包與ffmpeg包不一樣。 1) 創建一個虛擬環境env conda create -n yourenv python3.x conda activate yourenv2) ffmpeg-python包的安裝 pip install ffmpeg-python3) 安裝系統級別的 FFmpeg 工具 雖然安裝了 ffmpeg-p…

C#進階學習(四)單向鏈表和雙向鏈表,循環鏈表(上)單向鏈表

目錄 前置知識&#xff1a; 一、鏈表中的結點類LinkedNode 1、申明字段節點類&#xff1a; 2、申明屬性節點類: 二、兩種方式實現單向鏈表 ①定框架&#xff1a; ②增加元素的方法&#xff1a;因為是單鏈表&#xff0c;所以增加元素一定是只能在末尾添加元素&#xff0c;…

RK3588 Buildroot 串口測試工具

RK3588 Buildroot串口測試工具(含代碼) 一、引言 1.1 目的 本文檔旨在指導開發人員能快速測試串口功能 1.2 適用范圍 本文檔適用于linux 系統串口測試。 二、開發環境準備 2.1 硬件環境 開發板:RK3588開發板,確保其串口硬件連接正常,具備電源供應、調試串口等基本硬…

HOJ PZ

https://docs.hdoi.cn/deploy 單體部署 請到~/hoj-deploy/standAlone的目錄下&#xff0c;即是與docker-compose.yml的文件同個目錄下&#xff0c;該目錄下有個叫hoj的文件夾&#xff0c;里面的文件夾介紹如下&#xff1a; hoj ├── file # 存儲了上傳的圖片、上傳的臨…

EtherCAT 的優點與缺點

EtherCAT&#xff08;以太網控制自動化技術&#xff09;是一種高性能的工業以太網協議&#xff0c;廣泛應用于實時自動化控制。以下是其核心優缺點分析&#xff1a; ?一、EtherCAT 的核心優點? 1. ?超低延遲 & 高實時性? ?原理?&#xff1a;采用"?Processing…

高并發多級緩存架構實現思路

目錄 1.整體架構 3.安裝環境 1.1 使用docket安裝redis 1.2 配置redis緩存鏈接&#xff1a; 1.3 使用redisTemplate實現 1.4 緩存注解優化 1.4.1 常用緩存注解簡紹 1.4.2 EnableCaching注解的使用 1.4.3使用Cacheable 1.4.4CachePut注解的使用 1.4.5 優化 2.安裝Ngin…

Qt QML實現Windows桌面顏色提取器

前言 實現一個簡單的小工具&#xff0c;使用Qt QML實現Windows桌面顏色提取器&#xff0c;實時顯示鼠標移動位置的顏色值&#xff0c;包括十六進制值和RGB值。該功能在實際應用中比較常見&#xff0c;比如截圖的時候&#xff0c;鼠標移動就會在鼠標位置實時顯示坐標和顏色值&a…

vue3+vite 多個環境配置

同一套代碼 再也不用在不同的環境里來回切換請求地址了 然后踩了一個坑 就是env的文件路徑是在當前項目下 不是在views內 因為公司項目需求只有dev和pro兩個環境 雖然我新增了3個 但是只在這兩個里面配置了 .env是可以配置一些公共配置的 目前需求來說不需要 所以我也懶得配了。…

AI賦能PLC(一):三菱FX-3U編程實戰初級篇

前言 在工業自動化領域&#xff0c;三菱PLC以其高可靠性、靈活性和廣泛的應用場景&#xff0c;成為眾多工程師的首選控制設備。然而&#xff0c;傳統的PLC編程往往需要深厚的專業知識和經驗積累&#xff0c;開發周期長且調試復雜。隨著人工智能技術的快速發展&#xff0c;利用…

XSS 跨站Cookie 盜取表單劫持網絡釣魚溯源分析項目平臺框架

漏洞原理&#xff1a;接受輸入數據&#xff0c;輸出顯示數據后解析執行 基礎類型&#xff1a;反射 ( 非持續 ) &#xff0c;存儲 ( 持續 ) &#xff0c; DOM-BASE 拓展類型&#xff1a; jquery &#xff0c; mxss &#xff0c; uxss &#xff0c; pdfxss &#xff0c; flashx…

鴻蒙應用(醫院診療系統)開發篇2·Axios網絡請求封裝全流程解析

一、項目初始化與環境準備 1. 創建鴻蒙工程 src/main/ets/ ├── api/ │ ├── api.ets # 接口聚合入口 │ ├── login.ets # 登錄模塊接口 │ └── request.ets # 網絡請求核心封裝 └── pages/ └── login.ets # 登錄頁面邏輯…

ADAS高級駕駛輔助系統詳細介紹

ADAS&#xff08;高級駕駛輔助系統&#xff09;核心模塊&#xff0c;通過 “監測→預警→干預” 三層邏輯提升行車安全。用戶選擇車輛時&#xff0c;可關注傳感器配置&#xff08;如是否標配毫米波雷達&#xff09;、功能覆蓋場景&#xff08;如 AEB 是否支持夜間行人&#xff…

Prometheus+Grafana+K8s構建監控告警系統

一、技術介紹 Prometheus、Grafana及K8S服務發現詳解 Prometheus簡介 Prometheus是一個開源的監控系統和時間序列數據庫&#xff0c;最初由SoundCloud開發&#xff0c;現已成為CNCF(云原生計算基金會)的畢業項目?。它專注于實時監控和告警&#xff0c;特別適合云原生和分布式…

MATLAB腳本實現了一個三自由度的通用航空運載器(CAV-H)的軌跡仿真,主要用于模擬升力體在不同飛行階段(初始滑翔段、滑翔段、下壓段)的運動軌跡

%升力體:通用航空運載器CAV-H %讀取數據1 升力系數 alpha = [10 15 20]; Ma = [3.5 5 8 10 15 20 23]; alpha1 = 10:0.1:20; Ma1 = 3.5:0.1:23; [Ma1, alpha1] = meshgrid(Ma1, alpha1); CL = readmatrix(simulation.xlsx, Sheet, Sheet1, Range, B2:H4); CL1 = interp2(…

Day09【基于jieba分詞和RNN實現的簡單中文分詞】

基于jieba分詞和RNN實現的中文分詞 目標數據準備主程序預測效果 目標 本文基于給定的中文詞表&#xff0c;將輸入的文本基于jieba分詞分割為若干個詞&#xff0c;詞的末尾對應的標簽為1&#xff0c;中間部分對應的標簽為0&#xff0c;同時將分詞后的單詞基于中文詞表做初步序列…

Linux-服務器添加審計日志功能

#查看audit軟件是否在運行(狀態為active而且為綠色表示已經在運行) systemctl start auditd #如果沒有在運行的話,查看是否被系統禁用 (audit為0表示被禁用) cat /proc/cmdline | grep -w "audit=0" #修改/etc/default/grub里面audit=0 改為audit=1 #更新GRUB…