面向对象

类的定义

class Person:
    species = "Homo sapiens"   # 类变量(所有实例共享)
 
    def __init__(self, name: str, age: int):
        self.name = name       # 实例变量
        self.age = age
 
    def greet(self) -> str:
        return f"Hi, I'm {self.name}"
 
    def __repr__(self) -> str:
        return f"Person(name={self.name!r}, age={self.age})"
 
    def __str__(self) -> str:
        return self.name
 
p = Person("Alice", 30)
p.greet()   # "Hi, I'm Alice"
repr(p)     # "Person(name='Alice', age=30)"

继承

class Animal:
    def __init__(self, name: str):
        self.name = name
 
    def speak(self) -> str:
        raise NotImplementedError
 
class Dog(Animal):
    def speak(self) -> str:
        return f"{self.name} says Woof!"
 
# super() 调用父类
class GuideDog(Dog):
    def __init__(self, name: str, owner: str):
        super().__init__(name)
        self.owner = owner
 
    def speak(self) -> str:
        return super().speak() + " (guide dog)"

多重继承与 MRO

class A:
    def hello(self): return "A"
 
class B(A):
    def hello(self): return "B"
 
class C(A):
    def hello(self): return "C"
 
class D(B, C):
    pass
 
D().hello()   # "B"(MRO:D → B → C → A)
D.__mro__     # 查看方法解析顺序

访问控制(约定)

class BankAccount:
    def __init__(self, balance: float):
        self.owner = "Alice"      # 公开
        self._balance = balance   # 约定受保护
        self.__pin = "1234"       # 名称改写(name mangling)
        # 实际存储为 _BankAccount__pin

property

class Circle:
    def __init__(self, radius: float):
        self._radius = radius
 
    @property
    def radius(self) -> float:
        return self._radius
 
    @radius.setter
    def radius(self, value: float):
        if value < 0:
            raise ValueError("Radius cannot be negative")
        self._radius = value
 
    @property
    def area(self) -> float:
        import math
        return math.pi * self._radius ** 2
 
c = Circle(5)
c.radius = 10   # 调用 setter
c.area          # 314.159...

classmethod 与 staticmethod

class Date:
    def __init__(self, year, month, day):
        self.year, self.month, self.day = year, month, day
 
    @classmethod
    def from_string(cls, s: str) -> "Date":
        y, m, d = map(int, s.split("-"))
        return cls(y, m, d)
 
    @staticmethod
    def is_valid(year, month, day) -> bool:
        return 1 <= month <= 12 and 1 <= day <= 31
 
Date.from_string("2024-01-15")
Date.is_valid(2024, 13, 1)   # False

常用魔术方法

class Vector:
    def __init__(self, x, y):
        self.x, self.y = x, y
 
    def __repr__(self):        return f"Vector({self.x}, {self.y})"
    def __add__(self, other):  return Vector(self.x+other.x, self.y+other.y)
    def __mul__(self, n):      return Vector(self.x*n, self.y*n)
    def __rmul__(self, n):     return self.__mul__(n)
    def __eq__(self, other):   return self.x == other.x and self.y == other.y
    def __abs__(self):         return (self.x**2 + self.y**2) ** 0.5
    def __iter__(self):        return iter((self.x, self.y))
    def __len__(self):         return 2
魔术方法触发场景
__init__实例化
__repr__repr() / 调试
__str__str() / print()
__len__len()
__getitem__obj[key]
__contains__x in obj
__call__obj()
__enter__/__exit__with 语句
__hash__hash() / 字典键

dataclass(Python 3.7+)

from dataclasses import dataclass, field
 
@dataclass
class Point:
    x: float
    y: float
    z: float = 0.0
    tags: list = field(default_factory=list)
 
    def distance(self) -> float:
        return (self.x**2 + self.y**2 + self.z**2) ** 0.5
 
# 自动生成 __init__、__repr__、__eq__
 
@dataclass(frozen=True)   # 不可变,自动生成 __hash__
class ImmutablePoint:
    x: float
    y: float

抽象类

from abc import ABC, abstractmethod
 
class Shape(ABC):
    @abstractmethod
    def area(self) -> float: ...
 
    @abstractmethod
    def perimeter(self) -> float: ...
 
class Rectangle(Shape):
    def __init__(self, w: float, h: float):
        self.w, self.h = w, h
 
    def area(self)      -> float: return self.w * self.h
    def perimeter(self) -> float: return 2 * (self.w + self.h)

相关链接