{
  "$type": "site.standard.document",
  "canonicalUrl": "https://rednafi.com/python/declaratively-transform-dataclass-fields/",
  "description": "Leverage Python's __post_init__ hook to declaratively transform dataclass fields. Automatically serialize data with clean, maintainable code.",
  "path": "/python/declaratively-transform-dataclass-fields/",
  "publishedAt": "2022-03-20T00:00:00.000Z",
  "site": "at://did:plc:fgtm2c26vfcj74rfmeggbyqj/site.standard.publication/3mnl6f7ob462z",
  "tags": [
    "Python"
  ],
  "textContent": "While writing microservices in Python, I like to declaratively define the shape of the data\ncoming in and out of JSON APIs or NoSQL databases in a separate module. Both TypedDict and\ndataclass are fantastic tools to communicate the shape of the data with the next person\nworking on the codebase.\n\nWhenever I need to do some processing on the data before starting to work on that, I prefer\nto transform the data via dataclasses. Consider this example:\n\nThe above class defines the structure of a payload that'll be saved in a DynamoDB table. To\nmake things simpler, I want to serialize the request_payload, response_payload, and\nstatus_code fields to JSON string before saving them to the DB. Usually, I'd do it in the\nto_dynamodb_item like this:\n\nHowever, keeping track of this json.dumps transformation that's buried in a method can be\ndifficult. Also, it can be hard to track the fields that need to be deserialized whenever\nyou want the rich data structures back. Another disadvantage is that you'll have to perform\nthe same transformation again if you need serialized fields in another method. A better way\nis to take advantage of the __post_init__ hook exposed by dataclasses. Here's how you can\ndo it:\n\nRunning the script will print the following:\n\nNotice, how the intended fields are now JSON encoded. Python calls the __post_init__ hook\nof a dataclass after calling the __init__ method. If you don't generate any init by\ndecorating the target class with @dataclass(init=False), in that case, the __post_init__\nhook won't be executed.\n\nThe field function with repr=False allows us to exclude the configuration fields like\n_json_transform and _json_fields from the final __repr__ of the class. Notice that\nthese two fields are absent in the final representation of the dataclass instance.\n\nYou can turn off the JSON conversion by setting the _json_transform to False:\n\nYou can also add or remove fields to be transformed by changing the value of the\n_json_fields iterable of the class:\n\nThis will only serialize the status_code field. Neat!\n\nFurther reading\n\n- [Post-init processing - Python docs]\n\n\n\n\n[post-init processing - python docs]:\n    https://docs.python.org/3/library/dataclasses.html#post-init-processing",
  "title": "Declaratively transform data class fields in Python"
}