文章目录

前言

第一章:元类 —— 类的“制造工厂”

1.1 万物皆对象,类也是对象

1.2 type() 动态创建类

1.3 自定义元类 —— 给“类创建过程”加钩子

1.4 元类与装饰器的区别

第二章:异常类 —— 定制你自己的“报错”

2.1 为什么需要自定义异常?

2.2 基础写法:继承 Exception

2.3 带额外信息的异常类

2.4 异常类体系

2.5 什么时候用自定义异常?

🧁 结尾

前言

今天聊两个“高阶”但很酷的概念——元类 和 异常类

元类 是“制造类的类”——它决定了类怎么被创建。你写的每个类,背后都是元类在干活。

异常类 是“定制报错”——Python 自带的异常够用,但你也可以自己造新的异常类型,携带更精确的错误信息。

一个管“生”,一个管“死”(报错也算一种“死”)

next let me show🏭

第一章:元类 —— 类的“制造工厂”

1.1 万物皆对象,类也是对象

在 Python 里,一切皆对象:数字是对象,字符串是对象,类也是对象

既然类是对象,那它肯定是由某个“类”创建出来的。这个创建类的类,就叫 元类(Metaclass)

python

class MyClass:
    pass

# 查看 MyClass 的类型
print(type(MyClass))   # <class 'type'>

📌 默认情况下,所有类的元类都是 typetype 就是 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 内置了很多异常:ValueErrorTypeErrorKeyError……但有时候你想更精确地描述错误,或者携带额外信息(比如出错时的具体数值)。

这时候你就需要自定义异常类。

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 加自己的属性和方法,让报错信息更精准、更友好。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