Python idiom: understanding a list with a limit of elements

I am basically trying to do this (pseudocode, invalid python):

limit = 10
results = [xml_to_dict(artist) for artist in xml.findall('artist') while limit--]

So how can I do this in a concise and effective way? An XML file can contain anything from 0 to 50 artists, and I can’t control how many of them can be obtained at one time, and AFAIK, there is no XPATH expression to say something like “get me up to 10 nodes”.

Thank!

+3
source share
5 answers

Assuming that it xmlis an object ElementTree, the method findall()returns a list, so just draw this list:

limit = 10
limited_artists = xml.findall('artist')[:limit]
results = [xml_to_dict(artist) for artist in limited_artists]
+5
source

lxml? XPath , .

>>> from lxml import etree
>>> from io import StringIO
>>> xml = etree.parse(StringIO('<foo><bar>1</bar><bar>2</bar><bar>4</bar><bar>8</bar></foo>'))
>>> [bar.text for bar in xml.xpath('bar[position()<=3]')]
['1', '2', '4']

itertools.islice ,

>>> from itertools import islice
>>> [bar.text for bar in islice(xml.iterfind('bar'), 3)]
['1', '2', '4']
>>> [bar.text for bar in islice(xml.iterfind('bar'), 5)]
['1', '2', '4', '8']
+6
limit = 10
limited_artists = [artist in xml.findall('artist')][:limit]
results = [xml_to_dict(artist) for limited_artists]
+2
source

This avoids trimming problems: it does not change the order of operations and does not create a new list, which may be important for large lists if you filter the list comprehension.

def first(it, count):
    it = iter(it)
    for i in xrange(0, count):
        yield next(it)
    raise StopIteration

print [i for i in first(range(1000), 5)]

It also works correctly with generator expressions, where slicing crashes due to memory usage:

exp = (i for i in first(xrange(1000000000), 10000000))
for i in exp:
    print i
+2
source

For everyone who found this question, because they tried to restrict the elements returned from the infinite generator:

from itertools import takewhile
ltd = takewhile(lambda x: x[0] < MY_LIMIT, enumerate( MY_INFINITE_GENERATOR ))
# ^ This is still an iterator. 
# If you want to materialize the items, e.g. in a list, do:
ltd_m = list( ltd )
# If you don't want the enumeration indices, you can strip them as usual:
ltd_no_enum = [ v for i,v in ltd_m ]
+2
source

Source: https://habr.com/ru/post/1760817/


All Articles