简体   繁体   English

使用 python-attrs 模块时启动子 class 的基础问题

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

I'm trying to create Model class with attrs module.我正在尝试使用attrs模块创建 Model class。 In my script CollectionModel class is inherited in User class. So logically all the attributes in the CollectionModel should be available in the User .在我的脚本中, CollectionModel class 继承自User class。因此从逻辑上讲, CollectionModel中的所有属性都应该在User中可用。 But while trying to create a new instance of User from dictionary (it is possible with attrs) it shows that attributes of CollectionModel are not present in the User但是在尝试从字典创建 User 的新实例时(使用 attrs 是可能的)它表明CollectionModel的属性不存在于User

My Script:我的脚本:

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))

Here, I'm trying to create a new User object from the user_object .在这里,我试图从user_object创建一个新的用户 object。 It shows the following error.它显示以下错误。

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

I guessed that the parent class is not initiated at first.一开始我猜是parent class没有发起。 So I tried to initiate it with the super() function and according to attrs documentation it should be done with __attrs_pre_init__ .所以我尝试用super() function 启动它,根据 attrs 文档,它应该用__attrs_pre_init__来完成。 From the documentation:从文档中:

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. __attrs_pre_init__存在的唯一原因是让用户有机会调用super().__init__() ,因为一些基于子类的 API 需要这样做。

So the modified child class becomes like this.于是修改后的child class就变成这样了。

@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__()

But the problem still remains.但问题仍然存在。 Am I doing the OOP in the wrong way?我以错误的方式执行 OOP 吗? Or is it just a bug of attrs module?或者它只是attrs模块的错误?

I've solved that issue and there were two problems.我已经解决了那个问题,但有两个问题。 The first one, in python, underscore before an attribute name makes it a private attribute.第一个,在 python 中,属性名称前的下划线使其成为私有属性。 So while creating a new instance from dictionary _id is an unexpected key.因此,从字典创建新实例时, _id是一个意想不到的键。

The second problem is, I indeed need an _id field as I'm working with MongoDB. In MongoDB document _id is reserved for using as a primary key.第二个问题是,我确实需要一个_id字段,因为我正在使用 MongoDB。在 MongoDB 中,文档_id被保留用作主键。

Now the first problem can be solved by replacing _id to id_ (yes, underscore in the opposite side since id is literally a bad choice for a variable name in python).现在第一个问题可以通过将_id替换为id_来解决(是的,在对面的下划线,因为id实际上是 python 中变量名的错误选择)。

For the second problem I've searched a lot to make an alias for id_ field.对于第二个问题,我搜索了很多来为id_字段创建别名。 But it is not simply easy while working with attrs module.但是使用attrs模块并不简单。 So I've modified the get_dict() method to get a perfect dictionary before throwing my data in MongoDB collection.因此,在将数据放入 MongoDB 集合之前,我修改了get_dict()方法以获得完美的字典。

Here is the modified CollectionModel class and User class:这是修改后的CollectionModel class 和User class:

@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))

Now printing an instance:现在打印一个实例:

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

Output: Output:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM