第一章:類定義的基礎概念

1.1 類定義的起源與演變

類定義的概念源於Simula語言,但Python的實現深受Smalltalk和C++影響。Guido van Rossum在Python 0.9中引入類,作為動態語言的輕量級OOP實現。早期,Python 2區分“舊式類”(經典繼承)和“新式類”(現代繼承),後者引入了super()和描述符協議。從Python 3起,所有類均為新式類,統一了繼承模型。

為什麼類定義如此重要?Python是鴨子類型語言(“如果它走路像鴨子,叫聲像鴨子,那就是鴨子”),類定義通過協議(protocols)而非嚴格接口實現多態。這讓類更靈活:無需顯式繼承,就能通過實現相同方法“兼容”。在函數式視角下,類方法是“有狀態的函數”,實例變量是閉包般的狀態捕獲。

演變亮點包括:

  • Python 3.6:dataclasses簡化了樣板代碼。
  • Python 3.7:dataclasses後置字段。
  • Python 3.9:結構化模式匹配擴展了類的使用。
  • Python 3.10+:參數規範和更好的錯誤消息。

這些變化讓類定義從靜態聲明轉向動態工具,尤其在AI和數據工程領域。

1.2 基本語法:class關鍵字的使用

類定義以class關鍵字開頭,後跟類名(PascalCase約定)和可選基類:

class MyClass:
    """類文檔字符串:描述類的目的和用法。"""
    
    # 類變量:所有實例共享
    class_var = "共享值"
    
    def __init__(self, arg1, arg2):
        """初始化方法,相當於構造函數。"""
        self.instance_var = arg1  # 實例變量
        self._protected = arg2   # 約定:保護變量(單下劃線)
    
    def public_method(self):
        """公共方法:可從外部調用。"""
        return f"實例變量: {self.instance_var}"
    
    def _internal_method(self):
        """內部方法:約定不從外部調用。"""
        return self._protected * 2

創建實例:

obj = MyClass("hello", 42)
print(obj.public_method())  # 實例變量: hello
print(MyClass.class_var)    # 共享值

注意:Python無私有成員,一切基於約定(_private、__name mangling)。__init__是特殊方法(dunder),不是真正的構造函數——實例在__new__中創建,__init__僅初始化。

類體在定義時執行,適合定義類變量或執行一次性初始化:

class DynamicClass:
    counter = 0  # 類變量
    
    def __init__(self):
        DynamicClass.counter += 1  # 靜態計數

1.3 類與實例:命名空間與屬性解析

類是一個命名空間,存儲方法和類變量;實例有自己的__dict__字典。屬性查找順序(MRO,Method Resolution Order)從實例到類,再到基類。

示例:屬性動態添加

class FlexibleClass:
    def __init__(self):
        self.dynamic_attr = "動態添加"

obj = FlexibleClass()
obj.new_method = lambda: "新方法"  # 動態綁定
print(obj.new_method())  # 新方法

這體現了Python的動態性:類定義後仍可修改。但在生產中,避免過度動態化,以維護可讀性。

類變量 vs 實例變量:

class Counter:
    count = 0  # 類變量
    
    def __init__(self):
        self.local_count = Counter.count  # 複製到實例
        Counter.count += 1

c1 = Counter()
c2 = Counter()
print(c1.local_count, c2.local_count)  # 0 1
print(Counter.count)  # 2

修改類變量影響所有實例,除非實例有同名屬性。

1.4 類作為函數:可調用類

類本身是可調用的,返回新實例:

class CallableClass:
    def __init__(self, value):
        self.value = value
    
    def __call__(self, *args, **kwargs):
        """使實例可調用。"""
        return self.value + sum(args)

cls = CallableClass(10)
instance = cls(5)  # __init__調用,等價於CallableClass(5)
result = instance(1, 2)  # __call__調用,13

這讓類像高階函數:接受參數創建“函數工廠”。

第二章:類方法與函數的互動

2.1 實例方法:綁定到self

實例方法是類定義的核心函數形式。第一參數隱式為self:

class BankAccount:
    def __init__(self, balance=0):
        self.balance = balance
    
    def deposit(self, amount):
        """存款方法。"""
        if amount > 0:
            self.balance += amount
        return self.balance
    
    def withdraw(self, amount):
        """取款方法。"""
        if 0 < amount <= self.balance:
            self.balance -= amount
        return self.balance

account = BankAccount(100)
print(account.deposit(50))  # 150

self是實例引用,確保方法訪問正確狀態。脱綁(unbound)方法:account.deposit 是函數對象,可手動調用account.deposit(account, 50)。

2.2 類方法:@classmethod裝飾器

類方法綁定到類本身,用cls參數:

class BankAccount:
    rate = 0.05  # 類變量:利率
    
    @classmethod
    def from_string(cls, account_str):
        """類方法:從字符串創建實例。"""
        name, balance = account_str.split(':')
        return cls(name, float(balance))  # cls替代BankAccount
    
    def __init__(self, name, balance):
        self.name = name
        self.balance = balance

# 使用
account = BankAccount.from_string("Alice:1000")
print(account.balance)  # 1000.0

優勢:子類調用時,使用子類創建實例,支持工廠模式。

2.3 靜態方法:@staticmethod裝飾器

靜態方法如普通函數,掛載在類上,無綁定:

class MathUtils:
    @staticmethod
    def add(x, y):
        """靜態方法:純函數,無需實例。"""
        return x + y
    
    @staticmethod
    def is_prime(n):
        if n < 2:
            return False
        for i in range(2, int(n**0.5) + 1):
            if n % i == 0:
                return False
        return True

print(MathUtils.add(3, 4))      # 7
print(MathUtils.is_prime(17))   # True

適合工具函數,避免污染命名空間。

2.4 方法解析順序:MRO與super()

多繼承時,MRO決定調用順序。用C3線性化算法計算:

class A:
    def method(self):
        print("A")

class B(A):
    pass

class C(A):
    def method(self):
        print("C")
        super().method()  # 調用A

class D(B, C):  # MRO: D -> B -> C -> A
    def method(self):
        print("D")
        super().method()  # B無method,跳C

d = D()
d.method()
# 輸出: D
#       C
#       A

super()動態分派,確保正確基類調用。在單繼承中,也推薦super()以便未來擴展。

第三章:特殊方法:讓類像內置類型

3.1 初始化與銷燬:new__與__del

__new__是靜態方法,控制實例創建:

class Singleton:
    _instance = None
    
    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance
    
    def __init__(self):
        self.value = "Singleton value"

s1 = Singleton()
s2 = Singleton()
print(s1 is s2)  # True

__del__是析構器,在垃圾回收時調用:

class Resource:
    def __init__(self, name):
        self.name = name
        print(f"創建 {name}")
    
    def __del__(self):
        print(f"銷燬 {self.name}")

r = Resource("文件句柄")
del r  # 觸發__del__

注意:__del__不保證立即調用,受循環引用影響。用contextmanager替代資源管理。

3.2 表示方法:str、repr__與__format

自定義字符串表示:

class Point:
    def __init__(self, x, y):
        self.x, self.y = x, y
    
    def __str__(self):
        return f"Point({self.x}, {self.y})"  # 用户友好
    
    def __repr__(self):
        return f"Point({self.x!r}, {self.y!r})"  # 調試用
    
    def __format__(self, spec):
        if spec == 'polar':
            import math
            r = math.sqrt(self.x**2 + self.y**2)
            theta = math.atan2(self.y, self.x)
            return f"r={r:.2f}, theta={theta:.2f}"
        return str(self)

p = Point(3, 4)
print(str(p))      # Point(3, 4)
print(repr(p))     # Point(3, 4)
print(f"{p:polar}") # r=5.00, theta=0.93

__repr__應可重現對象,__str__優先用户輸出。

3.3 比較方法:eq、__lt__等

實現可哈希和可排序:

class Point:
    def __init__(self, x, y):
        self.x, self.y = x, y
    
    def __eq__(self, other):
        if isinstance(other, Point):
            return self.x == other.x and self.y == other.y
        return NotImplemented
    
    def __lt__(self, other):
        if isinstance(other, Point):
            return (self.x, self.y) < (other.x, other.y)
        return NotImplemented
    
    def __hash__(self):
        return hash((self.x, self.y))

p1 = Point(1, 2)
p2 = Point(1, 2)
print(p1 == p2)  # True
print(hash(p1) == hash(p2))  # True

從Python 3.7起,dataclasses自動生成這些。

3.4 容器協議:len、__getitem__等

讓類像列表:

