Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

336
Visualizações
Problem with initiating base with child class while working with python-attrs module

I'm trying to create Model class with attrs module. In my script CollectionModel class is inherited in User class. So logically all the attributes in the CollectionModel should be available in the 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

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. 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. So I tried to initiate it with the super() function and according to attrs documentation it should be done with __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.

So the modified child class becomes like this.

@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? Or is it just a bug of attrs module?

over 4 years ago · Santiago Trujillo
1 Respostas
Responde à pergunta

0

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. So while creating a new instance from dictionary _id is an unexpected key.

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.

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

For the second problem I've searched a lot to make an alias for id_ field. But it is not simply easy while working with attrs module. So I've modified the get_dict() method to get a perfect dictionary before throwing my data in MongoDB collection.

Here is the modified CollectionModel class and 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:

{'timestamp': 1645131182.421929, 'username': '', 'userType': '', 'password': '', '_id': ObjectId('620eb5ae10f27b87de5be3a9')}
over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda