The Python Oracle

How to avoid running a deadly function 30,000 times in a list comprehension?

--------------------------------------------------
Rise to the top 3% as a developer or hire one of them at Toptal: https://topt.al/25cXVn
--------------------------------------------------

Music by Eric Matyas
https://www.soundimage.org
Track title: Forest of Spells Looping

--

Chapters
00:00 How To Avoid Running A Deadly Function 30,000 Times In A List Comprehension?
02:27 Accepted Answer Score 6
03:10 Answer 2 Score 1
03:36 Thank you

--

Full question
https://stackoverflow.com/questions/4648...

--

Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...

--

Tags
#python #python3x #listcomprehension

#avk47



ACCEPTED ANSWER

Score 6


No repro? This code does not run deadly_func on all the elements of listB. Just the ones where the corresponding listA value is True:

listA = [True, False, True, False]
listB = [1, 2, 3, 4]

def deadly_func(x):
    print("Called with {}".format(x))
    return x

print([(a, deadly_func(b)) for a, b in zip(listA, listB) if a])

# Output:
# Called with 1
# Called with 3
# [(True, 1), (True, 3)]

EDIT

Based on the updated question, my guess is that sf.shapes() is the expensive part. Thus calling sf.shape(i) on only the subset of elements you want is more efficient.

If my guess is correct, this should do the trick:

records = [(r[0], shpgeo.shape(sf.shape(i).__geo_interface__)) for i, r in enumerate(sf.records()) if haversine(lon, lat, float(r[8]), float(r[7])) < 10]

(Of course, this is mostly what you already did.)




ANSWER 2

Score 1


If you are having trouble with a list comprehension, sometimes it is easier to deconstruct it down to its for loop equivalent.

Such as:

things = []

for a, b in zip(listA, listB):
    if a == "condition":
        things.append(a, deadly_func(b))

It would be helpful to see your input/output. This isn't a full answer, but might help you debug your code.

Also, you can reduce the size of your input to the first 1000 for debugging by adding:

for a, b, in zip(listA, listB)[:1000]:
....