What's a good replacement for long list comprehensions?

I’m going to preface this by saying that it might be more clever than useful, but I’ve already started using it code and gotten kind of addicted.Sometimes you have some really long list comprehension that starts spanning multiple lines, e.g.

good_objects = [{'name': object.name, 'date': object.date} if object.name else {'name': None}                 for object in other_thing.create_objects() if object.is_good]or whatever. Obviously you can replace this withgood_objects = []for object in other_thing.create_objects():    if object.is_good:        if object.name:            good_objects.append({'name': object.name, 'date': object.date})        else:            good_objects.append({'name': None})

So that’s fine but it loses the feel of ‘atomicity’ that you got from a one liner; plus, now you have the token good_objects written three times in the process of constructing it, which is a (trivial) violation of DRY. What I’ve started doing in these situations is using a generator function (i.e. one that uses yield), plus an @inline decorator I made that calls the function in place (i.e. inline = lambda f: f()):

@inlinedef good_objects()    """You can even put a little doc string here to explain the nuances of this variable"""    for object in other_thing.create_objects():        if object.is_good:            if object.name:                yield {'name': object.name, 'date': object.date}            else:                yield {'name': None}

After this, you now have an iterator, good_object, that you can use as above. If you need a list rather than a generator (like if you need to be able to do good_object[x]) then just use @list as a decorator. I think it’s pretty sweet and elegant, if hacktastic.

@list@inlinedef good_objects()    """You can even put a little doc string here to explain the nuances of this variable"""    for object in other_thing.create_objects():        if object.is_good:            if object.name:                yield {'name': object.name, 'date': object.date}            else:                yield {'name': None}

P.s. you can also do this to make a dict by yielding pairs and adding @dict instead of list 🙂

Share

Tags

Similar Articles

The World's Most Powerful Mobile Data Collection Platform

Start a FREE 30-day CommCare trial today. No credit card required.

Get Started

Learn More

Get the latest news delivered
straight to your inbox