Skip to content

Instantly share code, notes, and snippets.

@technige
Created August 12, 2019 12:09
Show Gist options
  • Save technige/c721eb5c42ea2ef9df06415cbfd06903 to your computer and use it in GitHub Desktop.
Save technige/c721eb5c42ea2ef9df06415cbfd06903 to your computer and use it in GitHub Desktop.
from dataclasses import dataclass, fields
def neodataclass(_cls=None, *, init=True, repr=True, eq=True, order=False,
unsafe_hash=False, frozen=False):
""" Provides a wrapper around dataclass that silently filters out
any keyword arguments provided to __init__ that do not exist as
fields for that class.
"""
def wrap(cls):
""" The wrapper implementation, the outline of which is copied
from the standard library code to make functionality as
transparent as possible."""
# Generate the dataclass as normal
k = dataclass(cls, init=init, repr=repr, eq=eq, order=order,
unsafe_hash=unsafe_hash, frozen=frozen)
# Look for an __init__ implementation to override. If this isn't
# found then simply carry on as normal with the original
# dataclass.
try:
init_function = getattr(k, "__init__")
except AttributeError:
pass
else:
# Extract a list of all the field names for this class
field_names = [field.name for field in fields(k)]
def init_wrapper(*args, **kwargs):
""" Alternative __init__ implementation that filters
out redundant keyword arguments by checking against
the list of known fields
"""
# Create a filtered dictionary of keyword arguments...
filtered_kwargs = {name: value
for name, value in kwargs.items()
if name in field_names}
# ...and pass that to the original __init__ function.
return init_function(*args, **filtered_kwargs)
# Finally, assign the wrapped __init__ back to the
# attribute.
setattr(k, "__init__", init_wrapper)
return k
if _cls is None:
return wrap
return wrap(_cls)
@neodataclass
class Person:
name: str = None
age: int = None
def main():
print(Person(**{"name": "Alice", "age": 33, "gender": "F"}))
print(Person(name="Bob", age=44, gender="M"))
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment