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