目錄
- 1 python 垃圾處理機制
- 2 yield
- 3 python 多繼承,兩個父類有同名方法怎么辦?
- 4 python 多線程/多進程/協程
- 4.1 多線程與GIL全局解釋器鎖
- 4.2 多進程
- 4.3 協程
- 5 樂觀鎖/悲觀鎖
- 6 基本數據結構
- **1. 列表(List)**
- **2. 元組(Tuple)**
- **3. 字典(Dictionary)**
- **4. 集合(Set)**
- **5. 字符串(String)**
- **6. 隊列(Queue)**
- **7. 棧(Stack)**
- **8. 堆(Heap)**
- **匯總**
- 7 `is` 和 `==` 的區別(適用于 Python 3.7)
- **示例**
- 8 什么是 Lambda 函數(適用于 Python 3.8)
- **語法**
- **示例**
- **應用場景**
- 9 函數傳參
- 10 `*args` 和 `**kwargs` 的用法與原理**
- **(1) `*args`(可變位置參數)**
- **(2) `**kwargs`(可變關鍵字參數)**
- **(3) `*args` 和 `**kwargs` 混用**
- 11 裝飾器(Decorator)的作用與原理
- **(1) 裝飾器的作用**
- **(2) 裝飾器的原理**
- 12 Python 變量的作用域
- 13 解釋型和編譯型語言的區別
- **(1) 解釋型語言**
- **(2) 編譯型語言**
- 14 `__init__ `和 `__new__ `的區別
- 15 Python 的 `list` 和 `numpy.array`(數組)的區別
- **1. 類型限制**
- **2. 性能**
- **3. 功能與方法**
- **4. 內存效率**
- **5. 維度支持**
- **6. 廣播機制**
- **總結**
- 16 Python 的面向對象(OOP)
- 1. **封裝 (Encapsulation)**
- **封裝的關鍵點:**
- **示例:**
- 2. **繼承 (Inheritance)**
- **繼承的關鍵點:**
- **示例:**
- 3. **多態 (Polymorphism)**
- **多態的關鍵點:**
- **示例:**
- **總結:**
- 17
1 python 垃圾處理機制
Python垃圾回收詳細講解
2 yield
def fibonacci(n):result = []a, b = 0, 1for _ in range(n):result.append(a) # 存儲所有 Fibonacci 數值a, b = b, a + breturn result # 一次性返回所有值fib = fibonacci(1000000) # 計算 100 萬個斐波那契數def fibonacci(n):a, b = 0, 1for _ in range(n):yield a # 每次迭代返回一個值,而不是存入列表a, b = b, a + bfib = fibonacci(1000000) # 創建生成器對象,但不立即計算
print(next(fib))
print(next(fib))
print(next(fib))
print(next(fib))
print(next(fib))
0
1
1
2
3
3 python 多繼承,兩個父類有同名方法怎么辦?
單繼承
class Parent:def greet(self):print("Hello from Parent!")class Child(Parent): # Child 繼承 Parentpassc = Child()
c.greet() # 輸出: Hello from Parent!
多繼承
class Parent1:def greet(self):print("Hello from Parent1!")class Parent2:def greet(self):print("Hello from Parent2!")class Child(Parent1, Parent2): # 繼承多個父類passc = Child()
c.greet() # 輸出什么?
Python 解決多繼承方法沖突的方法是 MRO(Method Resolution Order),即方法解析順序。在 Python 中,MRO 遵循 C3 線性化算法,它按照深度優先+廣度遍歷的方式來確定方法的調用順序。
可以用 .__ mro__ 或 mro() 方法查看 MRO:print(Child.__mro__)
(<class ‘main.Child’>, <class ‘main.Parent1’>, <class ‘main.Parent2’>, <class ‘object’>)
先查找 Child
再查找 Parent1
再查找 Parent2
最后查找 object(所有類的基類)
解決方法沖突
直接指定某個父類的方法
class Parent1:def greet(self):print("Hello from Parent1!")class Parent2:def greet(self):print("Hello from Parent2!")class Child(Parent1, Parent2):def greet(self):Parent2.greet(self) # 直接調用 Parent2 的方法c = Child()
c.greet() # 輸出: Hello from Parent2!
4 python 多線程/多進程/協程
多線程指在同一個進程內通過創建多個線程來執行任務。每個線程都可以執行不同的任務,但它們共享同一進程的內存空間和資源。
多進程是指通過創建多個進程來并行執行任務。每個進程擁有獨立的內存空間和資源,可以完全獨立地運行。
4.1 多線程與GIL全局解釋器鎖
在同一進程中創建多個線程,共享進程內存空間,通過線程調度器實現并發執行。由于 Python 的 GIL(全局解釋器鎖)GIL全局解釋器鎖,多線程在 CPU 密集型任務(如計算)下無法真正實現并行,只適用于 I/O 密集型任務(如網絡請求、文件讀寫)。
使用方式1 傳入目標方法
import threading
def worker():print('線程正在執行')
# 創建線程
t = threading.Thread(target=worker)
# 啟動線程
t.start()
# 等待線程執行完畢
t.join()使用方式2 集成重寫方法
class MyThread(threading.Thread):def run(self):print(f'{self.name} 線程正在執行')
# 創建線程實例
my_thread = MyThread()
# 啟動線程
my_thread.start()
# 等待線程執行完畢
my_thread.join()
4.2 多進程
4.3 協程
- 協程極高的執行效率。因為子程序切換不是線程切換,而是由程序自身控制,因此,沒有線程切換的開銷,和多線程比,線程數量越多,協程的性能優勢就越明顯。
- 第二大優勢就是不需要多線程的鎖機制,因為只有一個線程,也不存在同時寫變量沖突,在協程中控制共享資源不加鎖,只需要判斷狀態就好了,所以執行效率比多線程高很多。
def coroutine_example():print("Coroutine started")x = yield "First yield value"print(f"Received: {x}")y = yield "Second yield value"print(f"Received: {y}")return "Coroutine finished"# 創建協程實例
coroutine = coroutine_example()# 啟動協程,執行到第一個yield處
print(next(coroutine)) # 輸出: Coroutine started,并返回 "First yield value"# 恢復協程,傳入值給x,繼續執行到第二個yield處
print(coroutine.send(10)) # 輸出: Received: 10,并返回 "Second yield value"# 再次恢復協程,傳入值給y,繼續執行到結束
result = coroutine.send(20) # 輸出: Received: 20,然后協程結束# 捕獲協程結束時的返回值
print(f"Coroutine result: {result}") # 輸出: Coroutine result: Coroutine finished# 嘗試再次恢復協程會引發StopIteration異常
try:coroutine.send(30)
except StopIteration as e:print(f"Coroutine ended with exception: {e}") # 捕獲異常并輸出
5 樂觀鎖/悲觀鎖
悲觀鎖 適用于高并發、沖突頻繁的場景 確保同一時刻只有一個線程能訪問數據,從而避免數據不一致
樂觀鎖 適用于并發沖突較少的場景 它允許多個線程同時讀取數據,更新時檢查數據是否被修改,若有沖突則重試。
6 基本數據結構
Python 的基本數據結構主要包括以下幾類:
1. 列表(List)
- 可變,支持增刪改查
- 有序,支持索引訪問
- 允許重復元素
- 底層實現:動態數組
lst = [1, 2, 3, 4]
lst.append(5) # 添加元素
lst.pop() # 刪除末尾元素
lst[1] = 99 # 修改元素
2. 元組(Tuple)
- 不可變,一旦創建不能修改
- 有序,支持索引訪問
- 允許重復元素
- 底層實現:靜態數組
tup = (1, 2, 3, 4)
val = tup[1] # 訪問元素
3. 字典(Dictionary)
- 可變,支持動態添加鍵值對
- 無序(Python 3.6 之前),有序(Python 3.7+)
- 鍵唯一,不可變;值可變
- 底層實現:哈希表(dict 使用哈希函數存儲鍵值對)
d = {'a': 1, 'b': 2}
d['c'] = 3 # 添加鍵值對
d.pop('b') # 刪除鍵值對
4. 集合(Set)
- 可變,支持增刪元素
- 無序
- 不允許重復元素
- 底層實現:哈希表
s = {1, 2, 3}
s.add(4) # 添加元素
s.remove(2) # 刪除元素
5. 字符串(String)
- 不可變
- 有序,支持索引訪問
- 支持切片
- 底層實現:字符數組
s = "hello"
print(s[1]) # 'e'
print(s[:3]) # 'hel'
6. 隊列(Queue)
- FIFO(先進先出)
- 通常使用
collections.deque
實現
from collections import deque
q = deque()
q.append(1) # 入隊
q.popleft() # 出隊
7. 棧(Stack)
- LIFO(后進先出)
- 通常使用
list
或collections.deque
實現
stack = []
stack.append(1) # 入棧
stack.pop() # 出棧
8. 堆(Heap)
- 默認是最小堆
- Python 使用
heapq
模塊
import heapq
heap = [3, 1, 4]
heapq.heapify(heap) # 轉換為堆
heapq.heappush(heap, 2) # 入堆
heapq.heappop(heap) # 出堆(最小值)
匯總
數據結構 | 可變性 | 有序性 | 允許重復 | 適用場景 |
---|---|---|---|---|
列表(list) | ? 可變 | ? 有序 | ? 允許 | 需要動態增刪改查 |
元組(tuple) | ? 不可變 | ? 有序 | ? 允許 | 需要不可變序列 |
字典(dict) | ? 可變 | ? 有序 (Py3.7+) | ? 鍵唯一 | 需要鍵值對存儲 |
集合(set) | ? 可變 | ? 無序 | ? 不允許 | 需要去重 |
字符串(str) | ? 不可變 | ? 有序 | ? 允許 | 處理文本 |
隊列(queue) | ? 可變 | ? 有序 | ? 允許 | 先進先出(FIFO) |
棧(stack) | ? 可變 | ? 有序 | ? 允許 | 后進先出(LIFO) |
堆(heap) | ? 可變 | ? 有序 | ? 允許 | 維護最小/最大值 |
7 is
和 ==
的區別(適用于 Python 3.7)
is
比較的是對象的內存地址(是否是同一個對象)。==
比較的是對象的值(內容是否相等)。
示例
a = [1, 2, 3]
b = [1, 2, 3]
c = aprint(a == b) # True (內容相同)
print(a is b) # False (a 和 b 是不同的對象)print(a == c) # True (內容相同)
print(a is c) # True (a 和 c 指向同一對象)
8 什么是 Lambda 函數(適用于 Python 3.8)
lambda
函數是匿名函數,即沒有名字的函數,使用 lambda
關鍵字定義。
語法
lambda 參數: 表達式
示例
add = lambda x, y: x + y
print(add(3, 5)) # 8
等價于:
def add(x, y):return x + y
應用場景
- 用于
map()
、filter()
、sorted()
nums = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x**2, nums))
print(squared) # [1, 4, 9, 16, 25]even_nums = list(filter(lambda x: x % 2 == 0, nums))
print(even_nums) # [2, 4]pairs = [(1, 2), (3, 1), (5, 0)]
pairs.sort(key=lambda x: x[1])
print(pairs) # [(5, 0), (3, 1), (1, 2)]
- 作為
functools.reduce()
的參數
from functools import reduce
nums = [1, 2, 3, 4]
product = reduce(lambda x, y: x * y, nums)
print(product) # 24
9 函數傳參
類型 | 可變性 | 示例 | 函數內部修改是否影響原變量 |
---|---|---|---|
不可變對象 | ? 不可變 | int 、float 、str 、tuple | ? 不影響,創建新對象 |
可變對象 | ? 可變 | list 、dict 、set | ? 影響,會修改原對象 |
10 *args
和 **kwargs
的用法與原理**
(1) *args
(可變位置參數)
- 允許函數接收任意數量的位置參數,并將它們存儲為一個 元組 (
tuple
)。
def add(*args):return sum(args)print(add(1, 2, 3)) # 6
print(add(4, 5, 6, 7)) # 22
等價于:
def add(a, b, c):return a + b + c
原理:
*args
作用是 收集 多個位置參數,將它們封裝成一個元組傳遞給函數。
(2) **kwargs
(可變關鍵字參數)
- 允許函數接收任意數量的 關鍵字參數,并將它們存儲為 字典 (
dict
)。
def greet(**kwargs):for key, value in kwargs.items():print(f"{key} : {value}")greet(name="Alice", age=25, country="USA")
# name : Alice
# age : 25
# country : USA
原理:
**kwargs
作用是 收集 多個關鍵字參數,并存儲為字典 {key: value}
傳遞給函數。
(3) *args
和 **kwargs
混用
*args
必須放在**kwargs
之前,否則會報錯。
def demo(a, b, *args, c=10, **kwargs):print(a, b, args, c, kwargs)demo(1, 2, 3, 4, 5, c=20, x=100, y=200)
# 輸出:1 2 (3, 4, 5) 20 {'x': 100, 'y': 200}
11 裝飾器(Decorator)的作用與原理
(1) 裝飾器的作用
裝飾器用于 在不修改原函數代碼的情況下,增強函數的功能,比如:
- 計算函數執行時間
- 記錄日志
- 檢查權限
- 緩存數據
(2) 裝飾器的原理
裝飾器本質上是一個函數,它接受一個函數作為參數,并返回一個新的函數。
def decorator(func):def wrapper():print("執行前")func()print("執行后")return wrapper@decorator
def hello():print("Hello, world!")hello()
# 執行前
# Hello, world!
# 執行后
等價于:
def hello():print("Hello, world!")hello = decorator(hello)
hello()
@decorator
語法糖的作用:等價于 hello = decorator(hello)
12 Python 變量的作用域
Python 作用域遵循 LEGB 規則:
- Local(局部作用域):函數內部定義的變量。
- Enclosing(閉包作用域):外部嵌套函數的變量。
- Global(全局作用域):模塊級變量。
- Built-in(內建作用域):Python 預定義的變量,如
len()
。
x = "global"def outer():x = "enclosing"def inner():x = "local"print(x) # 輸出 "local"inner()print(x) # 輸出 "enclosing"outer()
print(x) # 輸出 "global"
13 解釋型和編譯型語言的區別
(1) 解釋型語言
- 代碼逐行執行,不需要預先編譯。
- 運行時才翻譯,直接執行。
- 適用于動態語言(Python、JavaScript)。
print("Hello, World!") # Python 解釋器逐行執行
(2) 編譯型語言
- 代碼需要 先編譯 成機器碼(
.exe
等),然后執行。 - 運行速度快,但需要編譯過程。
- 適用于靜態語言(C、C++、Rust)。
#include <stdio.h>
int main() {printf("Hello, World!");return 0;
}
編譯后生成 a.out
文件,運行時不需要解釋。
14 __init__
和 __new__
的區別
方法 | 作用 | 調用時機 |
---|---|---|
__new__ | 創建對象,返回對象實例 | 類實例化時,先調用 __new__ |
__init__ | 初始化對象,設置屬性 | __new__ 之后調用 __init__ |
class A:def __new__(cls, *args, **kwargs):print("調用 __new__")instance = super().__new__(cls)return instancedef __init__(self, name):print("調用 __init__")self.name = namea = A("Tom")
# 調用 __new__
# 調用 __init__
15 Python 的 list
和 numpy.array
(數組)的區別
雖然 list
和 numpy.array
都是可以存儲一系列元素的容器,但它們在以下幾個方面有顯著區別:
1. 類型限制
-
list
:
list
是 動態類型,可以存儲不同類型的元素,例如整數、字符串、浮點數等。元素的類型可以混合在一起。my_list = [1, "hello", 3.14]
-
numpy.array
:
numpy.array
是 同質類型,即所有元素必須是相同的數據類型(例如,全是整數或浮點數),并且在創建時會固定類型。這樣做的好處是可以更高效地進行數值計算。import numpy as np arr = np.array([1, 2, 3]) # 類型為整數
2. 性能
-
list
:
Python 的list
是為通用數據存儲設計的,它的元素可以是任何對象,因此它的操作(如訪問、添加或刪除元素)通常需要更多的內存管理和更復雜的邏輯。對于大規模數值計算或高性能需求,list
可能不夠高效。 -
numpy.array
:
numpy.array
是專門為科學計算設計的,所有元素都是同一數據類型,因此在內存中是連續存儲的。這樣可以利用低級優化(如 SIMD)來提高性能,特別是在進行大量數學運算時,numpy.array
顯著優于list
。import numpy as np arr1 = np.array([1, 2, 3, 4, 5]) arr2 = np.array([6, 7, 8, 9, 10]) result = arr1 + arr2 # 進行高效的向量加法
3. 功能與方法
-
list
:
list
是 Python 內建的數據結構,支持的基本操作包括添加、刪除、修改、切片等,但它不支持直接進行數學或向量操作。my_list = [1, 2, 3] my_list.append(4) my_list.pop()
-
numpy.array
:
numpy.array
提供了 大量的數學運算和線性代數操作,例如向量加法、矩陣乘法、元素級操作、廣播等。import numpy as np arr = np.array([1, 2, 3]) result = arr * 2 # 每個元素都乘以 2 print(result) # 輸出 [2, 4, 6]
numpy
還支持很多函數,比如矩陣乘法(np.dot()
)、求和(np.sum()
)等。
4. 內存效率
-
list
:
Python 的list
是動態數組,元素存儲為指針,因此每個元素的內存開銷較大。此外,由于 Python 的list
是動態擴展的,可能會發生重新分配內存,這也會影響性能。 -
numpy.array
:
numpy.array
使用 緊湊的內存布局,所有元素連續存儲,這使得它的內存使用更加高效,尤其是當處理大量數據時。
5. 維度支持
-
list
:
Python 的list
只能表示一維數組。如果要表示多維數據(如二維矩陣),通常會使用嵌套list
。my_list = [[1, 2], [3, 4], [5, 6]] # 需要嵌套 list 來模擬二維矩陣
-
numpy.array
:
numpy.array
支持任意維度的數組,能夠表示 一維、二維、三維 等復雜的數據結構,并可以輕松地進行切片和變形操作。arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) # 2D array
6. 廣播機制
-
list
:
list
不支持 廣播機制(Broadcasting),這意味著你不能直接對list
進行元素級的算術操作。 -
numpy.array
:
numpy.array
支持廣播機制,可以讓不同形狀的數組之間進行運算。它會自動擴展數組的形狀,以便進行元素級運算。arr = np.array([1, 2, 3]) result = arr + 10 # 結果是 [11, 12, 13]
總結
list
是 Python 內建的通用容器,適用于存儲不同類型的元素,且易于使用,但在進行數值計算時性能不佳。numpy.array
是為科學計算設計的高效數組類型,它支持同質數據存儲、廣播機制和大量的數學運算操作,特別適用于需要高性能的數值計算任務。
在處理大量數值數據時,numpy.array
更加高效。如果你的任務主要涉及到數值計算、矩陣操作等,建議使用 numpy
。而如果你需要處理混合類型的數據或進行常規的存儲,list
可能更合適。
16 Python 的面向對象(OOP)
Python 的面向對象(OOP)特性包括 封裝、繼承 和 多態,這三個是面向對象編程的核心概念。下面詳細解釋這三個特性:
1. 封裝 (Encapsulation)
封裝是指將對象的狀態(屬性)和行為(方法)綁定在一起,并對外界隱藏實現細節,只暴露必要的接口。
封裝的關鍵點:
- 私有屬性和方法:可以使用雙下劃線(
__
)將屬性或方法標記為私有,防止外部直接訪問或修改。 - 公共接口:通過公共的接口(通常是方法),提供對私有數據的訪問或操作。這樣,外部只能通過這些方法訪問和修改對象的狀態,而無法直接改變對象的內部實現。
示例:
class Person:def __init__(self, name, age):self.__name = name # 私有屬性self.__age = age # 私有屬性def get_name(self): # 公共方法return self.__namedef set_name(self, name): # 公共方法self.__name = namedef get_age(self): # 公共方法return self.__agedef set_age(self, age): # 公共方法self.__age = age# 創建對象
person = Person("Alice", 30)
print(person.get_name()) # 通過公共接口訪問私有屬性
通過封裝,我們可以控制對象的屬性的讀取和修改方式,保證對象的狀態在有效范圍內。
2. 繼承 (Inheritance)
繼承是面向對象的一種機制,允許一個類繼承另一個類的屬性和方法。繼承實現了代碼的復用,并支持子類重寫父類的方法,從而能夠對父類的行為進行定制。
繼承的關鍵點:
- 父類和子類:父類(或基類)是被繼承的類,子類(或派生類)是繼承父類的類。子類可以繼承父類的所有公有屬性和方法,也可以重寫父類的方法。
- 方法重寫:子類可以重寫父類的方法來改變或擴展其行為。
示例:
class Animal:def speak(self):print("Animal makes a sound")class Dog(Animal): # Dog 類繼承 Animal 類def speak(self): # 重寫父類方法print("Dog barks")class Cat(Animal): # Cat 類繼承 Animal 類def speak(self): # 重寫父類方法print("Cat meows")# 創建對象
dog = Dog()
dog.speak() # 輸出 Dog barkscat = Cat()
cat.speak() # 輸出 Cat meows
在上面的例子中,Dog
和 Cat
都繼承了 Animal
類,并且各自重寫了 speak
方法,實現了不同的行為。繼承讓代碼更具可復用性。
3. 多態 (Polymorphism)
多態是指同一個方法或操作可以作用于不同的對象上,并且表現出不同的行為。多態可以通過方法重寫(子類中重新定義父類方法)和接口統一來實現。
多態的關鍵點:
- 方法重寫:子類可以重寫父類的方法,使得不同子類的對象能夠調用相同的方法時表現出不同的行為。
- 統一接口:不同類型的對象可以通過統一的接口(方法)進行操作,方法的具體實現取決于對象的類型。
示例:
class Animal:def speak(self):raise NotImplementedError("Subclass must implement abstract method")class Dog(Animal):def speak(self):print("Dog barks")class Cat(Animal):def speak(self):print("Cat meows")# 創建對象
animals = [Dog(), Cat()]for animal in animals:animal.speak() # 輸出不同的行為:Dog barks 和 Cat meows
在上面的例子中,Dog
和 Cat
都繼承自 Animal
類,并重寫了 speak
方法。通過父類引用調用 speak()
方法時,Python 會根據實際的對象類型(Dog
或 Cat
)來決定調用哪個版本的 speak
方法,從而實現了多態。
總結:
- 封裝:通過限制直接訪問對象的屬性和方法,保證對象的狀態不被外部直接修改,提供了更好的數據保護和接口管理。
- 繼承:通過繼承機制,子類可以復用父類的代碼,并可以通過方法重寫擴展或修改父類的行為。
- 多態:允許同一接口根據對象的不同類型表現出不同的行為,從而使得程序更具擴展性和靈活性。
這三個特性是面向對象編程的基礎,設計更清晰、更易維護的代碼。