Generator

Generator is helpful when we want to do a lazy optimisation.

For example:

def groupTuple(n):
    result = []
    for j in range(n):
        for i in range(j):
            result.append((i, j))
    return result

if __name__ == "__main__":
    for result in groupTuple(3):
        print(result)

This function in here will put the the tuples inside the list of result. Doing this we need at least O(n) memory.

Lazy optimisation

Instead of storing into result and print it out in the end. We can only print and calculate whenever we needed:

def lazy_groupTuple(n):
    for j in range(n):
        for i in range(j):
            yield (i,j)
            
if __name__ == "__main__":
    for result in lazy_groupTuple(3):
        print(result)

Doing this will reduce our storage to O(1)