I was looking forward to using the somewhat new typing.NamedTuple class, which allows the creation of named tuple classes using the usual Python class syntax (including the ability to add docstrings and methods, provide default values, type hints, etc etc).
However: the class at the bottom is producing the following error message:
AttributeError: Cannot overwrite NamedTuple attribute __new__
From this I gather just what it says: overriding __new__ is a still no-no. This is very disappointing.
The "old way" of going about this would be to inherit from a named tuple class, but this requires what I consider to be some ugly boilerplate code:
from collections import namedtuple
class FormatSpec(namedtuple('FormatSpecBase', 'fill align sign alt zero '
'width comma decimal precision type')):
__slots__ = ()
def __new__(cls, fill, align, sign, alt, zero,
width, comma, decimal, precision, type):
to_int=lambda x: int(x) if x is not None else x
zero=to_int(zero)
width=to_int(width)
precision=to_int(precision)
return super().__new__(cls, fill, align, sign, alt, zero,
width, comma, decimal, precision, type)
FormatSpec.__doc__=_FormatSpec.__doc__.replace('FormatSpecBase','FormatSpec')
Is there some other alternate way I can cast the zero, width, and precision arguments below to int prior to the creation of the named tuple, but still using the same class creation syntax? Or am I stuck using the old way?
from typing import NamedTuple, Optional
class FormatSpec(NamedTuple):
"""Represents a string that conforms to the [Format Specification
Mini-Language][1] in the string module.
[1]: https://docs.python.org/3/library/string.html#formatspec
"""
fill: Optional[str]
align: Optional[str]
sign: Optional[str]
alt: Optional[str]
zero: Optional[int]
width: Optional[int]
comma: Optional[str]
decimal: Optional[str]
precision: Optional[int]
type: str
def __new__(cls, fill, align, sign, alt, zero, width, comma, decimal, precision, type):
to_int=lambda x: int(x) if x is not None else x
zero=to_int(zero)
width=to_int(width)
precision=to_int(precision)
return super().__new__(cls, fill, align, sign, alt, zero,
width, comma, decimal, precision, type)
def join(self):
return ''.join('{!s}'.format(s) for s in self if s is not None)
def __format__(self, format_spec):
try:
return format(self.join(), format_spec)
except (TypeError, ValueError):
return super().__format__(format_spec)