Skip to content

Instantly share code, notes, and snippets.

@TheArcherST
Last active July 6, 2023 11:47
Show Gist options
  • Save TheArcherST/fd9d924323de6e50cc7794d4a67fffd7 to your computer and use it in GitHub Desktop.
Save TheArcherST/fd9d924323de6e50cc7794d4a67fffd7 to your computer and use it in GitHub Desktop.
Python namedtuple, but a base class.
# https://gist.github.com/TheArcherST/fd9d924323de6e50cc7794d4a67fffd7
from typing import ClassVar, Type
from collections import namedtuple
from itertools import chain
class Namedtuple(
tuple # for IDE typechecker
):
"""Namedtuple base class
Allows to create namedtuple with explicitly defined fields,
to allow IDE like PuCharm infer field names and their types.
Example
-------
>>> from typing import Generic, TypeVar
>>> from numbers import Number
...
>>> _T = TypeVar("_T", bound=Number)
...
>>> class Coordinates2D(Namedtuple, Generic[_T]):
... x: _T
... y: _T
...
>>> class Coordinates3D(Coordinates2D[_T]):
... z: _T
...
>>> coord = Coordinates3D(1, 2, 3)
>>> print(coord)
Coordinates3D(x=1, y=2, z=3)
>>> print(coord.x)
1
"""
__tp: ClassVar[Type[tuple]]
def __init_subclass__(cls, **kwargs):
cls.__tp = namedtuple(
cls.__name__,
chain.from_iterable(
filter(lambda x: not x.startswith("_" + i.__name__),
getattr(i, "__annotations__", {}))
for i in reversed(cls.__mro__)
),
)
def __new__(cls, *args, **kwargs):
return cls.__tp(*args, **kwargs)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment