Ok so let's start with a basic point about playing to the strengths of each environment and what the tradeoffs of each approach are.
Python is very consistent regarding how things are handed via iteration. So ideally you want to structure your code as:
for city in cities():
crawl_yelp(city)
Now the obvious, simple approach is to return a cursor and then as you iterate over it, you get a record you pass into your crawl function. If your database is not under high write load, my suspicion is that holding the read transaction open for this long is probably not a terrible thing.
However.... if it is, then cities() could collect the rows into a list and return that. You would trade memory and initial latency for something that would be easier on the database server itself under higher write load. If memory is a problem, you could write to a csv file, then open that and iterate over it (though that may require more work to do in a backwards-compatible way).
There's a saying, premature optimization is the root of all evil and that applies here. So the key thing is to make sure you can properly separate the logic in a way you can change it later without breaking things. So I would start by looping over the cursor unless I know that will be a problem and then if that is the case (or if it is shown to be a problem) I would explore other options, such as fetching everything from the cursor into an array of dictionaries (or tuples) and returning that, or serializing to a file and iterating over that.