|
| 1 | +<p>This rule raises an issue when a <code>return</code> statement with a value is used inside a generator function (a function that uses |
| 2 | +<code>yield</code>).</p> |
1 | 3 | <h2>Why is this an issue?</h2> |
2 | | -<p>Functions that use <code>yield</code> are known as "generators". Before Python 3.3, generators cannot <code>return</code> values. Similarly, |
3 | | -functions that use <code>return</code> cannot use <code>yield</code>. Doing so will cause a <code>SyntaxError</code>.</p> |
4 | | -<p>Either upgrade your version of Python to a version >= 3.3, or don’t use both return and yield in a function.</p> |
5 | | -<h3>Noncompliant code example</h3> |
6 | | -<pre> |
7 | | -def adder(n): |
8 | | - num = 0 |
9 | | - while num < n: |
10 | | - yield num |
11 | | - num += 1 |
12 | | - return num #Noncompliant |
| 4 | +<p>When a generator function uses <code>return</code> with a value, the value is not sent to the caller like a normal function return. Instead, it is |
| 5 | +silently attached to the <code>StopIteration</code> exception’s <code>value</code> attribute. Most callers iterate generators with a <code>for</code> |
| 6 | +loop, which swallows <code>StopIteration</code> automatically and discards the returned value entirely. This makes the <code>return</code> value |
| 7 | +effectively invisible and can lead to subtle bugs where developers expect the value to be accessible but it never reaches the calling code.</p> |
| 8 | +<p>A bare <code>return</code> (without a value) in a generator is fine — it simply ends the generator’s execution early, similar to how |
| 9 | +<code>return</code> works in a regular function.</p> |
| 10 | +<h2>How to fix it</h2> |
| 11 | +<h3>Code examples</h3> |
| 12 | +<h4>Noncompliant code example</h4> |
| 13 | +<pre data-diff-id="1" data-diff-type="noncompliant"> |
| 14 | +def counter(n): |
| 15 | + num = 0 |
| 16 | + while num < n: |
| 17 | + yield num |
| 18 | + num += 1 |
| 19 | + return num # Noncompliant: return with a value in a generator |
13 | 20 | </pre> |
| 21 | +<h4>Compliant solution</h4> |
| 22 | +<pre data-diff-id="1" data-diff-type="compliant"> |
| 23 | +def counter(n): |
| 24 | + num = 0 |
| 25 | + while num < n: |
| 26 | + yield num |
| 27 | + num += 1 |
| 28 | + return # Compliant: bare return for early exit is fine |
| 29 | +</pre> |
| 30 | +<h2>Resources</h2> |
| 31 | +<h3>Documentation</h3> |
| 32 | +<ul> |
| 33 | + <li><a href="https://peps.python.org/pep-0380/">PEP 380 - Syntax for Delegating to a Subgenerator</a> - introduces <code>return</code> in |
| 34 | + generators</li> |
| 35 | + <li><a href="https://docs.python.org/3/reference/simple_stmts.html#the-return-statement">Python Documentation - The return statement</a></li> |
| 36 | +</ul> |
14 | 37 |
|
0 commit comments