Python教程39:元类(Metaclass)
“元类就是深度魔法,99%的用户应该根本不必为此操心。” —— Tim Peters
元类是Python的高级特性,用于创建类的"类"。今天我们揭开元类的神秘面纱,理解Python对象系统的底层机制。
1. 什么是元类
一切皆对象
在Python中,类也是对象:
1class MyClass:
2 pass
3
4# 类是对象
5print(type(MyClass)) # <class 'type'>
6print(isinstance(MyClass, type)) # True
7
8# 类可以赋值、作为参数
9AnotherName = MyClass
10def func(cls):
11 return cls()
元类(Metaclass):
- 创建类的"类"
type是Python的默认元类- 类是元类的实例
1# 类是type的实例
2class MyClass:
3 pass
4
5print(type(MyClass)) # <class 'type'>
6
7# 等价于
8MyClass = type('MyClass', (), {})
type的三种用法
1# 用法1:查看对象类型
2print(type(5)) # <class 'int'>
3
4# 用法2:动态创建类
5# type(name, bases, dict)
6MyClass = type('MyClass', (), {'x': 5})
7obj = MyClass()
8print(obj.x) # 5
9
10# 用法3:作为元类(继承type)
11class MyMeta(type):
12 pass
2. 动态创建类
使用type动态创建类:
1# 方式1:正常定义
2class Dog:
3 def bark(self):
4 return "Woof!"
5
6# 方式2:用type创建(等价)
7def bark(self):
8 return "Woof!"
9
10Dog = type('Dog', (), {'bark': bark})
11
12dog = Dog()
13print(dog.bark()) # Woof!
type()参数:
name:类名bases:父类元组dict:类属性字典
1# 带继承和属性
2class Animal:
3 def eat(self):
4 return "Eating"
5
6Dog = type('Dog',
7 (Animal,), # 继承Animal
8 {
9 'species': 'Canis', # 类属性
10 'bark': lambda self: "Woof!" # 方法
11 })
12
13dog = Dog()
14print(dog.eat()) # Eating(继承)
15print(dog.bark()) # Woof!
16print(dog.species) # Canis
3. 自定义元类
创建自定义元类控制类的创建:
1class MyMeta(type):
2 """自定义元类"""
3
4 def __new__(cls, name, bases, attrs):
5 """
6 创建类时调用
7 - cls: 元类本身
8 - name: 类名
9 - bases: 父类
10 - attrs: 属性字典
11 """
12 print(f"创建类:{name}")
13
14 # 修改类属性
15 attrs['version'] = '1.0'
16
17 # 调用父类创建类
18 return super().__new__(cls, name, bases, attrs)
19
20# 使用元类
21class MyClass(metaclass=MyMeta):
22 pass
23# 输出:创建类:MyClass
24
25print(MyClass.version) # 1.0(自动添加)
元类的应用场景
1class UpperAttrMeta(type):
2 """
3 元类:将所有属性名转为大写
4 """
5 def __new__(cls, name, bases, attrs):
6 # 转换属性名为大写
7 uppercase_attrs = {
8 (key.upper() if not key.startswith('__') else key): value
9 for key, value in attrs.items()
10 }
11 return super().__new__(cls, name, bases, uppercase_attrs)
12
13class MyClass(metaclass=UpperAttrMeta):
14 x = 10
15 y = 20
16
17 def hello(self):
18 return "Hello"
19
20obj = MyClass()
21print(obj.X) # 10(x变成了X)
22print(obj.Y) # 20
23print(obj.HELLO()) # Hello(方法名也变了)
4. 实战示例
示例:单例模式元类
1class SingletonMeta(type):
2 """单例元类"""
3
4 _instances = {}
5
6 def __call__(cls, *args, **kwargs):
7 """
8 调用类创建实例时触发
9 - 检查是否已有实例
10 - 有则返回,无则创建
11 """
12 if cls not in cls._instances:
13 instance = super().__call__(*args, **kwargs)
14 cls._instances[cls] = instance
15 return cls._instances[cls]
16
17class Database(metaclass=SingletonMeta):
18 def __init__(self, connection_string):
19 self.connection_string = connection_string
20
21# 测试
22db1 = Database("localhost")
23db2 = Database("otherhost") # 参数被忽略
24
25print(db1 is db2) # True(同一实例)
26print(db1.connection_string) # localhost
示例:ORM字段验证
1class Field:
2 """字段描述符"""
3 def __init__(self, field_type):
4 self.field_type = field_type
5
6 def __set_name__(self, owner, name):
7 self.name = name
8
9 def __get__(self, instance, owner):
10 if instance is None:
11 return self
12 return instance.__dict__.get(self.name)
13
14 def __set__(self, instance, value):
15 if not isinstance(value, self.field_type):
16 raise TypeError(f"{self.name}必须是{self.field_type.__name__}")
17 instance.__dict__[self.name] = value
18
19class ModelMeta(type):
20 """ORM模型元类"""
21 def __new__(cls, name, bases, attrs):
22 # 收集所有Field
23 fields = {}
24 for key, value in attrs.items():
25 if isinstance(value, Field):
26 fields[key] = value
27
28 attrs['_fields'] = fields
29 return super().__new__(cls, name, bases, attrs)
30
31class Model(metaclass=ModelMeta):
32 """ORM基类"""
33 pass
34
35class User(Model):
36 name = Field(str)
37 age = Field(int)
38
39 def __init__(self, name, age):
40 self.name = name
41 self.age = age
42
43# 使用
44user = User("Alice", 25)
45print(user.name, user.age)
46# user.age = "abc" # TypeError
5. new vs init 在元类中
1class MyMeta(type):
2 def __new__(cls, name, bases, attrs):
3 """
4 创建类对象
5 - 在__init__之前调用
6 - 必须返回类对象
7 """
8 print(f"__new__: 创建类{name}")
9 return super().__new__(cls, name, bases, attrs)
10
11 def __init__(cls, name, bases, attrs):
12 """
13 初始化类对象
14 - 在__new__之后调用
15 - 不返回值
16 """
17 print(f"__init__: 初始化类{name}")
18 super().__init__(name, bases, attrs)
19
20class MyClass(metaclass=MyMeta):
21 pass
22# 输出:
23# __new__: 创建类MyClass
24# __init__: 初始化类MyClass
6. 何时使用元类
使用元类的场景:
- 自动注册类
- API框架(Django ORM)
- 代码注入
- 接口检查
- 日志和调试
不使用元类的场景(99%的情况):
- 装饰器能解决
- 类装饰器能解决
- Mixin能解决
- 继承能解决
1# 通常装饰器就够了
2def add_version(cls):
3 cls.version = '1.0'
4 return cls
5
6@add_version
7class MyClass:
8 pass
7. 小结
元类是Python的高级特性:
- 元类:创建类的类,type是默认元类
- 动态创建类:type(name, bases, dict)
- 自定义元类:继承type
- 应用:单例、ORM、框架
- 警告:99%情况不需要元类
除非开发框架,否则优先考虑装饰器、Mixin等更简单的方案。
练习题:
- 用type动态创建一个带方法的类
- 实现一个元类,自动为类添加__str__方法
- 创建一个注册元类,自动注册所有子类
本文代码示例:
关注公众号:极客老墨
更多 AI 应用开发、工程实践和效率工具分享,欢迎扫码关注。
