1

It is apparently Pythonic to return values that can be treated as 'False' versions of the successful return type, such that if MyIterableObject: do_things() is a simple way to deal with the output whether or not it is actually there.

With generators, bool(MyGenerator) is always True even if it would have a len of 0 or something equally empty. So while I could write something like the following:

result = list(get_generator(*my_variables))
if result:
    do_stuff(result)

It seems like it defeats the benefit of having a generator in the first place.

Perhaps I'm just missing a language feature or something, but what is the pythonic language construct for explicitly indicating that work is not to be done with empty generators?

To be clear, I'd like to be able to give the user some insight as to how much work the script actually did (if any) - contextual snippet as follows:

# Python 2.7
templates = files_from_folder(path_to_folder)
result = list(get_same_sections(templates)) # returns generator
if not result:
    msg("No data to sync.")
    sys.exit()

for data in result:
    for i, tpl in zip(data, templates):
        tpl['sections'][i]['uuid'] = data[-1]

msg("{} sections found to sync up.".format(len(result)))

It works, but I think that ultimately it's a waste to change the generator into a list just to see if there's any work to do, so I assume there's a better way, yes?

EDIT: I get the sense that generators just aren't supposed to be used in this way, but I will add an example to show my reasoning.

There's a semi-popular 'helper function' in Python that you see now and again when you need to traverse a structure like a nested dict or what-have-you. Usually called getnode or getn, whenever I see it, it reads something like this:

def get_node(seq, path):
    for p in path:
        if p in seq:
            seq = seq[p]
        else:
            return ()
    return seq

So in this way, you can make it easier to deal with the results of a complicated path to data in a nested structure without always checking for None or try/except when you're not actually dealing with 'something exceptional'.

mydata = get_node(my_container, ('path', 2, 'some', 'data'))
if mydata:  # could also be "for x in mydata", etc
    do_work(mydata)
else:
    something_else()

It's looking less like this kind of syntax would (or could) exist with generators, without writing a class that handles generators in this way as has been suggested.

  • possible duplicate of [How can I get generators/iterators to evaluate as False when exhausted?](http://stackoverflow.com/questions/7976269/how-can-i-get-generators-iterators-to-evaluate-as-false-when-exhausted) – tobias_k Mar 17 '15 at 16:32
  • So basically this kind of syntax is not intended for use with generators, then, and I should change my approach –  Mar 17 '15 at 18:30

1 Answers1

0

A generator does not have a length until you've exhausted its iterations.

the only way to get whether it's got anything or not, is to exhaust it

items = list(myGenerator)

if items:
    # do something

Unless you wrote a class with attribute nonzero that internally looks at your iterations list

class MyGenerator(object):

    def __init__(self, items):
        self.items = items

    def __iter__(self):
        for i in self.items:
            yield i

    def __nonzero__(self):
        return bool(self.items)

>>> bool(MyGenerator([]))
False
>>> bool(MyGenerator([1]))
True
>>> 
Bubai
  • 270
  • 1
  • 8