能否在SQLAlchemy ORM中使用带槽的dataclasses?
问题:带slots的dataclass与SQLAlchemy映射时出现AttributeError
我正在使用dataclasses和SQLAlchemy ORM向MySQL数据库传输数据,希望将数据条目存储在带槽(slots)的dataclass中,但初始化映射类时遇到错误。想了解是否能在数据模型dataclass上使用槽,以及报错的原因。
报错信息
Traceback (most recent call last): File "/home/python/.../example.py", line 44, in <module> print(Example(**example_data)) ^^^^^^^^^^^^^^^^^^^^^^^ File "<string>", line 2, in __init__ File "/home/python/.local/lib/python3.11/site-packages/sqlalchemy/orm/instrumentation.py", line 551, in _new_state_if_none self._state_setter(instance, state) File "<string>", line 1, in set AttributeError: 'Example' object has no attribute '_sa_instance_state'
复现代码
#!/usr/bin/env python3.11 # coding: utf-8 """ Python v. 3.11.5 SQLAlchemy v. 2.0.23 Example script demonstrating 'sa_instance_state' error: AttributeError: 'Example' object has no attribute '_sa_instance_state' """ from dataclasses import dataclass from sqlalchemy import Column from sqlalchemy import MetaData from sqlalchemy import PrimaryKeyConstraint from sqlalchemy import String from sqlalchemy import Table from sqlalchemy.orm import registry metadata_obj = MetaData() @dataclass(slots=True, weakref_slot=True) class Example: f1: str example = Table( "example", metadata_obj, Column("f1", String), PrimaryKeyConstraint("f1", name="example_pk"), ) example_data = {"f1": "1"} print(Example(**example_data)) # 'Example(f1='1')', as expected mapper_registry = registry() mapper_registry.map_imperatively(Example, example) print(Example(**example_data)) # errors
原因分析
SQLAlchemy ORM需要给映射类的实例添加_sa_instance_state属性,用来追踪对象的持久化状态(比如是否已被数据库加载、是否有修改等)。但当dataclass启用slots=True时,类的属性被严格限制在定义的槽列表中,默认不会包含_sa_instance_state这个SQLAlchemy内部需要的属性,因此初始化映射后的实例时,SQLAlchemy尝试设置该属性就会触发AttributeError。
解决方法
方法一:显式添加SQLAlchemy所需的槽
在dataclass的槽中手动添加_sa_instance_state,同时用field标记它不需要在__init__中初始化,也不参与repr输出:
from dataclasses import dataclass, field from typing import Any @dataclass(slots=True, weakref_slot=True) class Example: f1: str _sa_instance_state: Any = field(init=False, repr=False)
这样SQLAlchemy就能正常设置该属性,同时保留slots的特性。
方法二:禁用slots
如果不需要slots带来的内存优化或属性限制,可以直接去掉slots=True参数,让dataclass使用普通的属性存储机制,SQLAlchemy就能动态添加_sa_instance_state属性:
@dataclass(weakref_slot=True) class Example: f1: str
内容的提问来源于stack exchange,提问作者hjgt
相关产品推荐
相关产品推荐

