{"id":"recursion-calling-itself","slug":"calling-itself","title":"A function that calls itself","text":"You know that a function can call another function. A function can also call itself. That's called **recursion**, and it's another way to repeat something.\n\nJust as a `while` loop needs a way out, a recursive function needs a way to stop. This one calls itself every time, so it never ends on its own:\n\n```python\ndef count_up(n):\n    count_up(n + 1)\n\n\ncount_up(1)\n```\n\n```crash\nTraceback (most recent call last):\n  File \"main.py\", line 5, in <module>\n    count_up(1)\n    ~~~~~~~~^^^\n  File \"main.py\", line 2, in count_up\n    count_up(n + 1)\n    ~~~~~~~~^^^^^^^\n  File \"main.py\", line 2, in count_up\n    count_up(n + 1)\n    ~~~~~~~~^^^^^^^\n  File \"main.py\", line 2, in count_up\n    count_up(n + 1)\n    ~~~~~~~~^^^^^^^\n  [Previous line repeated 996 more times]\nRecursionError: maximum recursion depth exceeded\n```\n\nEvery call starts a new call before it has finished. Python keeps track of all the unfinished calls, and when there are about a thousand of them, it gives up with a `RecursionError`. The traceback shows the same line a few times and then says how many more times it was repeated.\n\n### The base case\n\nA recursive function that works has two parts:\n\n- A **base case**: a situation so simple that the function handles it without calling itself. That's where the calls stop.\n- A **recursive case**: the function calls itself with a smaller problem, one step closer to the base case.\n\n```python\ndef countdown(n):\n    if n == 0:\n        print(\"Liftoff!\")\n    else:\n        print(n)\n        countdown(n - 1)\n\n\ncountdown(3)\n```\n\n```output\n3\n2\n1\nLiftoff!\n```\n\n`countdown(3)` prints 3 and calls `countdown(2)`, which prints 2 and calls `countdown(1)`, which prints 1 and calls `countdown(0)`. That's the base case: it prints `Liftoff!` and doesn't call itself, so the calls end there. Each call has its own `n`: while `countdown(2)` runs, the `n` of `countdown(3)` is still 3.\n\nEach call makes `n` one smaller, so it gets to 0 sooner or later. But what about `countdown(-1)`? Then `n` goes -2, -3, -4 and never hits 0, and the program ends in a `RecursionError`. The base case `n <= 0` would catch that too.\n\n### Recursion that changes a list\n\nA recursive function can also change a list. None of the calls below gets a list of its own: in every call, `numbers` is another name for `powers`, the one list of the main program, because a function gets the list itself and not a copy (part 5). So each call finds the numbers that the calls before it appended:\n\n```python\ndef keep_doubling(numbers, limit):\n    if numbers[-1] * 2 <= limit:\n        numbers.append(numbers[-1] * 2)\n        keep_doubling(numbers, limit)\n\n\npowers = [1]\nkeep_doubling(powers, 100)\nprint(powers)\n```\n\n```output\n[1, 2, 4, 8, 16, 32, 64]\n```\n\nHere the base case is hidden: when the next number would go over the limit, the condition is false and the function ends without calling itself. A `while` loop does the same job:\n\n```python\ndef keep_doubling(numbers, limit):\n    while numbers[-1] * 2 <= limit:\n        numbers.append(numbers[-1] * 2)\n```\n\nA solution that repeats with a loop is called **iterative**, and one where a function calls itself **recursive**. Here the iterative version is shorter and easier to follow, so it's the better choice. Recursion earns its place when a problem breaks into smaller problems of the same kind: the factorial and binary search in the next steps, and the trees of the next module.\n","task":"Fill in the blanks: the base case's condition, and the argument of the recursive call. The program should print:\n\n```\n4\n3\n2\n1\nGo!\n```\n","kind":"fill","seed":"def countdown(n):\n    if n [[<= 0‖== 0‖< 1]]:\n        print(\"Go!\")\n    else:\n        print(n)\n        countdown([[n - 1]])\n\n\ncountdown(4)\n","solution":"def countdown(n):\n    if n <= 0:\n        print(\"Go!\")\n    else:\n        print(n)\n        countdown(n - 1)\n\n\ncountdown(4)\n","hints":["The base case is when the countdown has reached zero: `n <= 0` (or `n == 0`).","The recursive call gets a number one smaller, so the countdown gets closer to zero: `n - 1`."],"tests":[{"name":"Output","stdin":"","expect":"4\n3\n2\n1\nGo!","hidden":false}],"require":[],"forbid":[],"more":[{"task":"What does this program print? Type each line it prints.\n","kind":"predict","seed":"def show(n):\n    if n > 0:\n        print(n)\n        show(n - 2)\n\n\nshow(7)\n","solution":"def show(n):\n    if n > 0:\n        print(n)\n        show(n - 2)\n\n\nshow(7)\n","hints":["Each call prints its `n` and then calls the function with a number two smaller.","The calls stop when `n > 0` is false. Does `n` ever reach 0, or does it skip past it?"],"tests":[{"name":"Output","stdin":"","expect":"7\n5\n3\n1","hidden":false}],"require":[],"forbid":[],"lines":["7","5","3","1"]},{"task":"A sensor writes its readings into a list, and when it fails, it writes negative numbers. Write a recursive function `trim_end(readings)` that removes the negative numbers from the end of the list, so that the list ends with a number that is 0 or more. Negative numbers earlier in the list stay where they are, and a list of only negative numbers ends up empty. The function changes the list it gets and returns nothing. Use recursion, not a loop.\n\nFor example, this program:\n\n```python\nreadings = [12, -3, 7, 0, -1, -5]\ntrim_end(readings)\nprint(readings)\n```\n\nprints:\n\n```\n[12, -3, 7, 0]\n```\n","kind":"code","seed":"def trim_end(readings):\n    pass\n\n\nif __name__ == \"__main__\":\n    readings = [12, -3, 7, 0, -1, -5]\n    trim_end(readings)\n    print(readings)\n","solution":"def trim_end(readings):\n    if len(readings) > 0 and readings[-1] < 0:\n        readings.pop()\n        trim_end(readings)\n\n\nif __name__ == \"__main__\":\n    readings = [12, -3, 7, 0, -1, -5]\n    trim_end(readings)\n    print(readings)\n","hints":["There's something to do only when the last number, `readings[-1]`, is negative. `pop()` removes the last item of a list.","An empty list has no last item, so check `len(readings) > 0` first and join the two conditions with `and`: then `readings[-1]` is only looked at when the list has items.","After removing one number, let the function call itself to deal with the new last number. When the last number isn't negative, or the list is empty, the function does nothing: that's the base case."],"tests":[{"name":"Test 1","stdin":"","call":"readings = [12, -3, 7, 0, -1, -5]\ntrim_end(readings)\nprint(readings)\n","expect":"[12, -3, 7, 0]","hidden":false},{"name":"Test 2","stdin":"","call":"readings = [-2, -4]\ntrim_end(readings)\nprint(readings)\n","expect":"[]","hidden":true},{"name":"Test 3","stdin":"","call":"readings = []\ntrim_end(readings)\nprint(readings)\n","expect":"[]","hidden":true},{"name":"Test 4","stdin":"","call":"readings = [3, -1, 4]\ntrim_end(readings)\nprint(readings)\n","expect":"[3, -1, 4]","hidden":true},{"name":"Test 5","stdin":"","call":"readings = [5, 0, -2]\ntrim_end(readings)\nprint(readings)\n","expect":"[5, 0]","hidden":true}],"require":[{"pattern":"def trim_end\\b[^\\n]*\\n(?:[ \\t]*\\n|[ \\t]+[^\\n]*\\n)*?[ \\t]+[^\\n]*\\btrim_end\\s*\\(","message":"Make `trim_end` call itself inside its own body."}],"forbid":[{"pattern":"\\b(?:while|for)\\b","message":"Use recursion instead of a loop."}]}]}