Search code examples
pythonpython-dataclasses

How to mutate dataclass argument upon instantiation?


I have a dataclass that looks like this:

@dataclass
class AllLastTick:
    tick_type_mapping = {
        0: "bid_size",
        1: "bid_price",
        2: "ask_price",
        3: "ask_size",
        4: "last_trade_price",
        5: "last_trade_size"
    }
    time: int
    tick_type: int
    price: float
    size: Decimal

And I instantiate it like this:

tick_data = (
    time,
    tick_type,
    price,
    size
)

tick = AllLastTick(*tick_data)

The result is something that looks like this:

AllLastTick(time=1699358716, tick_type=2, price=178.49, size=Decimal('200'))

What I'd like to do is convert the tick_type argument to the value in AllLastTick .tick_type_mapping when the class is instantiated.

The ideal result would look like this:

AllLastTick(time=1699358716, tick_type="ask_price", price=178.49, size=Decimal('200'))

I've tried using something like this:

...
tick_type: int = field(default_factory=lambda x: tick_type_mapping[x])
...

Which I understand does not work because the fields cannot be mutable (question mark on this point).

How can I accomplish this?


Solution

  • How about using __post_init__? See the docs.

    from dataclasses import dataclass, field
    from decimal import Decimal
    
    class AllLastTick:
        tick_type_mapping = {
            0: "bid_size",
            1: "bid_price",
            2: "ask_price",
            3: "ask_size",
            4: "last_trade_price",
            5: "last_trade_size"
        }
        time: int
        tick_idx: int
        tick_type: str = field(init=False)
        price: float
        size: Decimal
        def __post_init__(self):
            self.tick_type = self.tick_type_mapping[self.tick_idx]
    

    Then,

    tick = AllLastTick(*tick_data)
    

    Will use the index and define a tick type for you. You just need to store the key in another attribute (tick_idx).