Python 元类
目录
学习目标
- 理解元类的概念和作用
- 掌握
type()动态创建类 - 学会自定义元类
- 了解元类的应用场景
一、类也是对象
在 Python 中,一切皆对象,类本身也是对象。类是 type 的实例。
class MyClass:
pass
# 类是对象
print(type(MyClass)) # <class 'type'>
print(type(int)) # <class 'type'>
print(type(str)) # <class 'type'>
# 对象是类的实例
obj = MyClass()
print(type(obj)) # <class '__main__.MyClass'>
# 所有类都继承自 object
print(issubclass(MyClass, object)) # True
print(issubclass(int, object)) # True二、type() 动态创建类
type() 不仅可以查看类型,还可以用来动态创建类。
2.1 基本语法
# type(name, bases, namespace)
# name: 类名
# bases: 父类元组
# namespace: 属性和方法字典
# 等价于 class MyClass: pass
MyClass = type("MyClass", (), {})
obj = MyClass()
print(type(obj)) # <class '__main__.MyClass'>
# 等价于:
# class Dog:
# species = "Canis familiaris"
# def bark(self):
# return "汪汪!"
Dog = type("Dog", (), {
"species": "Canis familiaris",
"bark": lambda self: "汪汪!"
})
dog = Dog()
print(dog.species) # Canis familiaris
print(dog.bark()) # 汪汪!2.2 带继承和方法
def say_hello(self):
return f"Hello, I'm {self.name}"
# 创建 Animal 基类
Animal = type("Animal", (), {
"__init__": lambda self, name: setattr(self, "name", name),
"speak": lambda self: "动物发出声音",
})
# 创建 Dog 子类
Dog = type("Dog", (Animal,), {
"speak": lambda self: f"{self.name} 说: 汪汪!",
})
dog = Dog("Buddy")
print(dog.speak()) # Buddy 说: 汪汪!三、自定义元类
元类是创建类的"类"。自定义元类需要继承 type。
3.1 基本元类
class Meta(type):
"""自定义元类"""
def __new__(mcs, name, bases, namespace):
"""创建类时调用"""
print(f"创建类: {name}")
print(f" 父类: {bases}")
print(f" 命名空间: {list(namespace.keys())}")
# 可以修改命名空间
namespace["created_by"] = "Meta"
# 调用父类的 __new__ 创建类
return super().__new__(mcs, name, bases, namespace)
def __init__(cls, name, bases, namespace):
"""初始化类时调用"""
print(f"初始化类: {name}")
super().__init__(name, bases, namespace)
def __call__(cls, *args, **kwargs):
"""创建实例时调用"""
print(f"创建 {cls.__name__} 的实例")
return super().__call__(*args, **kwargs)
class MyClass(metaclass=Meta):
class_attr = 100
def __init__(self, value):
self.value = value
# 输出:
# 创建类: MyClass
# 父类: ()
# 命名空间: ['__module__', '__qualname__', 'class_attr', '__init__', 'created_by']
# 初始化类: MyClass
obj = MyClass(42)
# 输出:创建 MyClass 的实例
print(obj.value) # 42
print(MyClass.created_by) # Meta3.2 自动注册子类
class PluginMeta(type):
"""自动注册插件的元类"""
registry = {}
def __new__(mcs, name, bases, namespace):
cls = super().__new__(mcs, name, bases, namespace)
if name != "BasePlugin": # 不注册基类
mcs.registry[name] = cls
print(f"注册插件: {name}")
return cls
class BasePlugin(metaclass=PluginMeta):
"""插件基类"""
def execute(self):
raise NotImplementedError
class EmailPlugin(BasePlugin):
def execute(self):
return "发送邮件"
class SMSPlugin(BasePlugin):
def execute(self):
return "发送短信"
class PushPlugin(BasePlugin):
def execute(self):
return "推送通知"
# 查看注册的所有插件
print("\n已注册插件:")
for name, cls in PluginMeta.registry.items():
print(f" {name}: {cls}")
# 动态创建插件实例
plugin_name = "EmailPlugin"
if plugin_name in PluginMeta.registry:
plugin = PluginMeta.registry[plugin_name]()
print(f"\n执行 {plugin_name}: {plugin.execute()}")四、元类的应用场景
4.1 属性名强制小写
class LowerCaseMeta(type):
"""将类中所有属性名转为小写"""
def __new__(mcs, name, bases, namespace):
# 创建新的命名空间,属性名转为小写
lower_namespace = {}
for key, value in namespace.items():
if not key.startswith("__"):
lower_namespace[key.lower()] = value
else:
lower_namespace[key] = value
return super().__new__(mcs, name, bases, lower_namespace)
class MyClass(metaclass=LowerCaseMeta):
Name = "Alice"
AGE = 25
CITY = "Beijing"
def SayHello(self):
return f"Hello, {self.name}"
obj = MyClass()
print(obj.name) # Alice
print(obj.age) # 25
print(obj.city) # Beijing
print(obj.sayhello()) # Hello, Alice4.2 单例模式
class SingletonMeta(type):
"""单例元类"""
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super().__call__(*args, **kwargs)
return cls._instances[cls]
class Database(metaclass=SingletonMeta):
def __init__(self, connection_string):
self.connection_string = connection_string
print(f"创建数据库连接: {connection_string}")
db1 = Database("mysql://localhost/mydb")
db2 = Database("mysql://localhost/other")
print(db1 is db2) # True(同一个实例)
print(db1.connection_string) # mysql://localhost/mydb
print(db2.connection_string) # mysql://localhost/mydb4.3 ORM 字段自动收集
class Field:
def __init__(self, field_type="TEXT", default=None):
self.field_type = field_type
self.default = default
def __repr__(self):
return f"Field({self.field_type})"
class ModelMeta(type):
"""ORM 元类:自动收集字段"""
def __new__(mcs, name, bases, namespace):
# 收集 Field 类型的属性
fields = {}
for key, value in namespace.items():
if isinstance(value, Field):
fields[key] = value
# 添加 fields 属性
namespace["_fields"] = fields
cls = super().__new__(mcs, name, bases, namespace)
# 如果有表名设置
if "__tablename__" not in namespace:
cls.__tablename__ = name.lower()
return cls
def __repr__(cls):
fields = ", ".join(f"{k}={v}" for k, v in cls._fields.items())
return f"<Model {cls.__name__}({fields})>"
class Model(metaclass=ModelMeta):
pass
class User(Model):
__tablename__ = "users"
id = Field("INTEGER", default=0)
name = Field("TEXT", default="")
email = Field("TEXT", default="")
class Post(Model):
id = Field("INTEGER")
title = Field("TEXT")
content = Field("TEXT")
print(User)
# <Model User(id=Field(INTEGER), name=Field(TEXT), email=Field(TEXT))>
print(Post)
# <Model Post(id=Field(INTEGER), title=Field(TEXT), content=Field(TEXT))>
print(User.__tablename__) # users
print(Post.__tablename__) # post(自动小写)五、元类 vs 类装饰器
元类和类装饰器都可以修改类的行为,但适用场景不同。
# 类装饰器(更简单)
def singleton(cls):
"""单例装饰器"""
instance = {}
def wrapper(*args, **kwargs):
if cls not in instance:
instance[cls] = cls(*args, **kwargs)
return instance[cls]
return wrapper
@singleton
class Logger:
def __init__(self):
print("创建 Logger")
# 元类(更强大,可以控制类创建过程)
class SingletonMeta(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super().__call__(*args, **kwargs)
return cls._instances[cls]
class Config(metaclass=SingletonMeta):
def __init__(self):
print("创建 Config")
# 选择建议:
# - 简单修改类:使用类装饰器
# - 深度定制类创建过程:使用元类
# - 框架开发:使用元类六、综合示例
"""
接口检查元类:确保子类实现了所有抽象方法
"""
from abc import abstractmethod
class InterfaceMeta(type):
"""检查接口实现的元类"""
def __new__(mcs, name, bases, namespace):
cls = super().__new__(mcs, name, bases, namespace)
# 跳过抽象基类本身
if getattr(cls, "__abstract__", False):
return cls
# 检查所有抽象方法是否已实现
for base in bases:
for attr_name in dir(base):
attr = getattr(base, attr_name)
if getattr(attr, "__isabstractmethod__", False):
if attr_name not in namespace:
raise TypeError(
f"类 {name} 必须实现抽象方法 '{attr_name}'"
)
return cls
class BaseHandler(metaclass=InterfaceMeta):
"""处理器基类"""
__abstract__ = True
@abstractmethod
def handle(self, request):
"""处理请求"""
pass
@abstractmethod
def validate(self, request):
"""验证请求"""
pass
# 正确实现
class HTTPHandler(BaseHandler):
def handle(self, request):
return f"处理 HTTP 请求: {request}"
def validate(self, request):
return True
# 错误实现(会报错)
# class BrokenHandler(BaseHandler):
# def handle(self, request):
# pass
# # 缺少 validate 方法!
handler = HTTPHandler()
print(handler.handle("GET /api/users"))小结
- 类是
type的实例,type是所有类的默认元类 type(name, bases, namespace)可以动态创建类- 自定义元类继承
type,重写__new__和__init__ - 元类应用场景:ORM、单例、接口检查、自动注册、属性转换等
- 类装饰器是元类的轻量级替代方案
- 大多数情况不需要元类,过度使用会增加代码复杂度
练习
- 使用
type()动态创建一个Calculator类,包含add和subtract方法。 - 编写一个元类,自动为类中所有方法添加计时功能。
- 实现一个元类,要求所有属性名必须以小写字母开头,否则抛出异常。
- 对比类装饰器和元类实现单例模式,分析各自的优缺点。
- 使用元类实现一个简单的 ORM,支持定义表名和字段类型。