HarvB
HarvB

Reputation: 50

Dataclass to ignore attribute in asdict in Python

I am creating a Python Tkinter MVC project using dataclasses and I would like to create widgets by iterating through the dictionary generated by the asdict method (when passed to the view, via the controller); however, there are attributes which I don't wish to include in the set of widgets. Before this edit I posted something similar to the class below (this is now more specific to the project I am working on, thanks to @Prune, @Cameron_McFee and @Brian_McCutchon for their responses). Is there a way to exclude attributes from the asdict method? In the example below I don't want to include the 'customer' in the dictionary.

I tried, experimentally, including the two field specifications - repr=False and init=False on two of the fields but I guessed they wouldn't work and they don't.

@dataclass
class Product:
    name: str
    description: str = field(repr=False)
    N: float = field(init=False, default=0.0)
    P: float
    K: float
    _customer = None #class variable until assigned
    self._customer # but 'self' doesn't exist in this context.

    @property
    def customer(self):
        return self._customer

    @customer.setter
    def customer(self, value):
        self._customer = value

I understand there are different ways to construct the class to achieve this, perhaps avoiding dataclasses, e.g:

class Product:

    def __init__(self, name: str, description: str, N: float, P: float, K: float):
        self.name = name
        self.description = description
        self.N = N
        self.P = P
        self.K = K
        self._customer = None 

    @property
    def customer(self):
        return self._customer

    @customer.setter
    def customer(self, value):
        self._customer = value

This involves more boilerplate which I would like to avoid if possible. An imperfect analogy would be a model in C# which can be instantiated using Dapper or EF.

Upvotes: 2

Views: 3198

Answers (2)

urpok23
urpok23

Reputation: 21

You can use InitVar:

from dataclasses import asdict, dataclass, InitVar, field

@dataclass
class A:
    a: int
    b: str
    ignore_me: InitVar[bool] = field()

a = A(1, "2", False)
print(asdict(a))  # prints "{'a': 1, 'b': '2'}"

Details: asdict internally uses fileds() for dataclass instances, but from docs we know that:

InitVar is not returned by the module-level fields() function

Upvotes: 0

Cameron McFee
Cameron McFee

Reputation: 396

From PEP 557:

The dataclass decorator examines the class to find fields. A field is defined as any variable identified in annotations. That is, a variable that has a type annotation. With two exceptions described below, none of the Data Class machinery examines the type specified in the annotation.

So it's valid python code but the _dib class variable (or the dib property) will not be included in the generated comparative methods as _dib is not in __annotations__

Upvotes: 1

Related Questions