Python 面向对象编程深度指南

文章目录

    • [📖 目录导航](#📖 目录导航)
    • [前言:为何精通面向对象对 Pythonista 至关重要](#前言:为何精通面向对象对 Pythonista 至关重要)
    • [Ch10 类与对象:奠定坚实的"壳、魂、根"](#Ch10 类与对象:奠定坚实的"壳、魂、根")
      • [1. `class` 的本质:模板与对象的二重性](#1. class 的本质:模板与对象的二重性)
      • [2. 对象的诞生:`new` 与 `init` 的协奏曲](#2. 对象的诞生:__new____init__ 的协奏曲)
      • [3. `self` 的奥秘:从函数到绑定方法](#3. self 的奥秘:从函数到绑定方法)
      • [4. 属性的三级查找链](#4. 属性的三级查找链)
      • [5. 调试友好双剑客:`str` 与 `repr`](#5. 调试友好双剑客:__str____repr__)
      • [6. "私有"属性:君子协定与名字重整](#6. "私有"属性:君子协定与名字重整)
    • [Ch11 三大特性一步到位](#Ch11 三大特性一步到位)
      • [1. 继承与 `super()`:驾驭 MRO](#1. 继承与 super():驾驭 MRO)
      • [2. 多态与鸭子类型:行为决定一切](#2. 多态与鸭子类型:行为决定一切)
      • [3. 封装与 `@property`:优雅的访问控制](#3. 封装与 @property:优雅的访问控制)
    • [Ch12 魔法工具箱:让你的类更强大](#Ch12 魔法工具箱:让你的类更强大)
      • [1. 运算符重载:让对象表现得像内置类型](#1. 运算符重载:让对象表现得像内置类型)
      • [2. `@dataclass`:一行顶十行的代码生成器](#2. @dataclass:一行顶十行的代码生成器)
      • [3. 枚举与类型提示:提升代码的健壮性与可读性](#3. 枚举与类型提示:提升代码的健壮性与可读性)
      • [4. 极简设计模式](#4. 极简设计模式)
    • [总结:Python OOP 速记口诀(精解版)](#总结:Python OOP 速记口诀(精解版))
      • [🔍 详细解读](#🔍 详细解读)

      • [📊 学习进度追踪](#📊 学习进度追踪)

        ╔══════════════════════════════════════════════════════════════╗
        ║ 🐍 Python OOP 魔法世界 ║
        ║ ║
        ║ ┌─────────┐ ┌─────────┐ ┌─────────┐ ║
        ║ │ 类与 │───▶│ 三大 │───▶│ 魔法 │ ║
        ║ │ 对象 │ │ 特性 │ │ 工具箱 │ ║
        ║ └─────────┘ └─────────┘ └─────────┘ ║
        ║ │ │ │ ║
        ║ ┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐ ║
        ║ │ 壳·魂·根 │ │继承·多态·│ │运算符重载│ ║
        ║ │ │ │ 封装 │ │@dataclass│ ║
        ║ └───────────┘ └───────────┘ └───────────┘ ║
        ╚══════════════════════════════════════════════════════════════╝

📖 目录导航

  • [前言:为何精通面向对象对 Pythonista 至关重要](#前言:为何精通面向对象对 Pythonista 至关重要)
  • [Ch10 类与对象:奠定坚实的"壳、魂、根"](#Ch10 类与对象:奠定坚实的"壳、魂、根")
  • [Ch11 三大特性一步到位](#Ch11 三大特性一步到位)
  • [Ch12 魔法工具箱:让你的类更强大](#Ch12 魔法工具箱:让你的类更强大)
  • [总结:Python OOP 速记口诀](#总结:Python OOP 速记口诀)

前言:为何精通面向对象对 Pythonista 至关重要

面向对象编程(Object-Oriented Programming, OOP)是现代软件开发的基石之一。在 Python 中,OOP 不仅仅是一种编程范式,它是语言设计的核心哲学------"一切皆对象"
Python 世界 整数 int 字符串 str 函数 function 模块 module 类 class 对象实例

本指南将带你深入探索 Python 的面向对象世界,从"类与对象"的基础概念,到"继承、多态、封装"三大支柱,再到利用"魔术方法"和高级工具施展 Python 独有的编程魔法。

💡 学习目标:无论你是希望巩固基础,还是渴望突破进阶,本文都将为你提供一份清晰、全面且可直接应用的实战地图。


Ch10 类与对象:奠定坚实的"壳、魂、根"

复制代码
    类的本质架构图
    ┌─────────────────────────────────────────┐
    │              type (元类)                │
    │  ┌─────────────────────────────────────┐│
    │  │            class 定义               ││
    │  │  ┌─────────────────────────────────┐││
    │  │  │         __dict__ 属性字典       │││
    │  │  │  ┌─────────────────────────────┐│││
    │  │  │  │      方法 & 类变量          ││││
    │  │  │  └─────────────────────────────┘│││
    │  │  └─────────────────────────────────┘││
    │  └─────────────────────────────────────┘│
    └─────────────────────────────────────────┘

1. class 的本质:模板与对象的二重性

在 Python 中,class 关键字定义了一个"模板"或"蓝图",用于创建具有特定属性和方法的对象。但更深层次地,类本身也是一个对象 ,它是 type 这个元类(metaclass)的实例。

python 复制代码
class Cookie:
    # 类体代码在 import 时执行一次
    print("正在烘焙 Cookie 模板...")
    shape = "圆形"  # 这是一个类属性

    def bake(self):
        # 这是一个方法
        print(f"正在烘烤一个{self.shape}的饼干。")

# "Cookie" 不仅是一个类,也是一个可以被引用的对象
print(Cookie)
# <class '__main__.Cookie'>

# 我们可以检查它的类型
print(type(Cookie))
# <class 'type'>

💡 深入理解:类的创建过程

当你定义一个类时,Python 解释器会:

  1. 执行类体中的代码
  2. 将所有产生的局部变量存储在字典中
  3. 这个字典最终成为类的 __dict__ 属性
  4. 类本身成为 type 的实例

这就是为什么我们说"类也是对象"的原因。

2. 对象的诞生:__new____init__ 的协奏曲

Client Python new init Instance Car("Tesla", "Model 3") 调用 new(cls, ...) 创建空实例 返回实例 调用 init(self, ...) 初始化属性 None 返回完整实例 Client Python new init Instance

许多人误以为 __init__ 是 Python 的构造函数,但事实并非如此。对象的创建分为两个阶段:

  1. __new__ (分配内存):负责创建并返回一个类的空实例
  2. __init__ (初始化实例):负责为实例填充属性
python 复制代码
class Car:
    def __new__(cls, *args, **kwargs):
        print(f"1. 调用 __new__: 为 {cls.__name__} 分配内存。")
        instance = super().__new__(cls)
        return instance

    def __init__(self, brand, model):
        print(f"2. 调用 __init__: 初始化 {brand} {model}。")
        self.brand = brand
        self.model = model
        # 注意:__init__ 不应有 return 语句

my_car = Car("Tesla", "Model 3")
# 输出:
# 1. 调用 __new__: 为 Car 分配内存。
# 2. 调用 __init__: 初始化 Tesla Model 3。

3. self 的奥秘:从函数到绑定方法

复制代码
    方法调用转换过程
    ┌─────────────────┐    ┌─────────────────┐
    │   类中定义时    │    │  实例访问时     │
    │                 │    │                 │
    │  def method()   │───▶│  bound method   │
    │  (普通函数)     │    │  (绑定方法)     │
    └─────────────────┘    └─────────────────┘
             │                       │
             ▼                       ▼
    obj.method = method        obj.method()
    (未绑定)                   (self 自动传入)

self 是一个约定俗成的名称,它代表实例对象本身。当你在实例上调用一个方法时,Python 会自动将该实例作为第一个参数传递给方法。

python 复制代码
class Pizza:
    def __init__(self, ingredients):
        self.ingredients = ingredients

    @staticmethod
    def is_vegetarian(ingredients_list):
        """静态方法:不接收 self 或 cls"""
        return "火腿" not in ingredients_list

    @classmethod
    def from_margherita(cls):
        """类方法:接收 cls 作为第一个参数"""
        return cls(["番茄", "马苏里拉奶酪"])

# 静态方法可以直接通过类调用
print(Pizza.is_vegetarian(["番茄", "蘑菇"]))  # True

# 类方法作为工厂函数
margherita_pizza = Pizza.from_margherita()
print(margherita_pizza.ingredients)  # ['番茄', '马苏里拉奶酪']

4. 属性的三级查找链

找到 未找到 找到 未找到 找到 未找到 访问 obj.attr 实例 dict 返回实例属性 类 dict 返回类属性 父类 MRO 返回父类属性 AttributeError

Python 访问属性时遵循一个查找顺序:

  1. 实例属性 :首先在实例的 __dict__ 中查找
  2. 类属性 :如果在实例中找不到,则向上追溯到类的 __dict__ 中查找
  3. 父类属性:如果当前类也找不到,会继续沿着继承链(MRO)向上查找

⚠️ 重要提醒:属性遮蔽现象

如果在实例上对一个与类属性同名的属性进行赋值,会发生"遮蔽"(shadowing),即创建一个新的实例属性,它会覆盖掉对类属性的访问,但不会修改类属性本身。

python 复制代码
class Example:
    shared = "我是类属性"

obj1 = Example()
obj2 = Example()

print(obj1.shared)  # "我是类属性"
obj1.shared = "我是实例属性"
print(obj1.shared)  # "我是实例属性" (遮蔽了类属性)
print(obj2.shared)  # "我是类属性" (类属性未被修改)

5. 调试友好双剑客:__str____repr__

复制代码
    字符串表示方法对比
    ┌─────────────────┬─────────────────┐
    │     __str__     │     __repr__    │
    ├─────────────────┼─────────────────┤
    │   用户友好      │   开发者友好    │
    │   可读性优先    │   明确性优先    │
    │   print() 调用  │   交互式显示    │
    │   str() 调用    │   repr() 调用   │
    └─────────────────┴─────────────────┘
python 复制代码
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __repr__(self):
        # 目标:明确,无歧义,最好能重建对象
        return f"Point(x={self.x!r}, y={self.y!r})"

    def __str__(self):
        # 目标:对用户友好
        return f"坐标点 ({self.x}, {self.y})"

p = Point(1, 2)
print(p)         # 调用 __str__ -> 坐标点 (1, 2)
print(repr(p))   # 调用 __repr__ -> Point(x=1, y=2)
print([p])       # 容器会调用元素的 __repr__ -> [Point(x=1, y=2)]

6. "私有"属性:君子协定与名字重整

复制代码
    Python 访问控制机制
    ┌─────────────────────────────────────────┐
    │  public_attr     ← 完全公开             │
    │  _protected_attr ← 受保护 (约定)        │
    │  __private_attr  ← 名字重整             │
    │                    ↓                    │
    │  _ClassName__private_attr (实际名称)    │
    └─────────────────────────────────────────┘

Python 没有真正的私有属性。访问控制主要依靠约定:

python 复制代码
class MyClass:
    def __init__(self):
        self.public_var = 0        # 公开属性
        self._protected_var = 1    # 受保护属性 (约定)
        self.__private_var = 2     # 私有属性 (名字重整)

    def get_private(self):
        return self.__private_var

obj = MyClass()
print(obj.public_var)     # 0 (正常访问)
print(obj._protected_var) # 1 (可以访问,但不推荐)
# print(obj.__private_var) # AttributeError

# 但可以通过重整后的名字访问
print(obj._MyClass__private_var) # 2

Ch11 三大特性一步到位

复制代码
    OOP 三大特性关系图
    ┌─────────────────────────────────────────────────────────┐
    │                      面向对象                          │
    │  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐    │
    │  │    继承     │  │    多态     │  │    封装     │    │
    │  │ Inheritance │  │ Polymorphism│  │Encapsulation│    │
    │  │             │  │             │  │             │    │
    │  │ 代码复用    │  │ 接口统一    │  │ 数据保护    │    │
    │  │ super()     │  │ 鸭子类型    │  │ @property   │    │
    │  │ MRO         │  │ abc.ABC     │  │ getter/setter│   │
    │  └─────────────┘  └─────────────┘  └─────────────┘    │
    └─────────────────────────────────────────────────────────┘

1. 继承与 super():驾驭 MRO

graph TD A[object] --> B[A] B --> C[B] B --> D[C] C --> E[D] D --> E F[MRO: D → B → C → A → object] style E fill:#ff9999 style F fill:#99ff99

继承允许一个类(子类)获取另一个类(父类)的属性和方法。Python 支持多重继承,使用 C3 线性化算法 来计算方法解析顺序(MRO)。

python 复制代码
class A:
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        print("A")

class B(A):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        print("B")

class C(A):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        print("C")

class D(B, C):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        print("D")

# MRO: D -> B -> C -> A -> object
d = D()
# 输出: A, C, B, D (注意顺序与 MRO 中 __init__ 的调用顺序相反)

# 查看 MRO
print(D.__mro__)
# (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, 
#  <class '__main__.A'>, <class 'object'>)

🔍 深入理解:C3 线性化算法

C3 线性化算法确保:

  1. 单调性:子类永远在父类前面
  2. 局部优先级保持:如果 A 在类定义中出现在 B 前面,那么在 MRO 中 A 也在 B 前面
  3. 无环性:避免循环继承

这个算法解决了多重继承中的"菱形问题",确保方法调用的顺序是明确且可预测的。

2. 多态与鸭子类型:行为决定一切

复制代码
    鸭子类型哲学
    ┌─────────────────────────────────────────┐
    │  "如果它走起路来像鸭子,叫起来也像鸭子,  │
    │   那么它就是一只鸭子。"                 │
    │                                         │
    │  ┌─────────┐  ┌─────────┐  ┌─────────┐ │
    │  │   鸟    │  │  飞机   │  │  超人   │ │
    │  │ .fly()  │  │ .fly()  │  │ .fly()  │ │
    │  └─────────┘  └─────────┘  └─────────┘ │
    │       │            │            │      │
    │       └────────────┼────────────┘      │
    │                    ▼                   │
    │            make_it_fly(obj)             │
    └─────────────────────────────────────────┘

Python 的多态性根植于"鸭子类型"哲学:我们不关心对象的"血统",只关心它是否具备我们需要的"行为"。

python 复制代码
import abc

class CanFly(abc.ABC):
    @abc.abstractmethod
    def fly(self):
        """使对象飞行的方法"""
        pass

class Bird(CanFly):
    def fly(self):
        print("🐦 鸟儿在扇动翅膀飞翔。")

class Airplane(CanFly):
    def fly(self):
        print("✈️ 飞机在引擎轰鸣中起飞。")

# 虚拟子类:即使 Plane 没有继承 CanFly,只要注册了,
# isinstance 和 issubclass 也会认为它们是兼容的。
class Plane:
    def fly(self):
        print("🛩️ 小型飞机起飞了。")

CanFly.register(Plane)

def make_it_fly(flyer: CanFly):
    flyer.fly()

# 多态性展示
flyers = [Bird(), Airplane(), Plane()]
for flyer in flyers:
    make_it_fly(flyer)

print(isinstance(Plane(), CanFly))  # True

3. 封装与 @property:优雅的访问控制

graph LR A[外部访问] --> B[@property] B --> C[getter 方法] B --> D[setter 方法] B --> E[deleter 方法] C --> F[内部属性] D --> F E --> F F --> G[数据验证] F --> H[计算属性] F --> I[缓存机制] style B fill:#ff9999 style F fill:#99ff99

封装是将数据(属性)和操作数据的方法捆绑在一起的机制。@property 装饰器让你在保持简洁的 . 语法的同时,背后可以执行复杂的逻辑。

python 复制代码
import math

class Circle:
    def __init__(self, radius):
        self._radius = radius  # 使用"受保护"的内部变量

    @property
    def radius(self):
        """半径属性的 getter"""
        return self._radius

    @radius.setter
    def radius(self, value):
        """半径属性的 setter,带数据验证"""
        if value < 0:
            raise ValueError("半径不能为负数。")
        self._radius = value

    @property
    def area(self):
        """一个只读的计算属性"""
        return math.pi * (self._radius ** 2)

    @property
    def circumference(self):
        """周长计算属性"""
        return 2 * math.pi * self._radius

# 使用示例
c = Circle(10)
print(f"半径: {c.radius}")           # 10
print(f"面积: {c.area:.2f}")         # 314.16
print(f"周长: {c.circumference:.2f}") # 62.83

c.radius = 12    # 调用 setter
print(f"新面积: {c.area:.2f}")       # 452.39

# c.area = 5 # AttributeError: can't set attribute

🚀 高级技巧:cached_property

对于计算昂贵的属性,可以使用 functools.cached_property

python 复制代码
from functools import cached_property
import time

class ExpensiveCalculation:
    @cached_property
    def expensive_result(self):
        print("正在进行昂贵的计算...")
        time.sleep(1)  # 模拟耗时操作
        return 42

obj = ExpensiveCalculation()
print(obj.expensive_result)  # 第一次调用,会计算
print(obj.expensive_result)  # 第二次调用,直接返回缓存结果

Ch12 魔法工具箱:让你的类更强大

复制代码
    Python 魔术方法全景图
    ┌─────────────────────────────────────────────────────────┐
    │                    🎩 魔术方法                          │
    │  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐    │
    │  │  运算符重载 │  │  容器协议   │  │  上下文管理 │    │
    │  │ __add__     │  │ __len__     │  │ __enter__   │    │
    │  │ __eq__      │  │ __getitem__ │  │ __exit__    │    │
    │  │ __lt__      │  │ __setitem__ │  │             │    │
    │  └─────────────┘  └─────────────┘  └─────────────┘    │
    │  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐    │
    │  │  字符串表示 │  │  函数调用   │  │  属性访问   │    │
    │  │ __str__     │  │ __call__    │  │ __getattr__ │    │
    │  │ __repr__    │  │             │  │ __setattr__ │    │
    │  └─────────────┘  └─────────────┘  └─────────────┘    │
    └─────────────────────────────────────────────────────────┘

1. 运算符重载:让对象表现得像内置类型

通过实现特定的"魔术方法"(dunder methods),你可以让自定义对象支持 Python 的内置运算符。

运算符 方法 反向 就地 描述
+ __add__ __radd__ __iadd__ a + b。如果 a 不支持,尝试 b.__radd__(a)
== __eq__ --- --- a == b。建议同时实现 __hash__
< __lt__ __gt__ --- a < b。配合 @functools.total_ordering
len() __len__ --- --- 必须返回整数
obj[k] __getitem__ --- --- 支持下标和切片
with obj __enter__, __exit__ --- --- 上下文管理器协议
obj() __call__ --- --- 让实例可以像函数一样被调用
python 复制代码
from functools import total_ordering

@total_ordering
class Student:
    def __init__(self, name, score):
        self.name = name
        self.score = score
    
    def __eq__(self, other):
        if not isinstance(other, Student):
            return NotImplemented
        return self.score == other.score
    
    def __lt__(self, other):
        if not isinstance(other, Student):
            return NotImplemented
        return self.score < other.score
    
    def __add__(self, other):
        if isinstance(other, Student):
            return Student(f"{self.name}+{other.name}", 
                         (self.score + other.score) / 2)
        return NotImplemented
    
    def __repr__(self):
        return f"Student('{self.name}', {self.score})"

# 使用示例
alice = Student("Alice", 85)
bob = Student("Bob", 92)
charlie = Student("Charlie", 78)

print(alice < bob)        # True
print(alice == charlie)   # False
print(alice + bob)        # Student('Alice+Bob', 88.5)

students = [alice, bob, charlie]
students.sort()           # 自动使用 __lt__ 进行排序
print(students)           # [Student('Charlie', 78), Student('Alice', 85), Student('Bob', 92)]

2. @dataclass:一行顶十行的代码生成器

复制代码
    @dataclass 功能对比
    ┌─────────────────┬─────────────────┬─────────────────┐
    │   传统类定义    │   @dataclass    │     增强选项    │
    ├─────────────────┼─────────────────┼─────────────────┤
    │ 手写 __init__   │   自动生成      │   init=True     │
    │ 手写 __repr__   │   自动生成      │   repr=True     │
    │ 手写 __eq__     │   自动生成      │   eq=True       │
    │ 手写 __hash__   │   可选生成      │   frozen=True   │
    │ 普通属性存储    │   可优化内存    │   slots=True    │
    └─────────────────┴─────────────────┴─────────────────┘

dataclasses 模块自 Python 3.7 引入,是一个代码生成器,可以为你自动添加样板代码。

python 复制代码
from dataclasses import dataclass, field
from typing import List

@dataclass(frozen=True, slots=True)
class Point3D:
    x: float
    y: float
    z: float = field(default=0.0, repr=False)  # z 默认为0,且不出现在 repr 中
    
    def distance_from_origin(self) -> float:
        return (self.x**2 + self.y**2 + self.z**2)**0.5

@dataclass
class Student:
    name: str
    age: int
    grades: List[float] = field(default_factory=list)
    
    @property
    def average_grade(self) -> float:
        return sum(self.grades) / len(self.grades) if self.grades else 0.0

# 使用示例
p1 = Point3D(1, 2)
p2 = Point3D(1, 2)

print(p1)                    # Point3D(x=1.0, y=2.0)
print(p1 == p2)              # True (自动实现了 __eq__)
print(p1.distance_from_origin())  # 2.23606797749979

student = Student("Alice", 20)
student.grades.extend([85, 92, 78])
print(f"平均分: {student.average_grade:.1f}")  # 平均分: 85.0

⚡ 性能优化:slots=True 的威力

使用 slots=True 可以:

  • 减少内存使用(约 40-50%)
  • 提高属性访问速度
  • 防止动态添加属性
python 复制代码
import sys

@dataclass
class RegularPoint:
    x: float
    y: float

@dataclass(slots=True)
class SlottedPoint:
    x: float
    y: float

regular = RegularPoint(1.0, 2.0)
slotted = SlottedPoint(1.0, 2.0)

print(f"Regular: {sys.getsizeof(regular)} bytes")
print(f"Slotted: {sys.getsizeof(slotted)} bytes")
# Slotted 通常会更小

3. 枚举与类型提示:提升代码的健壮性与可读性

enum.Enum TrafficLight RED YELLOW GREEN typing List Dict Union Optional

python 复制代码
from enum import Enum, auto
from typing import List, Dict, Union, Optional

class TrafficLight(Enum):
    RED = auto()
    YELLOW = auto()
    GREEN = auto()
    
    def can_go(self) -> bool:
        return self == TrafficLight.GREEN
    
    def next_light(self) -> 'TrafficLight':
        transitions = {
            TrafficLight.RED: TrafficLight.GREEN,
            TrafficLight.GREEN: TrafficLight.YELLOW,
            TrafficLight.YELLOW: TrafficLight.RED
        }
        return transitions[self]

class TrafficController:
    def __init__(self):
        self.current_light = TrafficLight.RED
        self.log: List[str] = []
    
    def change_light(self) -> None:
        old_light = self.current_light
        self.current_light = self.current_light.next_light()
        self.log.append(f"{old_light.name} -> {self.current_light.name}")
    
    def get_status(self) -> Dict[str, Union[str, bool]]:
        return {
            "current": self.current_light.name,
            "can_go": self.current_light.can_go(),
            "changes": len(self.log)
        }

# 使用示例
controller = TrafficController()
print(f"初始状态: {controller.current_light.name}")  # RED

controller.change_light()
print(f"变更后: {controller.current_light.name}")    # GREEN
print(f"可以通行: {controller.current_light.can_go()}")  # True

print(controller.get_status())
# {'current': 'GREEN', 'can_go': True, 'changes': 1}

4. 极简设计模式

单例模式 (Singleton)
复制代码
    单例模式实现对比
    ┌─────────────────┬─────────────────┬─────────────────┐
    │   传统实现      │   装饰器实现    │   元类实现      │
    ├─────────────────┼─────────────────┼─────────────────┤
    │ 复杂的逻辑      │   简洁优雅      │   高级但复杂    │
    │ 线程安全问题    │   functools     │   metaclass     │
    │ 代码重复        │   @cache        │   type.__call__ │
    └─────────────────┴─────────────────┴─────────────────┘
python 复制代码
# 线程安全的 Pythonic 实现
from functools import cache
import threading
import time

class _Meta(type):
    @cache
    def __call__(cls, *args, **kwargs):
        return super().__call__(*args, **kwargs)

class DatabaseConnection(metaclass=_Meta):
    def __init__(self):
        print(f"🔗 正在创建新的数据库连接... (线程: {threading.current_thread().name})")
        time.sleep(0.1)  # 模拟连接耗时
        self.connection_id = id(self)

    def query(self, sql: str) -> str:
        return f"执行查询: {sql} (连接ID: {self.connection_id})"

# 测试单例模式
def test_singleton():
    conn = DatabaseConnection()
    print(f"连接ID: {conn.connection_id}")

# 多线程测试
threads = []
for i in range(3):
    thread = threading.Thread(target=test_singleton, name=f"Thread-{i}")
    threads.append(thread)
    thread.start()

for thread in threads:
    thread.join()

# 验证是否为同一实例
a = DatabaseConnection()
b = DatabaseConnection()
print(f"是否为同一实例: {a is b}")  # True
工厂函数 (Factory)
python 复制代码
from abc import ABC, abstractmethod
from typing import Dict, Type

class Shape(ABC):
    @abstractmethod
    def draw(self) -> str:
        pass
    
    @abstractmethod
    def area(self) -> float:
        pass

class Circle(Shape):
    def __init__(self, radius: float):
        self.radius = radius
    
    def draw(self) -> str:
        return f"⭕ 画一个半径为 {self.radius} 的圆形"
    
    def area(self) -> float:
        return 3.14159 * self.radius ** 2

class Rectangle(Shape):
    def __init__(self, width: float, height: float):
        self.width = width
        self.height = height
    
    def draw(self) -> str:
        return f"⬜ 画一个 {self.width}x{self.height} 的矩形"
    
    def area(self) -> float:
        return self.width * self.height

class Triangle(Shape):
    def __init__(self, base: float, height: float):
        self.base = base
        self.height = height
    
    def draw(self) -> str:
        return f"🔺 画一个底边 {self.base},高 {self.height} 的三角形"
    
    def area(self) -> float:
        return 0.5 * self.base * self.height

class ShapeFactory:
    _shapes: Dict[str, Type[Shape]] = {
        "circle": Circle,
        "rectangle": Rectangle,
        "triangle": Triangle
    }
    
    @classmethod
    def create_shape(cls, shape_type: str, **kwargs) -> Shape:
        if shape_type not in cls._shapes:
            raise ValueError(f"不支持的形状类型: {shape_type}")
        
        shape_class = cls._shapes[shape_type]
        return shape_class(**kwargs)
    
    @classmethod
    def register_shape(cls, name: str, shape_class: Type[Shape]) -> None:
        """注册新的形状类型"""
        cls._shapes[name] = shape_class
    
    @classmethod
    def available_shapes(cls) -> List[str]:
        return list(cls._shapes.keys())

# 使用示例
shapes = [
    ShapeFactory.create_shape("circle", radius=5),
    ShapeFactory.create_shape("rectangle", width=4, height=6),
    ShapeFactory.create_shape("triangle", base=3, height=4)
]

for shape in shapes:
    print(shape.draw())
    print(f"面积: {shape.area():.2f}")
    print("-" * 30)

print(f"可用形状: {ShapeFactory.available_shapes()}")

总结:Python OOP 速记口诀(精解版)

复制代码
    🎯 Python OOP 核心要点
    ┌─────────────────────────────────────────────────────────┐
    │  ┌─────────────────────────────────────────────────────┐│
    │  │ 类是模板也是对象,init 只负责填肉                   ││
    │  │ 变量找 dict 先实例后类,double 下划线被改名         ││
    │  │ str 用户 repr 调试,property 把方法变属性           ││
    │  │ super 按 MRO 走,多态看行为不看族                  ││
    │  │ 重载返回 NotImplemented,dataclass 写 slots 省内存 ││
    │  │ enum 做常量集,工厂返回类,Python 把面向对象玩成脚本││
    │  └─────────────────────────────────────────────────────┘│
    └─────────────────────────────────────────────────────────┘

🔍 详细解读

  • 类是模板也是对象,init 只负责填肉

    类是 type 的实例,__new__ 创建骨架,__init__ 负责初始化。

  • 变量找 dict 先实例后类,double 下划线被改名

    属性查找遵循 MRO,__var 会被重整为 _Class__var

  • str 用户 repr 调试,property 把方法变属性

    明确 __str____repr__ 的用途,用 @property 优雅封装。

  • super 按 MRO 走,多态看行为不看族
    super() 遵循 C3 线性化顺序,鸭子类型是 Python 多态的核心。

  • 重载返回 NotImplementeddataclassslots 省内存

    善用魔术方法和 dataclasses 模块提升开发效率。

  • enum 做常量集,工厂返回类,Python 把面向对象玩成脚本

    Python 的 OOP 灵活而强大,鼓励简洁、实用的设计。


📊 学习进度追踪

  • 掌握类与对象的基本概念
  • 理解 __new____init__ 的区别
  • 熟练使用 @staticmethod@classmethod
  • 掌握属性查找链和 MRO
  • 实现 __str____repr__ 方法
  • 理解继承和 super() 的使用
  • 掌握多态和鸭子类型
  • 熟练使用 @property 进行封装
  • 掌握常用魔术方法
  • 使用 @dataclass 简化代码
  • 理解并应用设计模式

🎉 恭喜你完成了 Python 面向对象编程的深度学习!

现在你已经掌握了 Python OOP 的精髓,可以开始构建更加优雅和强大的程序了!

相关推荐
木木子99993 小时前
Python的typing模块:类型提示 (Type Hinting)
开发语言·windows·python
她说人狗殊途4 小时前
Spring IoC容器加载过程 vs Bean生命周期对应关系图
java·开发语言·rpc
RoyLin4 小时前
V8引擎与VM模块
前端·后端·node.js
MediaTea4 小时前
Python 编辑器:PyCharm
开发语言·ide·python·pycharm·编辑器
yinke小琪4 小时前
凌晨2点,我删光了所有“精通多线程”的代码
java·后端·面试
小熊出擊4 小时前
[pytest] 一文掌握 fixture 的作用域(scope)机制
python·功能测试·单元测试·自动化·pytest
Cherry Zack4 小时前
Django 视图与路由基础:从URL映射到视图函数
后端·python·django
Leinwin4 小时前
Codex CLI 配置 Azure OpenAI GPT-5-codex 指南
后端·python·flask
0wioiw04 小时前
Go基础(⑦实例和依赖注入)
开发语言·golang