0

I understand what the yield keyword does. But here I found an example for yield usage which makes me frustrated:

@defer.inlineCallbacks
def doStuff():
    result = yield takesTwoSeconds()
    nextResult = yield takesTenSeconds(result * 10)
    defer.returnValue(nextResult / 10)

That is a Twisted example. Here is (as author describes) yield used for async work or something like that. I decided to test it with non-async simple code:

import random

def func():
    return random.randint(0, 10)

def foo():
    while True:
        x = yield func()
        print("'x' value is", x)

f = foo()
for i in range(0, 3):
    print(next(f))

and I get as output:

6
'x' value is None
0
'x' value is None
7

So why do I get None for yield/return function value while example by author (mentioned above) gets proper value and insert it at next expressions?

Tomerikoo
  • 18,379
  • 16
  • 47
  • 61
Army of Earth
  • 311
  • 2
  • 8
  • 1
    Well `send` something. Read that other question and its answers again. – superb rain Dec 31 '20 at 13:14
  • @superbrain did it but nothing got from it. As there is no before and after context at author example. "Well `send` something" much better. – Army of Earth Dec 31 '20 at 13:30
  • Yes, their Twisted example doesn't show the sending, but their explanatory example with its usage demonstration does. And sending is the whole point of the question. Also, [the documentation](https://docs.python.org/3/reference/expressions.html#yield-expressions) tells you about `next` and `None` and `send`. – superb rain Dec 31 '20 at 13:53
  • @superbrain it might be obvious for experienced programmers but not for newbie. But I'll mark your "become pro in Python, learn all frameworks and then ask questions" as good point for learning, thx – Army of Earth Dec 31 '20 at 13:57

1 Answers1

-1

You return/yield the result before printing.

You should rewrite the part of the code like this to print the value BEFORE yielding it:

import random

def func():
    return random.randint(0, 10)

def foo():
    while True:
        x = func()
        print("'x' value is", x)
        yield x
        
f = foo()
for i in range(0, 3):
    print(next(f))

This displays what your are expecting:

'x' value is 6
6
'x' value is 5
5
'x' value is 2
2

You should recall the yield keyword interrupt the function and return the result, then it resume where the yield took place at the next function call.

Malo
  • 1,233
  • 1
  • 8
  • 25
  • Could you comment what s wrong with this answer, thanks. – Malo Dec 31 '20 at 13:23
  • Their generator code is totally fine, they're just using it incorrectly. It seems you didn't read the linked-to question and answers, either. – superb rain Dec 31 '20 at 13:28
  • As I wrote above and under my question. I read answer and question fully twice. But because of no before context there is was hard to understand whats going on. And of course instead of userfriendly answer I got "he just hasn't eyes to read, lol, kek". Nothing new. – Army of Earth Dec 31 '20 at 13:33
  • @Malo btw, there is more important why linked author got right result. I assume `@defer.inlineCallbacks` decorator inside his implementation uses `send` method to "doStuff" function. So that is 2-side result moving: 1) `send` method from inside `defer.inlineCallbacks` transfer value to `doStuff` which then assign to `result` value and then 2) `takesTwoSeconds()` return result into `defer.inlineCallbacks`. But I'm not sure for 100% cuz of dominance of code Gods who feel unworthy write proper answers – Army of Earth Dec 31 '20 at 13:48
  • @ArmyofEarth: yes the original example is different, and the simple example you provide does not reproduce the original complex one exactly. So my friendly answer was trying to make your piece of code work and avoid the None value results.... – Malo Dec 31 '20 at 14:01