Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Class Attribute and metaclass in dataclasses

I have some Python classes with class attributes and metaclass:

from abc import ABCMeta

class OldProduct(metaclass=ABCMeta):
    c_type: str
    c_brand: str

    def __init__(self, name:str):
        self.name = name

class OldLegoBox(OldProduct):
    c_type = "Toy"
    c_brand = "Lego"

    def __init__(self, name:str, price:float):
        self.name = name
        self.price = price

oldbox1 = OldLegoBox("Princess", 12.3)
print(oldbox1.c_brand)
oldbox2 = OldLegoBox("Knight", 42.3)
print(oldbox2.c_brand)

I would like to use dataclasses to improve the code: how to deal with the class properties c_type and c_brand?

I am thinking of the following which seems to fill my need:

from abc import ABCMeta
from dataclasses import dataclass, field


@dataclass
class Product(metaclass=ABCMeta):
    c_type: str
    c_brand: str
    name: str


@dataclass
class LegoBox(Product):
    name: str
    price: float
    c_type: str = field(default="Toy", init=False)
    c_brand: str = field(default="Lego", init=False)


box1 = LegoBox("Princess", 12.3)
print(box1)
box1.price = 1000
box1.name = "toto"
box1.c_brand = "some brand"
print(box1)
box2 = LegoBox("Knight", 42.3)
print(box2)

Is there a more appropriate approach?

like image 590
Jean-Francois T. Avatar asked Sep 17 '19 01:09

Jean-Francois T.


1 Answers

Dataclass class variables should be annotated with typing.ClassVar

@dataclass
class Product(metaclass=ABCMeta):
    c_type: ClassVar[str]
    c_brand: ClassVar[str]
    name: str

@dataclass
class LegoBox(Product):
    c_type: ClassVar[str] = "Toy"
    c_brand: ClassVar[str] = "Lego"
    price: float

Using abstract classes doesn't actually get you anything here, as far as I can tell, because there are no abstract methods. You can still create instances of Product, but they will not have c_type or c_brand attributes.

like image 79
Patrick Haugh Avatar answered Sep 30 '22 11:09

Patrick Haugh