class Vector:
    def __init__(self, data):
        self.data = list(data)
    
    def __len__(self):
        return len(self.data)
    
    def __getitem__(self, index):
        return self.data[index]
    
    def __setitem__(self, index, value):
        self.data[index] = value
    
    def __delitem__(self, index):
        del self.data[index]
    
    def __iter__(self):
        return iter(self.data)

v = Vector([1, 2, 3])
print(len(v))      # 3
print(v[0])        # 1
v[1] = 4
for x in v:        # 迭代
    print(x)       # 1 4 3
del v[2]

這啓用for循環、切片等,支持itertools集成。

3.5 上下文管理:enter__與__exit

實現with語句:

class FileManager:
    def __init__(self, filename, mode="r"):
        self.filename = filename
        self.mode = mode
        self.file = None
    
    def __enter__(self):
        self.file = open(self.filename, self.mode)
        return self.file
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        if self.file:
            self.file.close()
        if exc_type:
            print(f"異常: {exc_val}")
        return False  # 不抑制異常

with FileManager("example.txt", "w") as f:
    f.write("Hello, context!")
# 自動關閉

優於try-finally,異常安全。

第四章:繼承與多態

4.1 單繼承:擴展基類

繼承複用代碼:

class Animal:
    def __init__(self, name):
        self.name = name
    
    def speak(self):
        return f"{self.name} 發出聲音"

class Dog(Animal):
    def speak(self):
        return f"{self.name} 汪汪!"  # 多態覆蓋

d = Dog("Buddy")
print(d.speak())  # Buddy 汪汪!

super()在__init__中調用基類:

class Dog(Animal):
    def __init__(self, name, breed):
        super().__init__(name)
        self.breed = breed

4.2 多繼承:菱形問題與MRO

多繼承支持複雜層次:

class Flyer:
    def fly(self):
        return "飛行中"

class Swimmer:
    def swim(self):
        return "游泳中"

class Duck(Flyer, Swimmer):
    def __init__(self):
        pass

duck = Duck()
print(duck.fly())   # 飛行中
print(duck.swim())  # 游泳中

菱形繼承:A -> B,C -> D,使用MRO解決:

class A:
    def method(self):
        print("A")

class B(A):
    pass

class C(A):
    def method(self):
        print("C")
        super().method()

class D(B, C):
    pass

print(D.mro())  # [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

C3確保每個基類出現一次,避免重複調用。

4.3 混合繼承:接口模擬與協議

Python無顯式接口,用ABC(Abstract Base Classes)強制實現:

from abc import ABC, abstractmethod

class Shape(ABC):
    @abstractmethod
    def area(self):
        pass

class Rectangle(Shape):
    def __init__(self, width, height):
        self.width = width
        self.height = height
    
    def area(self):
        return self.width * self.height

rect = Rectangle(3, 4)
print(rect.area())  # 12
# Shape()  # TypeError: Can't instantiate abstract class

協議(如Iterable)通過鴨子類型實現,無需繼承。

4.4 委託與組合:優於繼承

組合優先:將對象作為屬性委託:

class Engine:
    def start(self):
        return "引擎啓動"

class Car:
    def __init__(self):
        self.engine = Engine()
    
    def start(self):
        return self.engine.start() + ",汽車前進"

car = Car()
print(car.start())  # 引擎啓動,汽車前進

減少耦合,避免“脆弱基類問題”。

第五章:屬性與描述符

5.1 屬性:@property裝飾器

動態計算屬性:

class Circle:
    def __init__(self, radius):
        self._radius = radius
    
    @property
    def radius(self):
        return self._radius
    
    @radius.setter
    def radius(self, value):
        if value < 0:
            raise ValueError("半徑不能負")
        self._radius = value
    
    @property
    def area(self):
        import math
        return math.pi * self._radius ** 2

c = Circle(5)
print(c.area)      # ~78.54
c.radius = 10      # setter觸發
print(c.area)      # ~314.16
# c.radius = -1    # ValueError

getter/setter/deleter使屬性像字段,卻有邏輯。

5.2 描述符協議:自定義屬性行為

描述符是類,實現__get__、__set__等:

