简体   繁体   中英

How can I use python iterable to perform flexible search generators?

EDIT: Turns out this isn't much of a question. I managed to get this working as I more or less typed this in.

I've got an online csv table database that I query with a cgi script. The script can take several optional filter arguments, but adding a new filter means I have to double my if statements.

Ex:

records = list()
with open (csv_datafile, 'r') as data: 
    data_reader = csv.DictReader(data, fieldnames=DATA_FIELDS)
    if product is None:
        records.extend(record for record in data_reader if id_start < record['id'] <= id_end)
    else:
        records.extend(record for record in data_reader if id_start < record['id'] <= id_end and record['code'] == product)

You can see, that if I add another search criteria, this pattern falls apart because I'd have to nest redundant if's in each of the above if clauses.

Is there a way I use an iterator to do this? My thinking is along the lines of:

def data_search(iterator, **search)
    for item in iterable:
        yield_me=True
        for key in item.viewkeys() & search:
            if item[key] is not None:
                if item[key] != search[key]:
                    yeild_me=False
        if yield_me:
            yield item

Then the code to integrate would be something like:

search = dict()
if product_search:
    search['code'] = product

if vendor_search:
    search['vendor'] = vendor

records = list()
with open (csv_datafile, 'r') as data: 
    data_reader = csv.DictReader(data, fieldnames=DATA_FIELDS)
    data_reader = data_search(data_reader, **search)
    records.extend(record for record in data_reader if id_start < record['id'] <= id_end)

Should I continue on this tack, or is there a better way?

I don't think you need a generator for this. I think you're on the right track with building up your search conditions (although if you can get them passed in as name/value pairs in a dictionary that's easier to work with), but enforcing it can be simpler.

with open(csv_datafile, 'r') as data:
    data_reader = csv.DictReader(data, fieldnames=DATA_FIELDS)
    records = [record for record in data_reader if all(record.get(filter_key) == filter_value for (filter_key, filter_value) in search.iteritems()) and id_start < record['id'] <= id_end]

There are different expressions possible using filter if you prefer, and I might make a passes_search_filters helper function for legibility.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM