{
"$type": "site.standard.document",
"canonicalUrl": "https://rednafi.com/python/dataclasses/",
"description": "Master Python dataclasses to eliminate boilerplate code. Learn ordering, immutability, hashing, default values, and post-init processing.",
"path": "/python/dataclasses/",
"publishedAt": "2020-03-12T00:00:00.000Z",
"site": "at://did:plc:fgtm2c26vfcj74rfmeggbyqj/site.standard.publication/3mnl6f7ob462z",
"tags": [
"Python"
],
"textContent": "Recently, my work needed me to create lots of custom data types and draw comparison among\nthem. So, my code was littered with many classes that somewhat looked like this:\n\nThis class only creates a CartesianPoint type and shows a pretty output of the instances\ncreated from it. However, it already has two methods inside, __init__ and __repr__ that\ndon't do much.\n\nDataclasses\n\nLet's see how data classes can help to improve this situation. Data classes were introduced\nto python in version 3.7. Basically they can be regarded as code generators that reduce the\namount of boilerplate you need to write while generating generic classes. Rewriting the\nabove class using dataclass will look like this:\n\nIn the above code, the magic is done by the dataclass decorator. Data classes require you\nto use explicit [type annotations] and it automatically implements methods like __init__,\n__repr__, __eq__ etc beforehand. You can inspect the methods that dataclass auto\ndefines via Python's help.\n\nUsing default values\n\nYou can provide default values to the fields in the following way:\n\nUsing arbitrary field type\n\nIf you don't want to specify your field type during type hinting, you can use Any type\nfrom python's typing module.\n\nInstance ordering\n\nYou can check if two instances are equal without making any modification to the class.\n\nHowever, if you want to compare multiple instances of dataclasses, aka add __gt__ or\n__lt__ methods to your instances, you have to turn on the order flag manually.\n\nBy default, while comparing instances, all of the fields are used. In our above case, all\nthe fields x, y, zof point_1 instance are compared with all the fields of point_2\ninstance. You can customize this using the field function.\n\nSuppose you want to acknowledge two instances as equal only when attribute x of both of\nthem are equal. You can emulate this in the following way:\n\nYou can see the above code prints out True despite the instances have different y and\nz attributes.\n\nAdding methods\n\nMethods can be added to dataclasses just like normal classes. Let's add another method\ncalled dist to our CartesianPoint class. This method calculates the distance of a point\nfrom origin.\n\nMaking instances immutable\n\nBy default, instances of dataclasses are mutable. If you want to prevent mutating your\ninstance attributes, you can set frozen=True while defining your dataclass.\n\nIf you try to mutate the any of the attributes of the above class, it will raise\nFrozenInstanceError.\n\nMaking instances hashable\n\nYou can turn on the unsafe_hash parameter of the dataclass decorator to make the class\ninstances hashable. This may come in handy when you want to use your instances as dictionary\nkeys or want to perform set operation on them. However, if you're using unsafe_hash make\nsure that your dataclasses don't contain any mutable data structure in it.\n\nConverting instances to dicts\n\nThe asdict() function converts a dataclass instance to a dict of its fields.\n\nPost-init processing\n\nWhen dataclass generates the __init__ method, internally it'll call __post_init__\nmethod. You can add additional processing in the __post_init__ method. Here, I've added\nanother attribute tup that returns the cartesian point as a tuple.\n\nRefactoring the CartesianPoint class\n\nThe feature rich original CartesianPoint looks something like this:\n\nLet's see the class in action:\n\nBelow is the same class refactored using dataclass.\n\nUse this class like before.\n\nFurther reading\n\n- [Python dataclasses official docs]\n- [The ultimate guide to dataclasses in Python 3.7]\n\n\n\n\n[type annotations]:\n https://docs.python.org/3/library/typing.html\n\n[python dataclasses official docs]:\n https://docs.python.org/3/library/dataclasses.html\n\n[the ultimate guide to dataclasses in python 3.7]:\n https://realpython.com/python-data-classes/",
"title": "Reduce boilerplate code with Python's dataclasses"
}