Using namedtuples field names for column indices in a list of lists
Steven D'Aprano
steve+comp.lang.python at pearwood.info
Sun Jan 8 01:42:49 EST 2017
On Sunday 08 January 2017 16:39, Deborah Swanson wrote:
> What I've done so far:
>
> with open('E:\\Coding projects\\Pycharm\\Moving\\Moving 2017 in.csv',
> 'r') as infile:
> ls = list(csv.reader(infile))
> lst = namedtuple('lst', ls[0])
>
> where 'ls[0]' is the header row of the csv, and it works perfectly well.
> 'lst' is a namedtuple instance with each of the column titles as field
> names.
Are you sure? namedtuple() returns a class, not a list:
py> from collections import namedtuple
py> names = ['A', 'B', 'C']
py> namedtuple('lst', names)
<class '__main__.lst'>
The way namedtuple() is intended to be used is like this:
py> from collections import namedtuple
py> names = ['A', 'B', 'C']
py> Record = namedtuple('Record', names)
py> instance = Record(10, 20, 30)
py> print(instance)
Record(A=10, B=20, C=30)
There is no need to call fget directly to access the individual fields:
py> instance.A
10
py> instance.B
20
py> instance[1] # indexing works too
20
which is *much* simpler than:
py> Record.A.fget(instance)
10
I think you should be doing something like this:
pathname = 'E:\\Coding projects\\Pycharm\\Moving\\Moving 2017 in.csv'
with open(pathname, 'r') as infile:
rows = list(csv.reader(infile))
Record = namedtuple("Record", rows[0])
for row in rows[1:]: # skip the first row, the header
row = Record(row)
# process this row...
if row.location == 0:
...
[...]
> But I haven't found a way to assign new values to a list element. using
> namedtuple.fieldname. I think a basic problem is that namedtuples have
> the properties of tuples, and you can't assign to an existing tuple
> because they're immutable.
Indeed. Being tuples, you have to create a new one. You can do it with slicing,
like ordinary tuples, but that's rather clunky:
py> print(instance)
Record(A=10, B=20, C=30)
py> Record(999, *instance[1:])
Record(A=999, B=20, C=30)
The recommended way is with the _replace method:
py> instance._replace(A=999)
Record(A=999, B=20, C=30)
py> instance._replace(A=999, C=888)
Record(A=999, B=20, C=888)
Note that despite the leading underscore, _replace is *not* a private method of
the class. It is intentionally documented as public. The leading underscore is
so that it won't clash with any field names.
--
Steven
"Ever since I learned about confirmation bias, I've been seeing
it everywhere." - Jon Ronson
More information about the Python-list
mailing list