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

Deborah Swanson python at deborahswanson.net
Mon Jan 9 23:27:38 EST 2017


MRAB wrote, on January 09, 2017 7:37 PM
> 
> 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.

Appreciate your explanation of why this statement looks like a list
comprehension, but it isn't one.
 
> > 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.) 

>>> [1,2,3]
[1, 2, 3]
>>> type(_)
<class 'list'>

So it is a list, despite not being made by a list comprehension and
despite its non-listlike behaviors. Guess I've never looked at the type
of a list before, probably because lists are so obvious by looking at
them.

> > '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!

As testified by IDLE above!  ;)  A list of namedtuples may be an
instance of a list, but it doesn't always behave like a list of lists.
For example, if you want to modify an element of a record in records,
you can't just say 

'record.Location = Tulsa' 

like you can say 

'record[Location] = Tulsa'

because each record is very much like a tuple, and tuples are immutable.
You have to use the _replace function:

record._replace(Location) = Tulsa

This is very unlike a list of lists. Only the outer data structure is a
list, and inside it's all namedtuples.

So it's not a list of lists, it's a list of namedtuples.  But .sort and 
sorted() DTRT, and that's valuable.

> > 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".
> 
> -- 
> https://mail.python.org/mailman/listinfo/python-list
> 



More information about the Python-list mailing list