alphanumeric
alphanumeric

Reputation: 19329

How to use yield instead of return

The code below iterates through the numbers ranging between 1 and 5 calling forEachInRangeThisNumberLoopThreeTimes function passing it a number. The function takes a number and loops it three times appending each iteration to the numbers list which it returns at the end.

def forEachInRangeThisNumberLoopThreeTimes(number):
    numbers = []
    for each in range(number):
        for i in range(3):
            numbers.append(i)
    return numbers


result = []
for number in range(1, 5):
    print number, forEachInRangeThisNumberLoopThreeTimes(number)

Which prints:

1 [0, 1, 2]
2 [0, 1, 2, 0, 1, 2]
3 [0, 1, 2, 0, 1, 2, 0, 1, 2]
4 [0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2]

Instead of appending each number to the result variable I would like to use yield:

def forEachInRangeThisNumberLoopThreeTimes(number):
    for each in range(number):
        for i in range(3):
            yield i

Now when I execute:

for number in range(1, 5):
    result = forEachInRangeThisNumberLoopThreeTimes(number)

the result is not what I expect:

1 <generator object forEachInRangeThisNumberLoopThreeTimes at 0x104ebfaf0>
2 <generator object forEachInRangeThisNumberLoopThreeTimes at 0x104ebfaf0>
3 <generator object forEachInRangeThisNumberLoopThreeTimes at 0x104ebfaf0>
4 <generator object forEachInRangeThisNumberLoopThreeTimes at 0x104ebfaf0>

Where is the error?

Upvotes: 0

Views: 128

Answers (3)

bluesummers
bluesummers

Reputation: 12607

When using yield inside of a function, it becomes a generator, that's why you are getting these outputs.

I'll use a simpler example to explain how to use generators properly. Let's say we have the following generator:

def example_generator():
    yield 1
    yield 2 
    yield 3

Now when I'll call x = example_generator(), x will hold a generator not the value 1.

If I want to get the value 1, I would have to

x = example_generator()
first_val = next(example_generator())

Now first_val has the value 1, calling next() again, you'll get the value 2. When the generator is exhausted, you'll get a StopIteration exception

To avoid StopIteration you could just

for value in example_generator():
    print(value)

and in this case you'll get

1
2
3

and the for loop will handle the StopIteration for you.

If you are looking for getting it as a list you are basically losing the advantages of using a generator, but it could be done by

list(example_generator())

I hope this was a clear enough explanation so you could understand for yourself how to use generators in python. Happy generating!

Upvotes: 0

Zauz
Zauz

Reputation: 309

I think this is what you are looking for:

def forEachInRangeThisNumberLoopThreeTimes(number):
    for each in range(number):
        for i in range(3):
            yield i

result = []
for num in forEachInRangeThisNumberLoopThreeTimes(5):
    result.append(num)

or

result = list(forEachInRangeThisNumberLoopThreeTimes(number))

You have to treat your function like an iterable if you use yield.

Upvotes: 2

bipll
bipll

Reputation: 11940

yield designates that a function returns a generator object. It conforms to iterable interface, so if you want a strict list from it, build the list explicitly:

result = list(forEachInRangeThisNumberLoopThreeTimes(number))

or even

result = [x for x in forEachInRangeThisNumberLoopThreeTimes(number)]

Upvotes: 4

Related Questions