1. 語言基礎
1.1 數據類型與變量
Python 是一門動態類型語言,這意味著你不需要顯式聲明變量的類型。Python 解釋器會根據你賦予變量的值自動推斷其類型。這使得 Python 代碼簡潔易懂,但同時也需要注意一些潛在的問題。
1.1.1 Python 數據類型概述
Python 提供了多種內置數據類型,以下是一些常見的類型:
- 數值類型:
- 整型 (int):用于表示整數,例如 10, -5, 0
- 浮點型 (float):用于表示小數,例如 3.14, -2.5, 0.0
- 復數類型 (complex):用于表示復數,例如 2+3j
- 字符串類型 (str):用于表示文本,例如 “Hello world!”, “Python”
- 布爾類型 (bool):用于表示真假,只有
True
和False
兩種值 - 列表類型 (list):有序可變序列,用方括號
[]
包裹,元素之間用逗號,
分隔 - 元組類型 (tuple):有序不可變序列,用圓括號
()
包裹,元素之間用逗號,
分隔 - 字典類型 (dict):無序可變鍵值對集合,用花括號
{}
包裹,鍵值對之間用冒號:
分隔
1.1.2 變量聲明與賦值
在 Python 中,使用 =
符號來給變量賦值。
name = "Alice"
age = 25
is_student = True
需要注意的是,變量名必須以字母或下劃線開頭,后面可以跟字母、數字或下劃線。同時,Python 變量名區分大小寫。
1.1.3 類型轉換
有時我們需要將不同數據類型之間進行轉換,Python 提供了一些內置函數來實現類型轉換:
int()
:將其他數據類型轉換為整型float()
:將其他數據類型轉換為浮點型str()
:將其他數據類型轉換為字符串類型bool()
:將其他數據類型轉換為布爾類型
例如:
number = "10"
int_number = int(number) # 將字符串轉換為整型
1.2 運算符與表達式
運算符是用來對操作數執行特定操作的符號,表達式則是由操作數和運算符組合而成的計算公式。
1.2.1 算術運算符
算術運算符用于進行數值計算,包括:
運算符 | 描述 | 示例 | 結果 |
---|---|---|---|
+ | 加法 | 10 + 5 | 15 |
- | 減法 | 10 - 5 | 5 |
* | 乘法 | 10 * 5 | 50 |
/ | 除法 | 10 / 5 | 2.0 |
// | 整數除法 | 10 // 5 | 2 |
% | 取余 | 10 % 5 | 0 |
** | 冪運算 | 10 ** 2 | 100 |
1.2.2 比較運算符
比較運算符用于比較兩個操作數的大小或是否相等,結果為布爾值(True 或 False)。
運算符 | 描述 | 示例 | 結果 |
---|---|---|---|
== | 等于 | 10 == 5 | False |
!= | 不等于 | 10 != 5 | True |
> | 大于 | 10 > 5 | True |
< | 小于 | 10 < 5 | False |
>= | 大于等于 | 10 >= 5 | True |
<= | 小于等于 | 10 <= 5 | False |
1.2.3 邏輯運算符
邏輯運算符用于對布爾值進行操作,包括:
運算符 | 描述 | 示例 | 結果 |
---|---|---|---|
and | 邏輯與 | True and True | True |
or | 邏輯或 | True or False | True |
not | 邏輯非 | not True | False |
1.2.4 位運算符
位運算符用于對操作數的二進制位進行操作,包括:
運算符 | 描述 | 示例 | 結果 |
---|---|---|---|
& | 按位與 | 10 & 5 | 0 |
| | 按位或 | 10 | 5 | 15 |
^ | 按位異或 | 10 ^ 5 | 15 |
~ | 按位取反 | ~10 | -11 |
<< | 左移 | 10 << 2 | 40 |
>> | 右移 | 10 >> 2 | 2 |
1.2.5 賦值運算符
賦值運算符用于將值賦給變量,包括:
運算符 | 描述 | 示例 | 等價于 |
---|---|---|---|
= | 賦值 | x = 10 | x = 10 |
+= | 加法賦值 | x += 5 | x = x + 5 |
-= | 減法賦值 | x -= 5 | x = x - 5 |
*= | 乘法賦值 | x *= 5 | x = x * 5 |
/= | 除法賦值 | x /= 5 | x = x / 5 |
//= | 整數除法賦值 | x //= 5 | x = x // 5 |
%= | 取余賦值 | x %= 5 | x = x % 5 |
**= | 冪運算賦值 | x **= 5 | x = x ** 5 |
&= | 按位與賦值 | x &= 5 | x = x & 5 |
|= | 按位或賦值 | x |= 5 | x = x | 5 |
^= | 按位異或賦值 | x ^= 5 | x = x ^ 5 |
<<= | 左移賦值 | x <<= 5 | x = x << 5 |
>>= | 右移賦值 | x >>= 5 | x = x >> 5 |
1.2.6 運算符優先級
在表達式中,不同的運算符具有不同的優先級。優先級高的運算符先執行,優先級低的運算符后執行。可以使用括號 ()
來改變運算順序,括號內的表達式優先執行。
以下列出了一些常用運算符的優先級,從高到低排序:
- 冪運算
**
- 按位取反
~
- 乘法、除法、整數除法、取余
*
,/
,//
,%
- 加法、減法
+
,-
- 位運算
<<
,>>
,&
,^
,|
- 比較運算符
==
,!=
,>
,<
,>=
,<=
- 邏輯運算符
not
,and
,or
- 賦值運算符
=
,+=
,-=
,*=
,/=
,//=
等等
1.2.7 表達式
表達式是由操作數和運算符組合而成的計算公式, Python 解釋器會根據運算符的優先級和結合性來計算表達式的值。
例如:
10 + 5 * 2
:由于乘法運算符優先級高于加法運算符,所以先執行5 * 2
,得到結果 10,然后再執行10 + 10
,最終結果為 20。(10 + 5) * 2
:由于括號內的表達式優先執行,所以先執行10 + 5
,得到結果 15,然后再執行15 * 2
,最終結果為 30。
1.3 控制流語句
控制流語句允許我們控制程序執行的流程,改變程序的執行順序。它們使程序能夠根據條件做出決策,重復執行代碼塊,以及在需要時跳出循環。
1.3.1 條件語句 (if-elif-else)
條件語句根據條件判斷,選擇執行不同的代碼塊。
語法:
if 條件1:代碼塊1
elif 條件2:代碼塊2
else:代碼塊3
- if: 如果條件1為真,則執行代碼塊1。
- elif: 如果條件1為假,則判斷條件2,如果條件2為真,則執行代碼塊2。可以有多個 elif 語句。
- else: 如果所有條件都為假,則執行代碼塊3。else 語句是可選的。
示例:
score = int(input("請輸入分數:"))if score >= 90:print("優秀")
elif score >= 80:print("良好")
elif score >= 70:print("中等")
else:print("不及格")
1.3.2 循環語句 (for, while)
循環語句用于重復執行一段代碼,直到滿足特定條件為止。
for 循環
for 循環用于遍歷序列 (例如列表、元組、字符串) 中的每個元素。
語法:
for 變量 in 序列:代碼塊
- 變量: 用于保存當前迭代的元素值。
- 序列: 需要遍歷的序列。
示例:
names = ["Alice", "Bob", "Charlie"]for name in names:print("Hello, " + name)
while 循環
while 循環會一直執行代碼塊,直到條件變為假。
語法:
while 條件:代碼塊
- 條件: 循環的判斷條件。
示例:
count = 0while count < 5:print(count)count += 1
1.3.3 循環控制語句 (break, continue)
循環控制語句用于在循環中改變執行流程。
break 語句
break 語句用于立即退出循環。
示例:
for i in range(10):if i == 5:breakprint(i)
continue 語句
continue 語句用于跳過當前迭代,繼續執行下一輪循環。
示例:
for i in range(10):if i % 2 == 0:continueprint(i)
1.4 函數
函數是 Python 代碼的模塊化單元,它可以接受輸入參數,執行一系列操作,并返回結果。函數可以提高代碼的可重用性和可讀性,使程序更加模塊化和易于維護。
1.4.1 函數定義與調用
函數定義:
def 函數名(參數列表):"""函數文檔字符串"""代碼塊return 返回值
- def: 定義函數的關鍵字。
- 函數名: 函數的名稱,必須以字母或下劃線開頭,可以包含字母、數字和下劃線。
- 參數列表: 函數接受的參數列表,多個參數用逗號隔開。
- 函數文檔字符串: 描述函數功能的字符串,可以使用三引號包裹。
- 代碼塊: 函數體,包含要執行的代碼。
- return: 返回函數的結果,可以省略,此時函數返回 None。
函數調用:
函數名(參數列表)
- 函數名: 要調用的函數名稱。
- 參數列表: 傳遞給函數的參數,順序和類型要與函數定義中的參數列表一致。
示例:
def greet(name):"""向用戶問好"""print("Hello, " + name + "!")greet("Alice") # 調用 greet 函數,傳遞參數 "Alice"
1.4.2 函數參數與返回值
參數:
- 位置參數: 按順序傳遞的參數,調用函數時參數的順序要與函數定義中的參數順序一致。
- 關鍵字參數: 使用參數名和參數值對的形式傳遞參數,可以改變參數的順序。
- 默認參數: 函數定義中為參數指定默認值,如果調用函數時未提供該參數,則使用默認值。
- 可變參數: 使用 *args 來接收任意數量的位置參數,這些參數會被打包成一個元組。
- 關鍵字可變參數: 使用 **kwargs 來接收任意數量的關鍵字參數,這些參數會被打包成一個字典。
返回值:
- 函數可以使用 return 語句返回值,返回值可以是任何類型的值,包括數字、字符串、列表、字典等。
- 如果函數沒有 return 語句,則默認返回 None。
示例:
def calculate_sum(a, b=10): # b 為默認參數,默認值為 10"""計算兩個數的和"""return a + bresult = calculate_sum(5) # 調用函數,傳遞一個參數,使用 b 的默認值
print(result) # 輸出 15result = calculate_sum(5, 20) # 調用函數,傳遞兩個參數,覆蓋 b 的默認值
print(result) # 輸出 25def sum_all(*args): # 使用 *args 接收任意數量的位置參數"""計算所有參數的和"""total = 0for arg in args:total += argreturn totalresult = sum_all(1, 2, 3, 4, 5) # 傳遞多個參數
print(result) # 輸出 15
1.4.3 遞歸函數
遞歸函數是指在函數內部調用自身的函數。
示例:
def factorial(n):"""計算 n 的階乘"""if n == 0:return 1else:return n * factorial(n - 1)result = factorial(5)
print(result) # 輸出 120
注意: 遞歸函數必須有一個終止條件,否則會無限遞歸下去導致程序崩潰。
1.4.4 匿名函數 (lambda)
匿名函數是指沒有名稱的函數,使用 lambda 關鍵字定義。
語法:
lambda 參數列表: 表達式
- lambda: 定義匿名函數的關鍵字。
- 參數列表: 函數的參數列表。
- 表達式: 函數體,只能包含一個表達式,返回值為該表達式的結果。
示例:
square = lambda x: x * x
print(square(5)) # 輸出 25add = lambda x, y: x + y
print(add(10, 20)) # 輸出 30
注意: 匿名函數通常用于簡化代碼,尤其是在需要使用函數作為參數或返回值的情況下。
2. 數據結構
數據結構是組織和存儲數據的特定方式,在編程中扮演著至關重要的角色。Python 提供了多種內置數據結構,讓我們可以方便地管理數據。
2.1 列表 (List)
列表是一種有序的可變數據結構,可以存儲不同類型的元素。
2.1.1 列表創建與訪問
-
創建列表: 使用方括號
[]
包含元素,元素之間用逗號,
分隔。my_list = [1, 2, 3, "hello", True]
-
訪問元素: 使用索引訪問列表中的元素,索引從 0 開始。
print(my_list[0]) # 輸出: 1 print(my_list[3]) # 輸出: hello
-
負索引: 負索引從列表末尾開始計數,-1 代表最后一個元素,-2 代表倒數第二個元素,以此類推。
print(my_list[-1]) # 輸出: True print(my_list[-3]) # 輸出: 3
2.1.2 列表操作 (添加、刪除、修改)
-
添加元素:
append(x)
: 在列表末尾添加元素。insert(i, x)
: 在指定索引i
處插入元素x
。extend(iterable)
: 將可迭代對象的所有元素添加到列表末尾。
my_list.append(4) my_list.insert(1, "world") my_list.extend([5, 6]) print(my_list) # 輸出: [1, 'world', 2, 3, 'hello', True, 4, 5, 6]
-
刪除元素:
remove(x)
: 刪除第一個值為x
的元素。pop(i)
: 刪除指定索引i
處的元素,并返回該元素的值。del list[i]
或del list[i:j]
: 刪除指定索引或切片范圍內的元素。
my_list.remove("hello") removed_item = my_list.pop(2) del my_list[0:2] print(my_list) # 輸出: [3, True, 4, 5, 6]
-
修改元素: 使用索引直接修改元素的值。
my_list[0] = "new_value" print(my_list) # 輸出: ['new_value', True, 4, 5, 6]
2.1.3 列表遍歷
-
使用 for 循環遍歷:
for item in my_list:print(item)
-
使用索引遍歷:
for i in range(len(my_list)):print(my_list[i])
2.2 元組 (Tuple)
元組是一種有序的不可變數據結構,使用圓括號 ()
包含元素。
2.2.1 元組創建與訪問
-
創建元組: 使用圓括號
()
包含元素,元素之間用逗號,
分隔。my_tuple = (1, 2, "hello", True)
-
訪問元素: 使用索引訪問元組中的元素,索引從 0 開始。
print(my_tuple[0]) # 輸出: 1 print(my_tuple[2]) # 輸出: hello
-
負索引: 負索引從元組末尾開始計數,-1 代表最后一個元素,-2 代表倒數第二個元素,以此類推。
print(my_tuple[-1]) # 輸出: True print(my_tuple[-3]) # 輸出: 2
2.2.2 元組不可變性
元組是不可變的,這意味著一旦創建,就不能修改其元素。
my_tuple[0] = "new_value" # 會導致錯誤
2.2.3 元組與列表的區別
特性 | 列表 | 元組 |
---|---|---|
可變性 | 可變 | 不可變 |
括號 | [] | () |
使用場景 | 存儲需要修改的數據 | 存儲不需要修改的數據 |
- 列表適合存儲需要頻繁添加、刪除、修改元素的數據。
- 元組適合存儲不需要修改的數據,例如存儲常量、坐標等。
2.3 字典 (Dictionary)
字典是一種無序的鍵值對集合,使用花括號 {}
包含鍵值對,鍵和值之間用冒號 :
分隔,鍵值對之間用逗號 ,
分隔。
2.3.1 字典創建與訪問
-
創建字典: 使用花括號
{}
包含鍵值對。my_dict = {"name": "John", "age": 30, "city": "New York"}
-
訪問元素: 使用鍵訪問字典中的值。
print(my_dict["name"]) # 輸出: John print(my_dict["age"]) # 輸出: 30
-
不存在的鍵: 訪問不存在的鍵會導致
KeyError
錯誤。print(my_dict["hobby"]) # 拋出 KeyError
-
使用
get()
方法訪問:get()
方法可以安全地訪問鍵,如果鍵不存在,則返回None
或指定的值。print(my_dict.get("hobby")) # 輸出: None print(my_dict.get("hobby", "unknown")) # 輸出: unknown
2.3.2 字典操作 (添加、刪除、修改)
-
添加元素: 使用新的鍵和值直接賦值。
my_dict["hobby"] = "reading" print(my_dict) # 輸出: {'name': 'John', 'age': 30, 'city': 'New York', 'hobby': 'reading'}
-
刪除元素:
del dict[key]
: 刪除指定鍵的鍵值對。pop(key)
: 刪除指定鍵的鍵值對,并返回該鍵對應的值。
del my_dict["city"] print(my_dict) # 輸出: {'name': 'John', 'age': 30, 'hobby': 'reading'}city = my_dict.pop("hobby") print(my_dict) # 輸出: {'name': 'John', 'age': 30} print(city) # 輸出: reading
-
修改元素: 使用鍵直接修改值。
my_dict["age"] = 31 print(my_dict) # 輸出: {'name': 'John', 'age': 31, 'hobby': 'reading'}
2.3.3 字典遍歷
-
遍歷鍵: 使用
for key in dict.keys()
遍歷字典的所有鍵。for key in my_dict.keys():print(key) # 輸出: name, age, hobby
-
遍歷值: 使用
for value in dict.values()
遍歷字典的所有值。for value in my_dict.values():print(value) # 輸出: John, 31, reading
-
遍歷鍵值對: 使用
for key, value in dict.items()
遍歷字典的所有鍵值對。for key, value in my_dict.items():print(f"{key}: {value}") # 輸出: name: John, age: 31, hobby: reading
2.4 集合 (Set)
集合是一種無序的、不可重復的元素集合,使用花括號 {}
包含元素,元素之間用逗號 ,
分隔。
2.4.1 集合創建與訪問
-
創建集合: 使用花括號
{}
包含元素。
注意:空集合必須使用set()
函數創建。my_set = {1, 2, 3, 4} empty_set = set()
-
訪問元素: 集合是無序的,無法通過索引訪問元素。可以判斷元素是否存在于集合中:
print(1 in my_set) # 輸出: True print(5 in my_set) # 輸出: False
2.4.2 集合操作 (交集、并集、差集)
-
交集: 使用
&
或intersection()
方法求兩個集合的交集。set1 = {1, 2, 3} set2 = {2, 3, 4} intersection_set = set1 & set2 print(intersection_set) # 輸出: {2, 3}
-
并集: 使用
|
或union()
方法求兩個集合的并集。union_set = set1 | set2 print(union_set) # 輸出: {1, 2, 3, 4}
-
差集: 使用
-
或difference()
方法求兩個集合的差集。difference_set = set1 - set2 print(difference_set) # 輸出: {1}
2.4.3 集合的不可重復性
集合中的元素是唯一的,不允許重復。
my_set = {1, 2, 2, 3}
print(my_set) # 輸出: {1, 2, 3}
3. 面向對象編程
面向對象編程 (OOP) 是一種編程范式,它將程序視為一組相互作用的對象,每個對象都包含數據和操作這些數據的函數。OOP 幫助組織和管理大型程序,使其更容易維護和擴展。
3.1 類與對象
3.1.1 類定義
-
類 是對象的藍圖,它定義了對象的屬性和方法。
-
在 Python 中,使用
class
關鍵字定義類,后面跟著類名和冒號:class Dog:# 類體
-
類體包含了類的屬性和方法的定義。
3.1.2 對象創建
-
對象 是類的實例,它擁有類定義的屬性和方法。
-
在 Python 中,使用類名和括號創建對象:
my_dog = Dog()
-
這行代碼創建了一個名為
my_dog
的Dog
類對象。
3.1.3 屬性與方法
-
屬性 是對象的特征,通常用變量表示。
-
方法 是對象的行為,通常用函數表示。
class Dog:def __init__(self, name, breed):self.name = nameself.breed = breeddef bark(self):print(f"{self.name} barks!")
-
__init__
方法是構造函數,用于初始化對象屬性。 -
self
參數表示當前對象,用于訪問對象的屬性和方法。 -
bark
方法定義了狗叫的行為。
3.1.3 實例化和調用類的方法
class Dog:def __init__(self, name, breed):self.name = nameself.breed = breeddef bark(self):print(f"{self.name} barks!")my_dog = Dog("Buddy", "Golden Retriever")
print(f"My dog's name is {my_dog.name} and it's a {my_dog.breed}.")
my_dog.bark()
3.2 封裝
封裝是面向對象編程中的一個重要概念,它將數據和操作數據的方法捆綁在一起,形成一個獨立的、自包含的單元,即對象。封裝的目標是隱藏對象的內部實現細節,只對外暴露必要的接口,以控制對對象的訪問。
3.2.1 類
類是封裝的核心概念,它定義了對象的屬性和方法。屬性表示對象的特征,方法表示對象的行為。
class Dog:def __init__(self, name, breed):self.name = nameself.breed = breeddef bark(self):print("Woof!")my_dog = Dog("Buddy", "Golden Retriever")
print(my_dog.name) # 輸出:Buddy
my_dog.bark() # 輸出:Woof!
3.2.2 私有屬性和方法
- 使用雙下劃線
__
開頭的屬性和方法被認為是私有的,只能在類內部訪問。 - 私有屬性和方法有助于隱藏實現細節,防止外部代碼誤操作。
class Dog:def __init__(self, name, breed):self.name = nameself.__breed = breed # 私有屬性def bark(self):print("Woof!")def __private_method(self): # 私有方法print("This is a private method.")my_dog = Dog("Buddy", "Golden Retriever")
print(my_dog.name) # 可以訪問公有屬性
# print(my_dog.__breed) # AttributeError: private access
my_dog.bark() # 可以調用公有方法
# my_dog.__private_method() # AttributeError: private access
注意: 雖然 Python 的私有機制是通過名稱改寫來實現的,仍然可以通過一些技巧來訪問私有屬性和方法。例如,使用 _ClassName__attribute_name
或者 _ClassName__method_name
可以訪問私有屬性和方法。
# 通過名稱改寫訪問私有屬性
print(my_dog._Dog__breed) # 輸出:Golden Retriever# 通過名稱改寫訪問私有方法
my_dog._Dog__private_method() # 輸出:This is a private method.
3.2.3 屬性裝飾器
- Python 中可以使用
@property
裝飾器將方法轉換為屬性,允許開發者通過類似訪問屬性的方式來調用方法。 - 同時,可以使用
@name.setter
和@name.deleter
裝飾器來定義屬性的 setter 和 deleter 方法,分別用于設置和刪除屬性的值。 - 使用屬性裝飾器可以更方便地控制對屬性的訪問,并隱藏內部實現細節。
class Dog:def __init__(self, name, breed):self._name = nameself._breed = breed@propertydef name(self):return self._name@name.setterdef name(self, value):self._name = value@name.deleterdef name(self):del self._namemy_dog = Dog("Buddy", "Golden Retriever")
print(my_dog.name) # 輸出:Buddy
my_dog.name = "Max"
print(my_dog.name) # 輸出:Max
del my_dog.name
# print(my_dog.name) # AttributeError: 'Dog' object has no attribute 'name'
3.2.4 模塊和包
- 模塊: 模塊是包含 Python 代碼的獨立文件,可以將相關的代碼封裝在一起,方便管理和重用。
- 包: 包是包含多個模塊的文件夾,可以將多個相關的模塊組織在一起,方便大型項目管理。
# 模塊
# my_module.py
def greet(name):print(f"Hello, {name}!")# 使用模塊
import my_module
my_module.greet("Alice")# 包
# package/__init__.py
# package/module1.py
# package/module2.py
# ...# 使用包
from package import module1
module1.some_function()
模塊和包可以有效地隱藏內部實現細節,提高代碼可讀性和可維護性。
3.3 繼承
繼承是面向對象編程中重要的概念之一,它允許創建一個新的類(子類)繼承另一個類的屬性和方法(父類),從而實現代碼復用和擴展。
3.3.1 單繼承
單繼承是指一個子類只繼承一個父類。使用 class 子類名(父類名):
語法實現單繼承。
class Animal:"""定義一個動物類"""def __init__(self, name):self.name = namedef speak(self):print("Animal sound")class Dog(Animal):"""定義一個狗類,繼承自 Animal 類"""def speak(self):print("Woof!")my_dog = Dog("Buddy")
my_dog.speak() # 輸出 "Woof!"
在 Dog
類中,我們使用 Animal
作為父類進行繼承。子類 Dog
可以訪問父類 Animal
中的屬性和方法。需要注意的是,子類 Dog
重寫了父類的 speak
方法,實現了特定于狗的行為。
3.3.2 多繼承
多繼承是指一個子類可以繼承多個父類。使用 class 子類名(父類1, 父類2, ...):
語法實現多繼承。
class Flyer:"""定義一個飛行類"""def fly(self):print("Flying...")class Swimmer:"""定義一個游泳類"""def swim(self):print("Swimming...")class Duck(Flyer, Swimmer):"""定義一個鴨子類,繼承自 Flyer 和 Swimmer 類"""def quack(self):print("Quack!")my_duck = Duck()
my_duck.fly() # 輸出 "Flying..."
my_duck.swim() # 輸出 "Swimming..."
my_duck.quack() # 輸出 "Quack!"
在 Duck
類中,我們繼承了 Flyer
和 Swimmer
類。Duck
類可以訪問這兩個父類的屬性和方法。多繼承可以實現更加復雜的類關系,但需要注意的是,多繼承可能會導致一些復雜的問題,例如方法名沖突和菱形繼承問題。
注意:
- 子類可以重寫父類的方法,實現特定于子類的行為。
- 多繼承可能會導致一些復雜的問題,例如方法名沖突和菱形繼承問題。
3.4 多態
多態是面向對象編程中的一個重要概念,它指的是同一個操作在不同的對象上表現出不同的行為。這使得代碼更加靈活、可擴展和易于維護。
3.4.1 方法重寫
方法重寫是實現多態的一種方式。子類可以重寫父類的方法,實現特定于子類的行為。
示例:
class Animal:def speak(self):print("Animal sound")class Dog(Animal):def speak(self):print("Woof!")class Cat(Animal):def speak(self):print("Meow!")animals = [Dog(), Cat(), Animal()]
for animal in animals:animal.speak() # 輸出 "Woof!", "Meow!", "Animal sound"
在上面的例子中,Dog
和 Cat
類都重寫了 Animal
類的 speak
方法,實現了各自不同的聲音。通過循環遍歷 animals
列表,調用每個對象的 speak
方法,我們可以看到不同的對象表現出不同的行為。
方法重寫的規則:
- 子類方法的名稱必須與父類方法的名稱相同。
- 子類方法的參數列表必須與父類方法的參數列表相同。
- 子類方法的返回值類型必須與父類方法的返回值類型相同或兼容。
- 子類方法的訪問權限必須與父類方法的訪問權限相同或更寬松。
3.4.2 多態的應用場景
多態在面向對象編程中有著廣泛的應用場景,例如:
- 代碼復用: 通過重寫父類的方法,可以實現不同類型的對象共享同一個接口,而無需編寫重復的代碼。
- 可擴展性: 通過繼承和方法重寫,可以輕松地添加新的對象類型,而無需修改現有代碼。
- 代碼簡潔: 多態可以使代碼更加簡潔,避免重復的條件判斷。
- 易于維護: 多態可以提高代碼的可讀性和可維護性,使代碼更容易理解和修改。
示例:
假設我們要開發一個游戲,其中包含不同的角色,例如戰士、法師和弓箭手。我們可以使用多態來實現角色的行為,例如攻擊、防御和技能。
class Character:def attack(self):print("General attack")class Warrior(Character):def attack(self):print("Warrior attack with sword")class Mage(Character):def attack(self):print("Mage attack with magic")characters = [Warrior(), Mage(), Character()]
for character in characters:character.attack() # 輸出 "Warrior attack with sword", "Mage attack with magic", "General attack"
通過多態,我們可以用統一的方式處理不同角色的攻擊行為,而無需關心角色的具體類型。
4. 常用模塊
模塊是 Python 代碼的組織單元,它可以包含函數、類、變量等。使用模塊可以提高代碼的可重用性和可維護性。
4.1 模塊導入
在 Python 中,可以使用 import
語句導入模塊。
4.1 導入整個模塊
import mathprint(math.pi)
print(math.sqrt(25))
這將導入 math
模塊,并使用 math.pi
和 math.sqrt()
訪問模塊中的常量和函數。
4.2 導入特定屬性
from math import pi, sqrtprint(pi)
print(sqrt(25))
這將只導入 math
模塊中的 pi
和 sqrt
屬性,并直接使用它們。
4.3 導入模塊并指定別名
import math as mprint(m.pi)
print(m.sqrt(25))
這將導入 math
模塊并將其指定為 m
,可以使用 m.pi
和 m.sqrt()
訪問模塊中的屬性。
4.4 導入所有屬性
from math import *print(pi)
print(sqrt(25))
這將導入 math
模塊中的所有屬性,但建議不要使用這種方式,因為它會導致命名沖突。
4.5 模塊搜索路徑
Python 在導入模塊時會搜索以下路徑:
- 當前目錄
- 環境變量
PYTHONPATH
中指定的目錄 - 標準庫目錄
4.2 常用模塊介紹
以下是幾個 Python 中常用的模塊的介紹:
4.2.1 math 模塊
math
模塊提供了大量的數學函數和常量,可以幫助我們進行各種數學運算。
常用函數:
pi
: 圓周率sqrt(x)
: 求平方根pow(x, y)
: 求 x 的 y 次方sin(x)
,cos(x)
,tan(x)
: 三角函數ceil(x)
: 向上取整floor(x)
: 向下取整log(x)
: 自然對數log10(x)
: 以 10 為底的對數
示例:
import mathprint(math.pi) # 輸出圓周率
print(math.sqrt(25)) # 輸出 5
print(math.pow(2, 3)) # 輸出 8
print(math.sin(math.pi / 2)) # 輸出 1
print(math.ceil(3.14)) # 輸出 4
print(math.floor(3.14)) # 輸出 3
4.2.2 random 模塊
random
模塊提供了生成隨機數的功能,可以用于各種場景,例如模擬隨機事件、洗牌等。
常用函數:
random()
: 生成 0 到 1 之間的隨機浮點數randint(a, b)
: 生成 a 到 b 之間的隨機整數choice(seq)
: 從序列中隨機選擇一個元素shuffle(seq)
: 打亂序列的元素順序sample(seq, k)
: 從序列中隨機抽取 k 個元素
示例:
import randomprint(random.random()) # 輸出 0 到 1 之間的隨機浮點數
print(random.randint(1, 10)) # 輸出 1 到 10 之間的隨機整數
print(random.choice(["apple", "banana", "orange"])) # 輸出 "apple", "banana" 或 "orange" 之一
numbers = [1, 2, 3, 4, 5]
random.shuffle(numbers) # 打亂 numbers 列表的元素順序
print(numbers)
print(random.sample(numbers, 2)) # 從 numbers 列表中隨機抽取 2 個元素
4.2.3 os 模塊
os
模塊提供了與操作系統交互的功能,可以用來執行操作系統命令、操作文件和目錄等。
常用函數:
getcwd()
: 獲取當前工作目錄chdir(path)
: 改變工作目錄listdir(path)
: 列出指定目錄下的所有文件和子目錄mkdir(path)
: 創建目錄makedirs(path)
: 創建多級目錄remove(path)
: 刪除文件rmdir(path)
: 刪除空目錄rename(old_path, new_path)
: 重命名文件或目錄system(command)
: 執行操作系統命令environ
: 獲取環境變量字典
示例:
import osprint(os.getcwd()) # 輸出當前工作目錄
os.chdir("/tmp") # 改變工作目錄到 /tmp
print(os.listdir("/tmp")) # 列出 /tmp 目錄下的所有文件和子目錄
os.mkdir("/tmp/mydir") # 創建目錄 /tmp/mydir
os.remove("/tmp/mydir/myfile.txt") # 刪除文件 /tmp/mydir/myfile.txt
os.rename("/tmp/mydir", "/tmp/mynewdir") # 重命名目錄 /tmp/mydir 為 /tmp/mynewdir
os.system("ls -l") # 執行 ls -l 命令
print(os.environ["HOME"]) # 輸出環境變量 HOME 的值
4.2.4 datetime 模塊
datetime
模塊提供了與日期和時間相關的功能,可以用來創建、格式化、計算日期和時間等。
常用類:
datetime.date
: 表示日期datetime.time
: 表示時間datetime.datetime
: 表示日期和時間
常用方法:
now()
: 獲取當前日期和時間today()
: 獲取當前日期strftime(format)
: 格式化日期和時間strptime(string, format)
: 解析日期和時間字符串
示例:
import datetimenow = datetime.datetime.now() # 獲取當前日期和時間
print(now)
print(now.strftime("%Y-%m-%d %H:%M:%S")) # 格式化日期和時間
birthday = datetime.date(1990, 1, 1) # 創建日期對象
print(birthday)
date_str = "2023-04-01"
date = datetime.datetime.strptime(date_str, "%Y-%m-%d").date() # 解析日期字符串
print(date)
4.2.5 requests 模塊
requests
模塊提供了與網絡請求相關的功能,可以用來發送 HTTP 請求、獲取網頁內容等。
常用方法:
get(url)
: 發送 GET 請求post(url, data)
: 發送 POST 請求put(url, data)
: 發送 PUT 請求delete(url)
: 發送 DELETE 請求json()
: 獲取響應內容的 JSON 格式text
: 獲取響應內容的文本格式status_code
: 獲取響應狀態碼
示例:
import requestsresponse = requests.get("https://www.google.com") # 發送 GET 請求
print(response.status_code) # 輸出響應狀態碼
print(response.text) # 輸出響應內容的文本格式
response = requests.post("https://www.example.com/api/login", data={"username": "user", "password": "password"}) # 發送 POST 請求
print(response.json()) # 輸出響應內容的 JSON 格式
注意: requests
模塊不是 Python 的內置模塊,需要使用 pip
安裝。
pip install requests
這些只是 Python 中常用的模塊的一部分,還有很多其他的模塊可以滿足各種需求,請參考官方文檔或其他學習資源進行更深入的了解。
5. 常見錯誤與調試
程序員在編寫代碼時不可避免地會遇到各種錯誤。了解常見的錯誤類型、掌握錯誤處理機制以及調試技巧是編寫高質量代碼的關鍵。
5.1 常見錯誤類型
Python 中常見的錯誤類型包括:
5.1.1 語法錯誤 (SyntaxError)
- 代碼結構或語法不符合 Python 規范。
- 例如:缺少冒號、括號不匹配、變量未定義等。
5.1.2 運行時錯誤 (RuntimeError)
- 運行時錯誤,也稱為異常,是在程序執行過程中發生的錯誤。它們會導致程序無法正常執行,并可能引發崩潰或其他意外行為。
5.1.3 邏輯錯誤 (Logical Error)
- 代碼邏輯存在問題,導致程序無法正常運行或產生錯誤結果。
- 例如:循環條件錯誤、算法邏輯錯誤等。
5.1.4 常見的運行時錯誤類型
-
TypeError
- 描述:類型錯誤,發生在操作數的類型不匹配時。
- 例子:
print("Hello" + 10) # TypeError: can only concatenate str (not "int") to str
-
ValueError
- 描述:值錯誤,發生在函數接收了類型正確但值不合法的數據時。
- 例子:
int("abc") # ValueError: invalid literal for int() with base 10: 'abc'
-
NameError
- 描述:名稱錯誤,發生在訪問未定義的變量時。
- 例子:
print(my_variable) # NameError: name 'my_variable' is not defined
-
IndexError
- 描述:索引錯誤,發生在訪問列表、元組或字符串時,索引超出了范圍。
- 例子:
my_list = [1, 2, 3] print(my_list[3]) # IndexError: list index out of range
-
KeyError
- 描述:鍵錯誤,發生在訪問字典時,指定的鍵不存在。
- 例子:
my_dict = {"name": "John"} print(my_dict["age"]) # KeyError: 'age'
-
AttributeError
- 描述:屬性錯誤,發生在訪問對象不存在的屬性時。
- 例子:
my_str = "Hello" print(my_str.length) # AttributeError: 'str' object has no attribute 'length'
-
IOError
- 描述:輸入/輸出錯誤,發生在與文件或網絡進行交互時出現問題。
- 例子:
with open("nonexistent_file.txt", "r") as f: # IOError: [Errno 2] No such file or directory: 'nonexistent_file.txt'content = f.read()
注意:
- 這些錯誤會在運行時發生,而不是在編譯時發生。
- 使用
try...except
語句可以捕獲這些錯誤并進行處理,從而避免程序崩潰。
通過理解常見的運行時錯誤類型,可以更有效地編寫和調試代碼,并確保程序的穩定性和可靠性。
5.2 錯誤處理機制 (try-except)
try-except 語句是 Python 中強大的錯誤處理機制,它允許你在程序執行過程中捕獲并處理異常。
5.2.1 語法
try:# 可能引發錯誤的代碼
except 錯誤類型1:# 處理錯誤類型1的代碼
except 錯誤類型2:# 處理錯誤類型2的代碼...
else:# 如果沒有錯誤,執行此代碼塊
finally:# 無論是否發生錯誤,都會執行此代碼塊
5.2.2 捕獲不同錯誤類型
try:num1 = int(input("請輸入第一個數: "))num2 = int(input("請輸入第二個數: "))result = num1 / num2print(f"{num1} 除以 {num2} 等于 {result}")
except ZeroDivisionError:print("除數不能為零!")
except ValueError:print("請輸入有效的整數!")
else:print("計算成功!")
finally:print("程序結束!")
解釋:
- 該代碼嘗試從用戶獲取兩個整數,并計算它們的商。
- 如果用戶輸入的第二個數為 0,則會引發
ZeroDivisionError
異常,程序會捕獲該異常并打印錯誤信息。 - 如果用戶輸入的不是整數,則會引發
ValueError
異常,程序會捕獲該異常并打印錯誤信息。 - 如果沒有發生任何異常,程序會成功計算結果并打印。
- 最后,無論是否發生異常,
finally
代碼塊都會執行,打印 “程序結束!”。
5.2.3 捕獲所有錯誤和錯誤信息
除了捕獲特定類型的錯誤,還可以使用 Exception
來捕獲所有類型的錯誤。
語法:
try:# 可能引發錯誤的代碼
except Exception as e:# 處理錯誤print(f"發生錯誤: {e}")
Exception
是所有錯誤類型的父類,因此使用Exception
可以捕獲所有類型的錯誤。as e
將錯誤對象賦值給變量e
,可以方便地獲取錯誤信息。- 在
except
代碼塊中,使用f-string
格式化輸出錯誤信息。
示例:
try:num1 = int(input("請輸入第一個數: "))num2 = int(input("請輸入第二個數: "))result = num1 / num2print(f"計算結果: {result}")
except Exception as e:print(f"發生錯誤: {e}")
finally:print("程序結束")
解釋:
- 如果輸入的兩個數都是數字,且除數不為零,程序會正常計算并輸出結果。
- 如果輸入的除數為零,程序會輸出 “發生錯誤: division by zero”。
- 如果輸入的不是數字,程序會輸出 "發生錯誤: invalid literal for int() with base 10: ‘…’ " (其中 “…” 是用戶輸入的非數字字符)。
- 無論程序是否出錯,都會輸出 “程序結束”。
其他需要注意的點:
- 雖然可以使用
Exception
捕獲所有類型的錯誤,但一般建議捕獲特定的錯誤類型,以便更精準地處理錯誤。 - 可以使用
e.__class__.__name__
獲取錯誤類型的名稱。
示例:
try:# 可能引發錯誤的代碼
except Exception as e:print(f"發生錯誤類型: {e.__class__.__name__}")print(f"錯誤信息: {e}")
5.3 調試技巧
調試是程序員必備技能之一,用于發現并解決代碼中的錯誤。常見的調試技巧包括:
5.3.1 打印調試信息 (print)
在代碼中插入 print
語句,打印變量的值或執行流程,幫助定位錯誤。
def calculate(a, b):print(f"a: {a}, b: {b}")result = a + bprint(f"result: {result}")return resultcalculate(5, 10)
5.3.2 使用調試器 (debugger)
Python 內置的調試器 pdb
可以逐步執行代碼,查看變量的值和執行流程。
import pdbdef calculate(a, b):pdb.set_trace() # 設置斷點result = a + breturn resultcalculate(5, 10)
5.3.3 使用日志 (logging)
將錯誤信息記錄到日志文件中,便于分析和排查問題。
import logginglogging.basicConfig(filename='app.log', level=logging.DEBUG)def calculate(a, b):logging.debug(f"a: {a}, b: {b}")result = a + blogging.debug(f"result: {result}")return resultcalculate(5, 10)
5.3.4 使用斷言 (assert)
在代碼中插入斷言,用于驗證程序邏輯,一旦斷言失敗,程序會拋出異常。
def calculate(a, b):assert a > 0, "a 必須大于 0"result = a + breturn resultcalculate(5, 10)