Constructors often need inputs that shouldn't be stored, and classes need constants that aren't per-instance data.
Two special annotations change how a name is treated.
`ClassVar[T]` marks a true class attribute: not a field, not in __init__, __repr__ or comparisons. Use it for constants and registries shared by all instances:
MAX_ITEMS: ClassVar[int] = 100Without ClassVar, an annotated name with a default would become a per-instance field.
`InitVar[T]` marks an init-only pseudo-field: it becomes a parameter of __init__ and is passed to __post_init__ as an argument, in field order, but is not stored on the instance, not shown in repr, and not returned by fields().
@dataclass
class User:
name: str
password: InitVar[str]
password_hash: str = field(init=False)
def __post_init__(self, password):
self.password_hash = hash_it(password)Typical uses: raw inputs to transform (a password to hash, a path to load), a database handle used only to fetch a value, or a flag that changes initialisation.
Note that replace() must be given every InitVar without a default, because it calls __init__ again and InitVars aren't stored.
Example
import hashlib
from dataclasses import InitVar, dataclass, field, fields
from typing import ClassVar
@dataclass
class Account:
username: str
password: InitVar[str]
password_hash: str = field(init=False, repr=False)
MIN_LENGTH: ClassVar[int] = 8 # class constant, not a field
def __post_init__(self, password: str) -> None:
if len(password) < self.MIN_LENGTH:
raise ValueError("password too short")
self.password_hash = hashlib.sha256(password.encode()).hexdigest()[:12]
acct = Account("ada", "correct horse")
print(acct) # Account(username='ada')
print(acct.password_hash) # 4104d36f8da2
print([f.name for f in fields(acct)]) # ['username', 'password_hash']
print(hasattr(acct, "password")) # False: InitVar is not storedRemember
- ClassVar annotations are class attributes, not fields
- InitVar values go to __init__ and __post_init__ but aren't stored
- fields() lists neither ClassVar nor InitVar pseudo-fields
Watch out for
- Forgetting ClassVar on a class constant, which turns it into a constructor parameter.