[Python-ideas] namedtuple literals [Was: RE a new namedtuple]

Terry Reedy tjreedy at udel.edu
Sun Jul 30 21:40:19 EDT 2017

On 7/30/2017 2:57 PM, Markus Meskanen wrote:
> I've been experimenting with this:
> class QuickNamedTuple(tuple):
>      def __new__(cls, **kwargs):
>          inst = super().__new__(cls, tuple(kwargs.values()))
>          inst._names = tuple(kwargs.keys())
>          return inst
>      def __getattr__(self, attr):
>          if attr in self._names:
>              return self[self._names.index(attr)]
>          raise AttributeError(attr)
>      def __repr__(self):
>          values = []
>          for i, name in enumerate(self._names):
>              values.append(f'{name}={self[i]}')
>          return f'({", ".join(values)})'
> It's a quick scrap and probably not ideal code, but the idea is the 
> point. I believe this is how the new "quick" named tuple should ideally 
> work:
> In: ntuple = QuickNamedTuple(x=1, y=2, z=-1)
> In: ntuple
> Out: (x=1, y=2, z=-1)
> In: ntuple[1] == ntuple.y
> Out: True
> In: ntuple == (1, 2, 3)
> Out: True
> In: ntuple == QuickNamedTuple(z=-1, y=2, x=1)
> Out: False
> So yeah, the order of the keyword arguments would matter in my case, and 
> I've found it to work the best. How often do you get the keywords in a 
> random order? And for those cases, you have SimpleNameSpace, or you can 
> just use the old namedtuple. But most of the time you always have the 
> same attributes in the same order (think of reading a CSV for example), 
> and this would be just a normal tuple, but with custom names for the 
> indexes.

Using a name to position map:

class QuickNamedTuple(tuple):

     def __new__(cls, **kwargs):
         inst = super().__new__(cls, tuple(kwargs.values()))
         inst._namepos = {name: i for i, name in enumerate(kwargs.keys())}
         return inst

     def __getattr__(self, attr):
             return self[self._namepos[attr]]
         except KeyError:
             raise AttributeError(attr) from None

     def __repr__(self):
         values = []
         for name, i in self._namepos.items():
         return f'({", ".join(values)})'

Same outputs as above.

Terry Jan Reedy

More information about the Python-ideas mailing list