I'm trying to create a class to represent a list of named tuples and I'm having trouble with accessing elements by name. Here's an example:
from typing import NamedTuple
class Record(NamedTuple):
id: int
name: str
age: int
class NamedTupleList:
def __init__(self, data):
self._data = data
def attempt_access(self, row, column):
print(f'{self._data[row].age=}')
r = self._data[row]
print(f'{type(column)=}')
print(f'{column=}')
print(f'{r[column]=}')
data = [Record(1, 'Bob', 30),
Record(2, 'Carol', 25),
Record(3, 'Ted', 29),
Record(4, 'Alice', 28),
]
class_data = NamedTupleList(data)
print('show data')
print(f'{data[0]=}')
print(f'{type(data[0])=}')
print(f'{data[0].age=}')
print('\nshow class_data')
print(f'{type(class_data)=}')
print('\nattempt_access by index')
class_data.attempt_access(0, 2)
print('\nattempt_access by name')
class_data.attempt_access(0, Record.age) # why can't I do this?
Produces:
data[0]=Record(id=1, name='Bob', age=30)
type(data[0])=<class '__main__.Record'>
data[0].age=30
show class_data
type(class_data)=<class '__main__.NamedTupleList'>
attempt_access by index
self._data[row].age=30
type(column)=<class 'int'>
column=2
r[column]=30
attempt_access by name
self._data[row].age=30
type(column)=<class '_collections._tuplegetter'>
column=_tuplegetter(2, 'Alias for field number 2')
print(f'{r[column]=}')
~^^^^^^^^
TypeError: tuple indices must be integers or slices, not _collections._tuplegetter
So I can successfully access 'rows' and 'columns' by index, but if I want to access a column (i.e. namedtuple attribute) through a method call I get an error. What's interesting is that the column value is _tuplegetter(2, 'Alias for field number 2')
so the index is known in my method but I can't get to it. Does anyone know how I can access this value so that I can pass a name to the method? I'm trying to avoid passing the name as a string - I'd really like to take advantage of the namespace since that's one of the advantages of a namedtuple after all.
Interesting question. The field is a descriptor, so you can invoke it:
class NamedTupleList:
def __init__(self, data):
self._data = data
def attempt_access(self, row, column):
r = self._data[row]
try:
val = r[column]
except TypeError:
val = column.__get__(r)
return val
Demo:
>>> class_data.attempt_access(0, 2)
30
>>> class_data.attempt_access(0, Record.age)
30
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With