I'm studying the meta-programming topic in Python, and as an exercise I'm trying to make a somewhat simplified version of dataclass. My goal in this exercise is to make the difference between annotated variables and usual ones to be as much transparent as possible. So I come with this code to obtain initial fields. It does not catch corner cases and as much as possible undressed to be short. So my question is there any visible pitfalls or am I doing something wrong from the early beginning?
Two helpful functions not to clutter `__annotations__`: from typing import Any AnyType = Any def _is_not_dunder(name): return not ((len(name) > 4) and (name[:2] == name[-2:] == '__')) def _is_not_descriptor(obj): return not (hasattr(obj, '__get__') or hasattr(obj, '__set__') or hasattr(obj, '__delete__')) The special dict (class namespace) to inject usual variables in ` __annotations__` with default typehint - `AnyType`, and also keep their ordered appearance in the class body. class SpecialDict(dict): def __init__(self): super().__init__() super().__setitem__('__annotations__', {}) def __setitem__(self, key, value): if not (key in self) and _is_not_dunder(key) and _is_not_descriptor(value): self['__annotations__'][key] = AnyType super().__setitem__(key, value) Data meta-class which defines `__fields` from `__annotations__`: class DataMeta(type): @classmethod def __prepare__(metacls, cls, bases, **kwargs): _dict = SpecialDict() return _dict def __init__(cls, *args , **kwargs): super().__init__(*args) def __new__(metacls, cls, bases, clsdict): clsdict['__fields'] = tuple(clsdict['__annotations__'].items()) _cls = type.__new__(metacls, cls, bases, clsdict) return _cls And test class: class MyClass(metaclass=DataMeta): a: float barattr: int = 2 jik = 12 bzik: int =14 def foo(self, param): pass data = MyClass() a.__fields # (('a', float), ('barattr', int), ('jik', typing.Any), ('bzik', int)) Thank you! With kind regards, -gdg -- https://mail.python.org/mailman/listinfo/python-list