Copied!
Happy Pythoning!

In this lesson, you’ll learn about the advanced generators methods of `.send()`, `.throw()`, and `.close()`. To practice with these new methods, you’re going to build a program that can make use of each of the three methods.

As you follow along in the lesson, you’ll learn that `yield` is an expression, rather than a statement. You can use it as a statement, but you can manipulate a yielded value. You are allowed to `.send()` a new value back to the generator. You’ll also handle exceptions with `.throw()` and stop the generator after a given amount of digits with `.close()`.

zell0ss

Great tutorial,

A curiosity I seem unable to answer, why the palindromes found are:

11 111 1111 10101

11 101 1001 10001

At first I thought that was because we send 10 ** (digits) and it got incremented just afterwards so it will skip 101, 1001, … I changed it to 10 ** (digits) -1 but got the same result.

I know it is not strictly generator related, but nonetheless, Im curious!

zell0ss

Ahhh! forgot markdown: i mean we send `10 ** (digits)` and I changed to `10 ** (digits) -1`

Pierre

Goodness, that was wonderfully clear. It’s the first time I’ve been able to follow a presentation of generators. Thanks, Christian.

My only regret is you didn’t walk through the calling of a generator comprehension as you did a generator function in video 2. I’ll do so myself expecting they are called in the same manner.

Thanks, again

Howard M Sherman

Something doesn’t make sense to me in the sequence of palindromes being printed. Using your `.throw()` method sample, the output is:

``````11
111
1111
10101
Traceback (most recent call last):
.
.
ValueError: We don't like large palindromes
``````

Following the logic of your code, I would think the sequence of palindromes printed would be:

``````11
101
1001
10001
``````

Since the for loop is running `pal_gen.send(10 ** (digits))`, it would seem to me first palindrome following each `10 ** (digits)` sent would be that number + 1. Am I missing something?

Eron

It’s nice, but I have a question: why don’t we raise an exception directly in test code or in the infinite_palindrome method instead using throw() method?

Imtiaz

I do not understand this statement in “infinite_palindromes” function. `i = (yield num)` num is yielding but yet in parentheses (generator expression)

Also, this whole loop is unclear to me. Can anyone explain or give me some pointer.

``````while True:
if is_palindrome(num):
i = (yield num)
if i is not None:
num = i
num += 1
``````

el-jose

Hey everyone

Same as @zell0ss and @Howard M Sherman I didn’t understand why the code was not printing 11, 101, 1001 … so, doing some research and debugging this is what I found:

1. In the first loop, you’re yielding an object (num = 11), then you save the “result” of that yield operation, which is None (i == None), and then you yield that None. In the second loop, you yield an object (num = 101), then you save the “result” of that yield operation, but in this case you NEVER yield that result, so None does not appear in the output. in the third loop (num = 111) is happening the same that happens in the first one, this is, yielding the None result.
2. the way that I found to fix it is to add another yield statement. this yield statement is invoked only in the even loops, in order to yield the “None” result and print the correct number:
``````def infinite_palindromes():
"""
Palindromes generator
"""
num = 0
while True:
if is_palindrome(num):
i = yield num
yield num # this is the new line
if i is not None:
num = i
num += 1
``````

also I added a time delay in the for cycle to actually see the result because for some reason, works faster than the original code:

``````for i in gen_pal:
time.sleep(1)
print(i)
digits = len(str(i))
gen_pal.send(10 ** (digits))
``````

Hopefully all this explanation can be helpful :)

loopology

It’s frustrating when it takes longer to understand the example than the concept being explained.

Why are we skipping to the next longer palindrome when we found the first for the current digit count? After 121 there are many more three-digit palindromes before we reach 1000. Why are we skipping them? Do we only want the first palindrome per digit count? If so, this deserves explicit mention.

Also, it’d be worth defining what exactly comprises a palindrome: According to the usual definition (“reads the same forward as backwards”), a one-digit number is a palindrome. This definition has the advantage to lend itself to recursive algorithms to detect palindromes.

Finally, these types of constructs:

``````    if num == reversed_num:
return True
else:
return False
``````

are more succinct and easier to read:

``````    return num == reversed_num
``````

Jon David

My inner Bash programmer asserted itself and I rewrote `is_palindrome` as:

``````is_palindrome = lambda val: int(''.join(reversed([x for x in str(val)]))) == val
``````

This does count single digits as palindromes, but I can’t help liking it more :))

Jon David

I just got an even better lambda from the realpython slack group!

``````is_palindrome = lambda x: str(x) == str(x)[::-1]
``````

elegance += 20

Konstantinos

I cannot understand why `i = (yield num)` for “num = 101” or “num = 1001”, sets `i` to `None`. It also seems that for these numbers, `yield` does not return to the generator consumer process. It is not explained at all in the course, though it’s critical to understand generators.

dheerajbhosale96

I found this tutorial little difficult to grasp. Checkout this resource for easy reading and better examples

pranayteja72

hi i’m trying to return the generator expression from one function to another

``````def infinite_seq(n):
k=(num**2 for num in range(n))
print(type(k)). ->generator
return k
def calling():
r=(infinite_seq(5))
print(type(r)) ->generator
n=list(r)
print(n)
c=calling()
``````

here my question is how to view the r value in better way rather than converting it to list . note:when i’m trying to use r=next(infinite_seq(5)) it is printing 0

to join the conversation.