@@ -692,15 +692,14 @@ def alert(string: str, level: int):
692692
693693
694694class MoreOnReturn (Page ):
695- title = "More on the `return` statement "
695+ title = "`return` ends the function call "
696696
697697 class double_return_in_one_function (VerbatimStep ):
698698 """
699699Sometimes `return` can be a source of confusion and mistakes for new learners.
700- Let's learn more about how `return` works, how it interacts with `if` statements and `for` loops .
700+ Let's learn more about how it works .
701701
702- First let's take a look at what happens when a function contains multiple `return` statements.
703- What do you think the following code will do?
702+ Run this code:
704703
705704 __copyable__
706705 __program_indented__
@@ -712,6 +711,8 @@ class double_return_in_one_function(VerbatimStep):
712711""" , """\
713712 2
714713""" , """\
714+ [1, 2]
715+ """ , """\
715716 1
7167172
717718""" , """\
@@ -728,16 +729,18 @@ def foo():
728729
729730 class cannot_return_multiple_values (VerbatimStep ):
730731 """
731- In the case of multiple `return` statements it's first reached, first served.
732- Whichever `return` is reached first by the code is the one that gets executed.
733- Once a `return` statement is executed, the function will stop, and the rest of the code will not get executed.
734- This means that it's possible to write unreachable `return` statements like the above:
732+ Once a `return` statement is executed, the function will stop, and the rest of the code is ignored.
733+ This means that any code immediately after a `return` in the same block is *unreachable*:
735734`return 2` can *never* be reached no matter how many times we run this function!
736- Because `return 1` will always be executed first and stop the function.
737735
738- ***One, and only one `return` can be executed per function call (which will stop the execution)!***
736+ ***One, and only one `return` can be executed per function call, then execution stops.***
737+
738+ Multiple `return` statements can still be useful when used properly, e.g. in an `if-else` block:
739739
740- So multiple `return` statements can be useful only in the case of multiple branches in the code, such as an `if-else` block.
740+ if condition:
741+ return value1
742+ else:
743+ return value2
741744
742745A common mistake is to misunderstand what `return` does in `for` loops. Try the following:
743746
@@ -754,18 +757,13 @@ def double_numbers(numbers):
754757
755758 class return_ends_whole_function (VerbatimStep ):
756759 """
757- At first it may look intuitive to combine `return` with lists and `for` loops as above:
758- **"return one thing for each thing in a list"**. But it doesn't work like that!
759-
760- If you inspect the code with *Snoop* you'll see what is happening clearly:
760+ At first it may look intuitive to `return` one value for each iteration in a `for` loop.
761+ But it doesn't work like that!
762+ If you inspect the code with Snoop or Python tutor you can see that the function returns 2 in the first
763+ loop iteration and then ends immediately.
761764
762- - the call to `double_numbers` begins, and then
763- - only the first step of the `for` loop is executed (which sets up `x = 1`),
764- - after which `1 * 2 = 2` is returned and the function stops!
765- - Then `assert_equal` rightfully complains that `2 != [2, 4, 6]`.
766-
767- So we cannot use `return` to output multiple values like that.
768- Instead we can build a list by appending the doubled numbers to it, and then return the whole list:
765+ Even when there's only one `return` statement, it will get executed only once and return one value.
766+ If you want to return several values, return a list:
769767
770768 __copyable__
771769 def double_numbers(numbers):
@@ -776,7 +774,6 @@ def double_numbers(numbers):
776774
777775 assert_equal(double_numbers([1, 2, 3]), [2, 4, 6])
778776
779- Above we saw that `return` stopped a `for` loop only after the first step of the loop.
780777What happens if there are nested loops? Try the following function:
781778
782779 __copyable__
@@ -785,10 +782,10 @@ def double_numbers(numbers):
785782
786783 def program (self ):
787784 def foo ():
788- for letter in 'abcde ' :
785+ for letter in 'abc ' :
789786 for number in range (3 ):
790787 print (f"{ letter } { number } " )
791- if letter == 'c ' :
788+ if letter == 'b ' :
792789 return letter
793790
794791 foo ()
@@ -798,34 +795,26 @@ def foo():
798795 a 0
799796a 1
800797a 2
798+ """ , """\
799+ a 0
800+ a 1
801+ a 2
801802b 0
802- b 1
803- b 2
804- c 0
805803""" , """\
806804 a 0
807805a 1
808806a 2
809807b 0
810808b 1
811809b 2
812- c 0
813- c 1
814- c 2
815810""" , """\
816811 a 0
817812a 1
818813a 2
819814b 0
820- b 1
821- b 2
822815c 0
823- d 0
824- d 1
825- d 2
826- e 0
827- e 1
828- e 2
816+ c 1
817+ c 2
829818""" , """\
830819 a 0
831820a 1
@@ -836,31 +825,25 @@ def foo():
836825c 0
837826c 1
838827c 2
839- d 0
840- d 1
841- d 2
842- e 0
843- e 1
844- e 2
845828"""
846829 ]
847830
848831 class break_vs_return (VerbatimStep ):
849832 """
850- As you see `return` does not only stop the inner loop or the outer loop, but ***it stops the whole function. ***
833+ As before, `return` ***stops the whole function***, including all loops.
851834
852- Previously you learned a way to stop loops early, by using `break`. Let's compare `break` to `return` and see how they are different.
853- Change the function as follows:
854-
855- __program_indented__
835+ Previously we showed [how to stop a loop with `break`](/course/?page=UsingBreak).
836+ Change `return letter` to `break` and see what the difference is.
856837 """
857838
839+ program_in_text = False
840+
858841 def program (self ):
859842 def foo ():
860- for letter in 'abcde ' :
843+ for letter in 'abc ' :
861844 for number in range (3 ):
862845 print (f"{ letter } { number } " )
863- if letter == 'c ' :
846+ if letter == 'b ' :
864847 break
865848
866849 foo ()
@@ -870,41 +853,26 @@ def foo():
870853 a 0
871854a 1
872855a 2
873- b 0
874- b 1
875- b 2
876856""" , """\
877857 a 0
878858a 1
879859a 2
880860b 0
881- b 1
882- b 2
883- c 0
884861""" , """\
885862 a 0
886863a 1
887864a 2
888865b 0
889866b 1
890867b 2
891- c 0
892- c 1
893- c 2
894868""" , """\
895869 a 0
896870a 1
897871a 2
898872b 0
899- b 1
900- b 2
901873c 0
902- d 0
903- d 1
904- d 2
905- e 0
906- e 1
907- e 2
874+ c 1
875+ c 2
908876""" , """\
909877 a 0
910878a 1
@@ -915,21 +883,15 @@ def foo():
915883c 0
916884c 1
917885c 2
918- d 0
919- d 1
920- d 2
921- e 0
922- e 1
923- e 2
924886"""
925887 ]
926888
927889 final_text = """
928- Unlike `return`, `break` only stops the loop in which it is used.
929- In this case only the inner loop `for number in range(3):` is stopped by `break`:
890+ Unlike `return`, `break` only stops the innermost loop in which it is used, in this case `for number in range(3):`.
891+ Here's exactly what happens:
930892
931- - For `letter = c `, the line `print(f"{letter} {number}")` is executed only for `number = 0`,
893+ - For `letter = b `, the line `print(f"{letter} {number}")` is executed only for `number = 0`,
932894- then the inner loop is stopped by `break`, but
933- - the outer loop continues its execution, moving on to the next letter `d`, and then `e`,
934- - the inner loop is still executed for letters `d` and `e` since they do not trigger the `break` statement.
935- """
895+ - the outer loop continues its execution, moving on to the next letter `c`
896+ - which is executed in full since it does not trigger the `break` statement.
897+ """
0 commit comments