class Validated:
    def __init__(self, min_val=0):
        self.min_val = min_val
    
    def __set_name__(self, owner, name):  # Python 3.6+
        self.name = name
    
    def __get__(self, obj, objtype=None):
        if obj is None:
            return self
        return obj.__dict__[self.name]
    
    def __set__(self, obj, value):
        if value < self.min_val:
            raise ValueError(f"{self.name} 不能小於 {self.min_val}")
        obj.__dict__[self.name] = value

class Product:
    price = Validated(0.01)
    
    def __init__(self, price):
        self.price = price

p = Product(10.0)
print(p.price)     # 10.0
# p.price = 0      # ValueError

描述符用於框架如SQLAlchemy的ORM。

5.3 slots:內存優化

限制實例屬性,節省內存:

class Point:
    __slots__ = ('x', 'y')
    
    def __init__(self, x, y):
        self.x = x
        self.y = y

p = Point(1, 2)
# p.z = 3         # AttributeError
import sys
print(sys.getsizeof(p))  # ~48 bytes vs 56+ for dict

適合大量實例,如遊戲實體。

5.4 類屬性:ClassVar與Final

從typing導入:

from typing import ClassVar, Final

class Config:
    API_URL: Final[str] = "https://api.example.com"  # 不可變
    debug: ClassVar[bool] = True  # 不存儲在實例
    
    def __init__(self):
        self.user_id = 123

Final防止重賦,ClassVar提示類型檢查器。

第六章:高級主題:元類與動態類

6.1 元類基礎:type是所有類的元類

元類是“類的類”,控制類創建:

class Meta(type):
    def __new__(cls, name, bases, attrs):
        # 修改attrs
        attrs['created_at'] = '動態添加'
        return super().__new__(cls, name, bases, attrs)
    
    def __init__(cls, name, bases, attrs):
        print(f"創建類 {name}")

class MyClass(metaclass=Meta):
    pass

print(MyClass.created_at)  # 動態添加
# 輸出: 創建類 MyClass

type是默認元類:type('ClassName', (Base,), {'attr': value})

6.2 自定義元類:驗證與日誌

class ValidatedMeta(type):
    def __new__(cls, name, bases, attrs):
        # 強制抽象方法
        if name != 'Base':
            if not any('method' in k for k in attrs if not k.startswith('_')):
                raise TypeError(f"{name} 缺少方法")
        return super().__new__(cls, name, bases, attrs)

class Base(metaclass=ValidatedMeta):
    pass

class Good(Base):
    def method(self):
        pass

# class Bad(Base):  # TypeError
#     pass

用於框架,確保接口一致。

6.3 ABCMeta:抽象基類元類

abc.ABCMeta擴展type,支持@abstractmethod。

6.4 動態類創建:type()與exec

運行時代碼:

def create_class(name, fields):
    attrs = {'__init__': lambda self: setattr(self, fields[0], 0)}
    return type(name, (), attrs)

Dynamic = create_class('Dynamic', ['value'])
d = Dynamic()
d.value = 42  # 通過動態添加

小心安全:在沙箱中使用。

第七章:dataclasses與現代簡化

7.1 @dataclass:自動生成樣板

Python 3.7+標準庫:

from dataclasses import dataclass, field
from typing import List

@dataclass
class Employee:
    name: str
    id: int = field(default=0)
    skills: List[str] = field(default_factory=list)
    
    def promote(self):
        self.id += 1

e = Employee("Alice", skills=["Python"])
print(e)  # Employee(name='Alice', id=0, skills=['Python'])  # 自動__repr__
print(e == Employee("Alice"))  # True,自動__eq__

生成__init__、repr、__eq__等。post_init自定義初始化。

7.2 高級dataclasses:frozen與order

@dataclass(frozen=True)  # 不可變
class Point:
    x: float
    y: float

@dataclass(order=True)  # 支持< > 等
class Version:
    major: int
    minor: int

v1 = Version(1, 2)
v2 = Version(1, 3)
print(v1 < v2)  # True

frozen用hash()安全。

7.3 asdict與astuple:序列化

from dataclasses import asdict, astuple

e_dict = asdict(e)  # {'name': 'Alice', 'id': 0, 'skills': ['Python']}
e_tuple = astuple(e)  # ('Alice', 0, ['Python'])

集成JSON或數據庫。

7.4 自定義dataclass行為

繼承dataclass:

@dataclass
class ValidatedEmployee(Employee):
    def __post_init__(self):
        if not self.name:
            raise ValueError("名字不能為空")