Reputation: 98505
I want to build-up a list from some individual items as well as groups of items defined by list comprehensions. Suppose I want a list ['foo', 0, 2, 4, 'bar']
, where 0,2,4
would come from a comprehension. The only way I know of doing it is:
['foo'] + [x*2 for x in range(3)] + ['bar']
Is there a way of doing it without explicit appending? I'm looking for some clever equivalent to the following non-working desired syntax:
['foo', x*2 for x in range(3), 'bar'] # invalid syntax :(
My presumption is that perhaps a similar syntax would avoid the creation of all the intermediate temporary lists that then have to be copied element-by-element in order to append them to the list being built, when using the explicit +
operator.
I'm looking for a solution that'd preferably be pythonic (idiomatic), for Python 2.7 and 3.x - should they be different.
The motivating code is below, where ScreamingBOM
is a named tuple - I'm trying to build the tuple up while creating as few temporaries as possible, since some of them may get quite sizable.
def make_screaming_bom(self, bom):
return ScreamingBOM(
summary = [
['', '', 'generated on: %s' % bom.time],
['', bom.unique_parts, 'unique parts'],
[]
]
+ [['', count, 'total %s' % (type)] for type, count in bom.counts.items()]
+ [
['', bom.total, 'total placements'],
[],
['BOM: %s' % (bom.title)],
['Assembly Part Number/Revision: %s / %s' % (bom.basename, bom.revision)],
['Customer: %s' % (bom.company)]
],
# other tuple fields follow
)
Upvotes: 0
Views: 93
Reputation: 155684
Best you can get to avoid temporaries is using generalized unpacking with a generator expression:
['foo', *(x*2 for x in range(3)), 'bar']
On CPython 3.9, that compiles to code equivalent to making an empty list, append
ing 'foo'
, extend
ing with the genexpr, then append
ing 'bar'
. The extend
step consumes the generator without realizing it as a list
, avoiding any temporaries. The code with a temporary list
(see bb1's answer) is likely to be slightly faster, but if you're set on avoiding temporaries, this is the most memory efficient solution.
The Python 2 "solution" is you just make a list
and manually append
and extend
line-by-line until you're done. If you really insist on one-liners no matter how ugly, using itertools.chain
will allow something fairly similar to how generalized unpacking worked when it was first introduced through 3.8 (items not unpacked were wrapped in temporary tuple
s, then a list
was built by unpacking all the arguments passed):
list(itertools.chain(('foo',), (x*2 for x in range(3)), ('bar',)))
But Python 2 has been end-of-life for over a year, so just write modern Python 3 code. :-)
Upvotes: 5