Mattia Surricchio
Mattia Surricchio

Reputation: 1618

Initialize frozen dataclass attribute with function

I am working with frozen dataclasses in Python. My goal is to create a dataclass with its frozen attributes. However, one of the attributes is a function of the other ones. I want my class to be frozen (once it has been instantiated it can't be changed), but I can't find a way to specify the value of an attribute inside the class with a method.

As an example, let's suppose to have the following simple class:

@dataclasses.dataclass(frozen=True)
class Car:
    color: str
    size: int
    model: str
    price: float

The price of the car is function of its color, size and model. As an example:

def _compute_price(self, color, size, model):

    if color == 'red':
       color_surplus = 10
    else:
       color_surplus = 0

    if size > 10:
       size_surplus = 10
    else:
       size_surplus = 5

    if model == 'mustang':
       model_surplus = 100
    else:
       model_surplus = 0

    self.price = color_surplus + size_surplus + model_surplus

I would like to create my car like:

car = Car('red', 15, 'mustang') 

And automatically use the above sample function inside my class to initialize the missing price attribute. However, as soon as I specify self.price, Python tells me that it is a read only attribute and thus non-assignable. I also tried to use the __init__ function, but I still have the same problem:

@dataclasses.dataclass(frozen=True)
class Car:

    def __init__(self,  color: str, size: int, model: str, price: float):
        
        self.color = color #error here
        ...
        ...

    

Any solutions? My goal is to use a frozen dataclass while being able to specify an attribute with a private function (included in the class) of the other ones

Upvotes: 3

Views: 1543

Answers (1)

Ruy Goncalves
Ruy Goncalves

Reputation: 56

Make price a property, wich are read only if you don't create a setter:

@property
def price(self):

    if self.color == 'red':
        color_surplus = 10
    else:
       color_surplus = 0

    if self.size > 10:
       size_surplus = 10
    else:
       size_surplus = 5
    if self.model == 'mustang':
       model_surplus = 100
    else:
       model_surplus = 0

    return color_surplus + size_surplus + model_surplus

You can also use cached_property instead of property to not recompute the value each time you call it

Upvotes: 4

Related Questions