Search code examples
pythonpython-3.xpython-dataclasses

Class with class variables as data attributes or using a dataclass


I am trying to decide between two styles, one using a class with only class variables and the other using dataclasses.

Class with class variables acting as data attributes:

class A1:
    foo: str = ""
    mut_list: list = []  # Note mutable default value

a = A1()
a.foo = "bar1"
a.mut_list = []
a.mut_list.append("baz1")

b = A1()
b.foo = "bar2"
b.mut_list = []  # Must set to empty list first before mutating
b.mut_list.append("baz2")

Versus making it a dataclass:

from dataclasses import dataclass, field

@dataclass
class A2:
    foo: str = ""
    mut_list: list = field(default_factory=list)

c = A2()
c.foo = "bar3"
c.mut_list.append("baz3")

d = A2()
d.foo = "bar4"
d.mut_list.append("baz4")

Which way is preferred and/or more clear to read?


Solution

  • In A1, you are defining unnecessary class attributes that are shadowed by explicitly defined instance attributes. You could have just written

    # You could even omit the annotated names altogether; they
    # are only used for type-checking.
    class A1:
        foo: str
        mut_list: list
    
    a = A1()
    a.foo = "bar1"
    a.mut_list = ["baz1"]
    

    In A2, the dataclass uses the class attributes to automatically define various methods, one of which (__init__) you should be but aren't using to avoid having to define the instance attributes explicitly.

    from dataclasses import dataclass, field
    
    @dataclass
    class A2:
        foo: str = ""
        mut_list: list = field(default_factory=list)
    
    c = A2("bar3", ["baz3"])
    

    I would definitely prefer A2 over A1, but only because it makes use of an __init__ method. You could just as easily add an __init__ method to A1 yourself to avoid having to assign to a.foo and a.mut_list after A1() returns.