Boris Gorelik
Boris Gorelik

Reputation: 31797

Why can't I override `to_dict` method of a `dataclass` object that uses `dataclasses_json`?

dataclasses_json is a library that provides JSON capabilities to python's data classes. I noticed that overriding to_dict method has no effect. Here's an example:

@dataclass_json
@dataclass
class Message2:
    message: str
    weight: int
    def to_dict(self, encode_json=False):
        print('Custom to_dict')
        ret = {'MESSAGE': self.message, 'WEIGHT': self.weight}
        return ret
m2 = Message2('m2', 2)
print(m2.to_dict())

The code prints the following:

{'message': 'm2', 'weight': 2}

While I was expecting

Custom to_dict
{'MESSAGE': 'm2', 'WEIGHT': 2}

If I remove the @dataclass_json line, I get the desired output.

So, my questions are:

  1. Why defining a function had no effect with @dataclass_json but worked without it?

  2. How can I override to_dict and use @dataclass_json?

Upvotes: 2

Views: 7077

Answers (2)

Rian Wouters
Rian Wouters

Reputation: 1

It gets more complicated if your custom to_dict wants to call the dataclass to_dict assigned by the decorator. In that case, you might want to wrap the generated function in a new function after the class definition.

def custom_to_dict(super_fn):
    @classmethod
    def to_dict(cls, *args, **kwargs):
        fn = super_fn
        # your stuff...
        return fn(*args, *kwargs)
    return to_dict
Message2.to_dict= custom_from_dict(Message2.to_dict)

I am sure it is possible to do this with a decorator as well.

Upvotes: 0

sanyassh
sanyassh

Reputation: 8540

  1. Because dataclass_json simply overrides your to_dict method here:
    cls.to_dict = DataClassJsonMixin.to_dict
  1. One possible way is to define a method with different name and after applying dataclass_json decorator use this method to create to_dict method. Complete example with decorator:
from dataclasses import dataclass
from dataclasses_json import dataclass_json


def recover_to_dict(cls):
    if hasattr(cls, '_to_dict'):
        setattr(cls, 'to_dict', getattr(cls, '_to_dict'))
    return cls


@recover_to_dict
@dataclass_json
@dataclass
class Message2:
    message: str
    weight: int
    def _to_dict(self, encode_json=False):
        print('Custom to_dict')
        ret = {'MESSAGE': self.message, 'WEIGHT': self.weight}
        return ret
m2 = Message2('m2', 2)
print(m2.to_dict())

Upvotes: 8

Related Questions