使用 python-attrs 模块时使用 child class 启动基础时出现问题

Problem with initiating base with child class while working with python-attrs module

我正在尝试使用 attrs 模块创建模型 class。在我的脚本中 CollectionModel class 是在 User class 中继承的。所以从逻辑上讲,CollectionModel 中的所有属性都应该在 User 中可用。但是在尝试从字典创建 User 的新实例时(使用 attrs 是可能的)它表明 CollectionModel 的属性不存在于 User

我的脚本:

from bson import ObjectId
from attrs import asdict, define, field, validators, Factory
import time


@define
class CollectionModel:
    """ Base Class For All Collection Schema"""
    _id : str =   field(converter=str, default=Factory(ObjectId))
    _timestamp : float = field(default=Factory(time.time))

    def get_dict(self):
        return asdict(self)

    def update(self):
        self._timestamp = time.time()

@define
class User(CollectionModel):
    
    username : str = field(factory = str, validator=validators.instance_of(str)) 
    userType : str = field(factory = str, validator=validators.instance_of(str)) 
    password : str = field(factory = str, validator=validators.instance_of(str))



user_object = User()
new_user_object = User(**asdict(user_object))

在这里,我正在尝试从 user_object 创建一个新用户 object。它显示以下错误。

TypeError: User.__init__() got an unexpected keyword argument '_id'

估计是parent class一开始没有启动。所以我尝试用 super() 函数启动它,根据 attrs 文档,它应该用 __attrs_pre_init__ 来完成。来自文档:

The sole reason for the existence of __attrs_pre_init__ is to give users the chance to call super().__init__(), because some subclassing-based APIs require that.

所以修改后的childclass就变成了这样

@define
class User(CollectionModel):
    
    username : str = field(factory = str, validator=validators.instance_of(str)) 
    userType : str = field(factory = str, validator=validators.instance_of(str)) 
    password : str = field(factory = str, validator=validators.instance_of(str))

    def __attrs_pre_init__(self):
        super().__init__()

但问题依旧。我是否以错误的方式执行 OOP?或者它只是 attrs 模块的错误?

我已经解决了那个问题,但有两个问题。第一个,在 python 中,属性名称前的下划线使其成为私有属性。因此,从字典创建新实例时 _id 是一个意外的键。

第二个问题是,我确实需要一个 _id 字段,因为我正在使用 MongoDB。在 MongoDB 文档中 _id 被保留用作主键。

现在第一个问题可以通过将 _id 替换为 id_ 来解决(是的,在对面的下划线,因为 id 从字面上看是变量的 bad choice python).

中的名称

对于第二个问题,我进行了很多搜索,为 id_ 字段创建了一个别名。但是使用 attrs 模块并不简单。因此,在将数据放入 MongoDB 集合之前,我修改了 get_dict() 方法以获得完美的字典。

这里是修改后的CollectionModelclass和Userclass:

@define
class CollectionModel:
    """ Base Class For All Collection Schema"""
    id_: ObjectId =   field(default=Factory(ObjectId))
    timestamp : float = field(default=Factory(time.time))

    def get_dict(self):
        d = asdict(self)
        d["_id"] = d["id_"]
        del d["id_"]
        return d

    def update(self):
        self.timestamp = time.time()

@define
class User(CollectionModel):

    username : str = field(factory = str, validator=validators.instance_of(str)) 
    userType : str = field(factory = str, validator=validators.instance_of(str)) 
    password : str = field(factory = str, validator=validators.instance_of(str))

正在打印实例:

user_object = User()
print(user_object.get_dict())

输出:

{'timestamp': 1645131182.421929, 'username': '', 'userType': '', 'password': '', '_id': ObjectId('620eb5ae10f27b87de5be3a9')}