Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Python curious behavior
#1
Experimenting with generators and functions I tried the following example:

def myfunc(k):
    if k == 3:
        return ["A string..."]
    else:
        yield from range(k)
What is expected behavior of this function, if we call it, e.g., as follows list(myfunc(3))?
list(myfunc(3))
Output:
[]
Why does this function return an empty list? This is quite unintuitive behavior of Python, because list(["A string..."]) should return ["A string..."].

This behavior remains true not only if we are using yield from construction, e.g.

def myfunc1(k):
    if k == 3:
        return ["A string..."]
    else:
        for j in range(k):
            yield j
And we still got unintuitive result:

list(myfunc1(3))
Output:
[]
In Python 2.x, a try to define such function (myfunc1) yields SyntaxError.


We can find an explanation of this behavior in PEP255,

Quote: A generator function can also contain return statements of the form:

return

Note that an expression_list is not allowed on return statements in the body of a generator (although, of course, they may appear in the bodies of non-generator functions nested within the generator).

When a return statement is encountered, control proceeds as in any function return, executing the appropriate finally clauses (if any exist). Then a StopIteration exception is raised, signalling that the iterator is exhausted. A StopIteration exception is also raised if control flows off the end of the generator without an explicit return.

Nevertheless, when yield from has come (Python 3.3+, see PEP380), it becomes possible to use return (with values) inside generators. The essence of such behavior becomes clear from PEP380:

Quote:2. In a generator, the statement

return value

is semantically equivalent to

raise StopIteration(value)

except that, as currently, the exception cannot be caught by except clauses within the returning generator.

Even being explainable from PEPs, this issue produces very unintuitive behavior, and probably a special warning needs to be raised (e.g. SyntaxWarning or something else) when one tries to execute such construction.

What do you think about this behavior? Do Python needs to raise a special warning to users, when they try to use both return and yield/yield from in the same function/generator's body?
Reply
#2
No, because the construct is useful. You have the ability to
stop the iteration. It's not used to get an additional value out.

Return a value via return is different use case and need the try-except clause.
Almost dead, but too lazy to die: https://sourceserver.info
All humans together. We don't need politicians!
Reply
#3
(Jul-23-2019, 07:09 AM)DeaD_EyE Wrote: Return a value via return is different use case and need the try-except clause.
May be I something misunderstood, but according to docs this could not be handled via try-except "except that, as currently, the exception cannot be caught by except clauses within the returning generator.".

(Jul-23-2019, 07:09 AM)DeaD_EyE Wrote: No, because the construct is useful.
I just told about raising a warning, not an exception. This is only polite way to point user's
attention on using return and yield in the same place. Such warning passed to stdout would be informative, I think.
This warning wouldn't break any existing code.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
Exclamation Python 3.10.1 32 Windows setup Virus behavior SapG20211215 8 2,994 Dec-15-2021, 06:51 PM
Last Post: snippsat

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020