Search code examples
pythonpython-3.xpython-dataclasses

Proper way to create class variable in Data Class


I've just begun playing around with Python's Data Classes, and I would like confirm that I am declaring Class Variables in the proper way.

Using regular python classes

class Employee:

    raise_amount = .05

    def __init__(self, fname, lname, pay):
        self.fname = fname
        self.lname = lname
        self.pay = pay

Using python Data Class

@dataclass
class Employee:
    fname: str
    lname: str
    pay: int
    raise_amount = .05

The class variable I am referring to is raise_amount. Is this a properly declared class variable using Data Classes? Or is there a better way of doing so?

I have tested the data class implementation already and it provides the expected functionality, but I am mainly wondering if my implementation is following best practices.


Solution

  • To create a class variable, annotate the field as a typing.ClassVar or not at all.

    from typing import ClassVar
    from dataclasses import dataclass
    
    @dataclass
    class Foo:
        ivar: float = 0.5
        cvar: ClassVar[float] = 0.5
        nvar = 0.5
    
    foo = Foo()
    Foo.ivar, Foo.cvar, Foo.nvar = 1, 1, 1
    print(Foo().ivar, Foo().cvar, Foo().nvar)   # 0.5 1 1
    print(foo.ivar, foo.cvar, foo.nvar)         # 0.5 1 1
    print(Foo(), Foo(12))                       # Foo(ivar=0.5) Foo(ivar=12)
    

    There is a subtle difference in that the unannotated field is completely ignored by @dataclass, whereas the ClassVar field is stored but not converted to an attribute.


    dataclasses — Data Classes

    The member variables [...] are defined using PEP 526 type annotations.

    Class variables

    One of two places where dataclass() actually inspects the type of a field is to determine if a field is a class variable as defined in PEP 526. It does this by checking if the type of the field is typing.ClassVar. If a field is a ClassVar, it is excluded from consideration as a field and is ignored by the dataclass mechanisms. Such ClassVar pseudo-fields are not returned by the module-level fields() function.