Using namedtuples field names for column indices in a list of lists
Deborah Swanson
python at deborahswanson.net
Mon Jan 9 22:02:59 EST 2017
Erik wrote, on January 09, 2017 5:47 PM
> As people keep saying, the object you have called 'records'
> is a *list*
> of namedtuple objects. It is not a namedtuple.
>
> IIRC, you create it using a list comprehension which creates the
> records. A list comprehension always creates a list.
Well no. The list is created with:
records.extend(Record._make(row) for row in rows)
I'm new to both namedtuples and list comprehensions, so I'm not exactly
sure if this statement is a list comprehension. It looks like it could
be. In any case I recreated records in IDLE and got
>>> type(records)
<class 'list'>
So it's a class, derived from list? (Not sure what the 'list' means.)
'records' is in fact a class, it has an fget method and data members
that I've used. And it behaves like a list sometimes, but many times
not.
The only reason I've hedged away from advice to treat records as a list
for sorting until I tried it for myself, was because of an awful lot of
strange behavior I've seen, while trying to do the same things with
namedtuples as I routinely do with scalars and lists. This is all new,
and until now, unexplored territory for me. And I generally avoid saying
I'm sure or outright agreeing with something unless I really do know it.
> The sorted() function and the list.sort() method can be used
> to sort a
> list containing any objects - it's just a case of telling them how to
> obtain the key values to compare (which, in the case of
> simple attribute
> access which the namedtuple objects allow,
> "operator.attrgetter()" will
> do that). This is why sorting the list works for you.
>
> You could sort objects of different types - but you might
> need to supply
> a function instead of operator.attrgetter() which looks at
> the type of
> each object and returns something that's obtained differently
> for each
> type (but which the sort function can compare).
>
>
>
>
> When you say 'Foo = namedtuple("Foo", "spam ham")', you are
> creating a
> "factory" which is able to generate "Foo" objects for you.
>
> When you say "x = Foo(1, 2)" you are using the factory to create an
> object for you which has its "spam" and "ham" attributes set to the
> values 1 and 2 respectively.
>
> When you say "records = [Foo(x, y) for x, y in some_iterable()]", you
> are creating a list of such objects. This is the thing you
> are then sorting.
>
>
>
> Does that make sense?
>
> Regards, E.
Perfect sense. And now that I've confirmed in code that both sorted()
and
.sort() behave as hoped for with namedtuples, I couldn't be happier. ;)
The only thing I don't think you have 100% correct is your assertion
that records is a list. And I'm really not sure now that
records.extend(Record._make(row) for row in rows)
is a list comprehension.
That's the last statement in the creation of 'records', and immediately
after that statement executes, the type function says the resulting
'records' is a class, probably derived from list, but it's not a
straight up list.
'records' is enough different that you can't assume across the board
that namedtuples created this way are equivalent to a list. You do run
into problems if you assume it behaves like a list, or even like
standard tuples, because it doesn't always. Believe me, when I first
started working with namedtuples, I got plenty snarled up debugging code
that was written assuming list behavior to know that a namedtuple of
namedtuples is not exactly a list. Or even exactly like a list.
But that's just a quibble. The important thing in this context is that
both .sort() and sorted() treat it like a list and DTRT. And that's
very nice. ;)
Deborah
More information about the Python-list
mailing list