文章目录
[第一章:元类 ------ 类的"制造工厂"](#第一章:元类 —— 类的“制造工厂”)
[1.1 万物皆对象,类也是对象](#1.1 万物皆对象,类也是对象)
[1.2 type() 动态创建类](#1.2 type() 动态创建类)
[1.3 自定义元类 ------ 给"类创建过程"加钩子](#1.3 自定义元类 —— 给“类创建过程”加钩子)
[1.4 元类与装饰器的区别](#1.4 元类与装饰器的区别)
[第二章:异常类 ------ 定制你自己的"报错"](#第二章:异常类 —— 定制你自己的“报错”)
[2.1 为什么需要自定义异常?](#2.1 为什么需要自定义异常?)
[2.2 基础写法:继承 Exception](#2.2 基础写法:继承 Exception)
[2.3 带额外信息的异常类](#2.3 带额外信息的异常类)
[2.4 异常类体系](#2.4 异常类体系)
[2.5 什么时候用自定义异常?](#2.5 什么时候用自定义异常?)
[🧁 结尾](#🧁 结尾)
前言
今天聊两个"高阶"但很酷的概念------元类 和 异常类。
元类 是"制造类的类"------它决定了类怎么被创建。你写的每个类,背后都是元类在干活。
异常类 是"定制报错"------Python 自带的异常够用,但你也可以自己造新的异常类型,携带更精确的错误信息。
一个管"生",一个管"死"(报错也算一种"死")
next let me show🏭
第一章:元类 ------ 类的"制造工厂"
1.1 万物皆对象,类也是对象
在 Python 里,一切皆对象:数字是对象,字符串是对象,类也是对象。
既然类是对象,那它肯定是由某个"类"创建出来的。这个创建类的类,就叫 元类(Metaclass)。
python
class MyClass:
pass
# 查看 MyClass 的类型
print(type(MyClass)) # <class 'type'>
📌 默认情况下,所有类的元类都是
type。type就是 Python 内置的元类,负责创建所有的类。
1.2 type() 动态创建类
除了 class 关键字,你可以直接用 type() 函数动态创建类:
python
# 用 type 创建类:type(类名, 父类元组, 属性字典)
MyDynamicClass = type("MyDynamicClass", (), {"x": 10, "hello": lambda self: "world"})
obj = MyDynamicClass()
print(obj.x) # 10
print(obj.hello()) # world
这和用 class 定义的效果一样,只不过是在运行时动态生成的。
1.3 自定义元类 ------ 给"类创建过程"加钩子
你可以继承 type,重写 __new__ 或 __init__,在类被创建时插入自定义逻辑。
最常见场景:自动给类添加属性或方法,或者做参数校验。
python
class MyMeta(type):
def __new__(cls, name, bases, attrs):
# 自动给类加一个属性
attrs["version"] = "1.0"
# 或者检查类名不能以数字开头等
return super().__new__(cls, name, bases, attrs)
# 使用 metaclass 参数指定元类
class MyClass(metaclass=MyMeta):
pass
print(MyClass.version) # 1.0(自动加上的)
📌 元类很强大,但也很少需要自己写。99% 的情况你不需要自定义元类。但理解它,有助于你理解 ORM(比如 Django 的 Model)、单例模式等底层机制。
1.4 元类与装饰器的区别
| 维度 | 装饰器 | 元类 |
|---|---|---|
| 作用对象 | 函数或类(实例) | 类本身(创建过程) |
| 时机 | 运行时(调用时) | 类定义时(编译时) |
| 修改能力 | 修改类的行为 | 修改类的结构(添加/删除属性、方法) |
| 复杂度 | 低 | 高 |
|----------|----------------------|
| 外部服务调用失败 | ThirdPartyAPIError |
| 数据验证失败 | ValidationError |
第二章:异常类 ------ 定制你自己的"报错"
2.1 为什么需要自定义异常?
Python 内置了很多异常:ValueError、TypeError、KeyError......但有时候你想更精确地描述错误 ,或者携带额外信息(比如出错时的具体数值)。
这时候你就需要自定义异常类。
2.2 基础写法:继承 Exception
自定义异常类必须继承自 Exception 或其子类。最简单的只需要一个 pass:
python
class MyCustomError(Exception):
pass
try:
raise MyCustomError("出错了!")
except MyCustomError as e:
print(e) # 出错了!
2.3 带额外信息的异常类
你可以重写 __init__,给异常加上更多属性:
python
class AgeTooOldError(Exception):
def __init__(self, age, limit=100):
self.age = age
self.limit = limit
super().__init__(f"年龄 {age} 超过最大限制 {limit}")
# 使用
def set_age(age):
if age > 100:
raise AgeTooOldError(age)
print(f"年龄设置为 {age}")
try:
set_age(150)
except AgeTooOldError as e:
print(f"错误:{e}")
print(f"你输入的年龄是 {e.age},最大允许 {e.limit}")
输出:
text
错误:年龄 150 超过最大限制 100
你输入的年龄是 150,最大允许 100
💡 这样调用者就能通过
e.age拿到具体数值,方便做日志或提示。
2.4 异常类体系
你可以构建自己的异常体系,比如:
python
class MyAppError(Exception):
"""应用根异常"""
pass
class DatabaseError(MyAppError):
"""数据库相关错误"""
pass
class NetworkError(MyAppError):
"""网络相关错误"""
pass
这样在 except MyAppError 时能捕获所有自定义异常,而更细分的异常可以单独处理。
2.5 什么时候用自定义异常?
| 场景 | 示例 |
|---|---|
| 业务逻辑校验失败 | BalanceNotEnoughError |
| 配置错误 | ConfigNotFoundError |
| 外部服务调用失败 | ThirdPartyAPIError |
| 数据验证失败 | ValidationError |
🎯 一张图总结
text
元类(制造类)
默认:type
自定义:继承 type,重写 __new__/__init__
用途:ORM、单例、自动注册
记住:99% 情况用不到
异常类(定制报错)
继承 Exception
添加 __init__ 携带额外信息
构建异常体系(根异常 + 子异常)
用途:精确错误类型 + 携带数据
🧁 结尾
元类 是"造类的机器",默认是 type。自定义元类能让你在类诞生时"插一脚",但大部分情况你不需要自己写。
异常类 是"报错定制师",继承 Exception 加自己的属性和方法,让报错信息更精准、更友好。