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):
try:
return self[self._namepos[attr]]
except KeyError:
raise AttributeError(attr) from None
def __repr__(self):
values = []
for name, i in self._namepos.items():
values.append(f'{name}={self[i]}')
return f'({", ".join(values)})'
Same outputs as above.
--
Terry Jan Reedy
_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/