Skip to content

Instantly share code, notes, and snippets.

@ZechCodes
Last active March 20, 2022 15:43
Show Gist options
  • Save ZechCodes/a09ec511bafdbf1d9f734a4288c96ec2 to your computer and use it in GitHub Desktop.
Save ZechCodes/a09ec511bafdbf1d9f734a4288c96ec2 to your computer and use it in GitHub Desktop.
Apply Mutations on Dataclass Fields
from __future__ import annotations
import json
from dataclasses import dataclass, MISSING, field as _field
from typing import Any, Callable
class MutationDescriptor:
def __init__(self, mutator: Callable[[Any], Any]):
self._mutator = mutator
self._attr = None
def __set_name__(self, owner, name):
self._attr = name
def __set__(self, instance, value):
instance.__dict__[self._attr] = self._mutator(value)
def field(*, default=MISSING, default_factory=MISSING, init=True, repr=True,
hash=None, compare=True, metadata=None, kw_only=MISSING, mutation=MISSING):
kwargs = locals() # Gets the field args while maintaining IDE autocomplete/type hinting
del kwargs["mutation"]
if mutation is not MISSING:
if not callable(mutation):
raise TypeError(f"Mutation callable '{mutation!r}' is not a callable.")
kwargs["default"] = MutationDescriptor(mutation)
return _field(**kwargs)
@dataclass
class Hello:
a: int = field(mutation=lambda x: x ** 2)
b: dict = field(mutation=json.dumps)
print(Hello(4, {"a": "b"}))
@ZechCodes
Copy link
Author

Inspired by @rednafi's tweet

@rednafi
Copy link

rednafi commented Mar 20, 2022

This is one honking great idea.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment