Richard Neumann <m...@richard-neumann.de> added the comment:
I just stumbled across this issue trying to resolve this: https://bugs.python.org/issue42765? While this fails: from typing import NamedTuple class Spamm(NamedTuple): foo: int bar: str def __getitem__(self, index_or_key): """Returns the respective item.""" if isinstance(index_or_key, str): try: return getattr(self, index_or_key) except AttributeError: raise IndexError(index_or_key) from None return super().__getitem__(index_or_key) def keys(self): return self._fields def main(): spamm = Spamm(12, 'hello') print(dir(spamm)) print(spamm._fields) d = dict(spamm) print(d) if __name__ == '__main__': main() with Traceback (most recent call last): File "/home/neumann/test.py", line 4, in <module> class Spamm(NamedTuple): RuntimeError: __class__ not set defining 'Spamm' as <class '__main__.Spamm'>. Was __classcell__ propagated to type.__new__? The following works: from typing import NamedTuple def _getitem(instance, index_or_key): """Returns the respective item.""" if isinstance(index_or_key, str): try: return getattr(instance, index_or_key) except AttributeError: raise IndexError(index_or_key) from None return super().__getitem__(index_or_key) def dicttuple(cls: tuple): """Extends a tuple class with methods for the dict constructor.""" cls.keys = lambda self: self._fields cls.__getitem__ = _getitem return cls @dicttuple class Spamm(NamedTuple): foo: int bar: str def main(): spamm = Spamm(12, 'hello') print(dir(spamm)) print(spamm._fields) d = dict(spamm) print(d) if __name__ == '__main__': main() And produces: ['__add__', '__annotations__', '__class__', '__class_getitem__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__module__', '__mul__', '__ne__', '__new__', '__orig_bases__', '__reduce__', '__reduce_ex__', '__repr__', '__rmul__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', '_asdict', '_field_defaults', '_fields', '_make', '_replace', 'bar', 'count', 'foo', 'index', 'keys'] ('foo', 'bar') {'foo': 12, 'bar': 'hello'} I am a bit baffled, why it works when the method is injected via a decorator. ---------- nosy: +conqp _______________________________________ Python tracker <rep...@bugs.python.org> <https://bugs.python.org/issue41629> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com