Using namedtuples field names for column indices in a list of lists

MRAB python at mrabarnett.plus.com
Mon Jan 9 22:37:01 EST 2017


On 2017-01-10 03:02, Deborah Swanson wrote:
> 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.
 >
This is a list comprehension:

     [Record._make(row) for row in rows]

and this is a generator expression:

     (Record._make(row) for row in rows)

It needs the outer parentheses.

The .extend method will accept any iterable, including list comprehensions:

     records.extend([Record._make(row) for row in rows])

and generator expressions:

     records.extend((Record._make(row) for row in rows))

In the latter case, the generator expression is the only argument of the 
.extend method, and Python lets us drop the pair of parentheses:

     records.extend(Record._make(row) for row in rows)

If there were another argument, it would be ambiguous and Python would 
complain.

> 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.
>
Its type is 'list', so it's an instance of a list, i.e. it's a list!

> 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. ;)
>
The list class has the .sort method, which sorts in-place. The 'sorted' 
function is a simple function that takes an iterable, iterates over it 
to build a list, sorts that list in-place, and then returns the list.

The oft-stated rule is that not every 2- or 3-line function needs to be 
a built-in, but 'sorted' is one of those cases where it's just nice to 
have it, a case of "practicality beats purity".



More information about the Python-list mailing list