type()可动态创建类,需严格传入类名字符串、父类元组、属性字典;必须显式设置__module__以避免序列化和调试问题;适用于运行时生成类的场景,而非替代class语句。

type() 能直接创建类,但不是“动态生成”就一定该用它——多数场景下写 class 语句更清晰,只有真需要运行时拼类名、继承链或方法时,才轮到 type() 出场。
type() 创建类的三个参数怎么填
调用 type(name, bases, dict) 时,三个参数必须严格对应:类名字符串、父类元组、属性字典。漏掉括号、传错类型(比如把 bases 写成列表而非元组)、或在 dict 里漏掉 __module__ 都会导致意外行为(如类出现在 __main__ 下而非当前模块)。
-
name:任意合法标识符字符串,如"DynamicUser",不能含空格或特殊字符 -
bases:必须是元组,哪怕只继承object,也得写成(object,)(注意末尾逗号) -
dict:键是属性/方法名,值是对象;方法需是已定义的函数对象,不能传 lambda(因 lambda 没有__name__,影响调试)
示例:
def say_hello(self):
return f"Hello, {self.name}"
<p>DynamicPerson = type("DynamicPerson", (object,), {
"<strong>module</strong>": <strong>name</strong>,
"<strong>init</strong>": lambda self, name: setattr(self, "name", name),
"greet": say_hello
})
</p>
为什么 __module__ 必须显式传入
如果不设 __module__,Python 会默认赋值为 "__builtin__"(Py2)或 "builtins"(Py3),导致该类无法被 pickle 序列化,也会让 IDE 无法跳转、调试器显示位置错误。
- 模块名应和当前文件一致,通常用
__name__即可 - 若在函数内创建类,且希望它归属调用方模块,需手动传入调用方的
__name__,不能依赖闭包 - 不设
__qualname__一般不影响使用,但嵌套类场景下建议一并设置
用 type() 模拟 @dataclass 的简易实现
真正需要 type() 的典型场景,是框架层自动补全属性与 __init__,比如简化数据类定义。此时关键是把字段名转为实例属性,并生成带类型注解的 __init__ 方法。
- 字段信息得从
dict中提取(比如约定用_fields键存字段列表) -
__init__必须是普通函数,不能用exec()动态编译字符串(安全与调试成本高) - 若字段带默认值,要按 Python 规则把无默认值参数放前面,否则会触发
TypeError - 生成的方法体里别直接引用外层变量,要用默认参数绑定,避免闭包延迟求值问题
简略示意:
def make_dataclass(class_name, fields):
# fields: [("name", str), ("age", int)]
def __init__(self, **kwargs):
for field_name, _ in fields:
setattr(self, field_name, kwargs.get(field_name))
<pre class="brush:php;toolbar:false;">return type(class_name, (), {
"__module__": __name__,
"__init__": __init__,
"__annotations__": {n: t for n, t in fields}
})Person = make_dataclass("Person", [("name", str), ("age", int)])
type() 和 metaclass= 的关系别搞混
type() 是元类的实例化方式,而 metaclass= 是声明式语法糖。两者不互斥,但目的不同:type() 用于“此刻造一个类”,metaclass 用于“以后所有子类都走这个构造逻辑”。硬用 type() 去模拟 metaclass 行为(比如每次创建都重算逻辑)反而绕远路。
- 如果只是临时生成一个类,用
type()直接、轻量 - 如果想控制一批类的创建过程(比如统一加日志、校验字段),应定义真正的元类,继承
type并重写__new__ - 用
type()创建的类,其__class__仍是type,除非你额外指定metaclass参数(Python 3.7+ 支持第 4 个参数)
容易被忽略的一点:type() 创建的类,不会自动触发你自定义元类里的 __init__ 方法——因为那根本不是它的元类。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











