How can this generator function be turned into a generator expression?

Question:

I have written a generator function that yields an infinite sequence of strings in the same fashion as the column-naming scheme in a spreadsheet application like Excel, e.g.:

'', 'A', 'B', ... 'Z', 'AA', 'AB', ... 'AZ', 'BA', ... 'ZZ', 'AAA', ...

My function works without any issues:

def __suffix_generator():
    len, gen = (0, iter(['']))

    while True:
        try:
            suffix = next(gen)
        except StopIteration:
            len += 1
            gen = itertools.product(string.ascii_uppercase, repeat=len)
            suffix = next(gen)

        yield ''.join(suffix)

However, I want to turn it into a more idiomatic version which will use only generator expressions and my best shot so far is this:

def __suffix_generator_gexp():
    from itertools import product, count
    from string import ascii_uppercase

    return (''.join(suffix) for suffix in
        (product(ascii_uppercase, repeat=len) for len in count()))

When using that generator, I get a runtime TypeError which tells me that the type of the suffix variable isn’t accepted:

TypeError: sequence item 0: expected string, tuple found

My assumption is that suffix should be a tuple containing the letters of the particular combination and that join would turn that into a string. How can I get this to work correctly, just like the first function?

Answers:

Maybe this is what you’re looking for:

map(''.join, chain.from_iterable(product(ascii_uppercase, repeat=l) for l in count(1)))

count(n) produces a sequence of numbers starting with n using step = 1, so that each number N_{t+1} = N_t + step and N_1 = n.

If you’re using Python 2.x, map will attempt to construct a list and will fail, so you can just do:

(''.join(perm) for perm in (...))

Where ... is the second argument of map from the first snippet.

Answered By: ForceBru