{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "d4a53758",
   "metadata": {},
   "source": [
    "# 函数进阶\n",
    "\n",
    "## 函数的参数传递"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5e628c6f",
   "metadata": {},
   "source": [
    "Python的函数采用了引用传递的方法,即传递参数时,并不复制一份参数的内容,而是将参数的引用传递给函数。\n",
    "\n",
    "例如:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "003fa7c4",
   "metadata": {},
   "outputs": [],
   "source": [
    "def f(x):\n",
    "    return id(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "fef96338",
   "metadata": {},
   "outputs": [],
   "source": [
    "a = 1.2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "bedf2afb",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4485901776"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "id(a)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "a10c5f49",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4485901776"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "f(a)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f66b0b35",
   "metadata": {},
   "source": [
    "函数`f(a)`的返回值与a的内存地址是一致的。这表示,当函数`f()`被调用时,Python并没有将a的值复制一份传给参数x,而是让参数x与a共享了同一块内存。所以a和x是同一个对象。\n",
    "\n",
    "对于列表有类似的结论:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "40de4e9c",
   "metadata": {},
   "outputs": [],
   "source": [
    "b = [1, 2, 3]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "209b58ca",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4486278400"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "f(b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "3ba2ebff",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4486278400"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "id(b)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "255f72f0",
   "metadata": {},
   "source": [
    "共享同一个对象的机制意味着,可以在函数中修改传入参数的值。例如:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "2fc37814",
   "metadata": {},
   "outputs": [],
   "source": [
    "def mod_f(x):\n",
    "    x[0] = 999\n",
    "    return x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "426c51d7",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 2, 3]"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "1b77b973",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[999, 2, 3]"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mod_f(b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "4f014365",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[999, 2, 3]"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cd196d65",
   "metadata": {},
   "source": [
    "不过,如果在函数中给参数x赋了一个新值,如另一个列表,根据赋值机制,虽然x指向一个新的内存位置,但原来的变量不会改变:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "68dce8b7",
   "metadata": {},
   "outputs": [],
   "source": [
    "def no_mod_f(x):\n",
    "    x = [4, 5, 6]\n",
    "    return x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "7b474ccc",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[4, 5, 6]"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "no_mod_f(b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "b3bed828",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[999, 2, 3]"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e16cf62a",
   "metadata": {},
   "source": [
    "## 默认参数的传递"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "587198fd",
   "metadata": {},
   "source": [
    "有默认参数的情况下,Python会在函数定义时,预先为默认参数分配内存,以避免每次生成一个额外的默认参数。这样做能够节约一定的空间,不过也可能会得到一些与直觉不符的结果。例如:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "133b2be2",
   "metadata": {},
   "outputs": [],
   "source": [
    "def f(x = []):\n",
    "    x.append(1)\n",
    "    return x"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cc5dbb86",
   "metadata": {},
   "source": [
    "理论上说,调用 `f()` 时返回的是 `[1]`, 但事实上:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "ec4cbacd",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1]"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "f()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "ef5c79b5",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 1]"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "f()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "ca57f94d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 1, 1]"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "f()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "147f8237",
   "metadata": {},
   "source": [
    "随着函数的调用,默认参数会被一直改变。这并不是Python的bug,且这种特性可以用于缓存。如果不想要这样的特性,可以这样定义函数:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "23a441a7",
   "metadata": {},
   "outputs": [],
   "source": [
    "def f(x = None):\n",
    "    if not x:\n",
    "        x = []    \n",
    "    x.append(1)\n",
    "    return x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "bbfaae61",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1]"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "f()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "5499605d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1]"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "f()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "60aa85c8",
   "metadata": {},
   "source": [
    "## 高阶函数"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "544e2088",
   "metadata": {},
   "source": [
    "以函数作为参数,或者返回一个函数的函数都是高阶函数。在Python中,函数也是一种基本类型的对象,例如:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "04188365",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<function max>"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "max"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "2a9115d0",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "builtin_function_or_method"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "type(max)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "05b2407d",
   "metadata": {},
   "source": [
    "对象性意味着可以对函数进行以下操作:\n",
    "- 将函数作为参数传给另一个函数。\n",
    "- 将函数名赋值给另一个变量。\n",
    "- 将函数作为另一个函数的返回值。\n",
    "\n",
    "例如:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "97429c11",
   "metadata": {},
   "outputs": [],
   "source": [
    "def square(x):\n",
    "    \"\"\"Square of x.\"\"\"\n",
    "    return x*x\n",
    "\n",
    "def cube(x):\n",
    "    \"\"\"Cube of x.\"\"\"\n",
    "    return x*x*x"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9fdec6e5",
   "metadata": {},
   "source": [
    "可以将它们作为字典的值:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "71a6e5c6",
   "metadata": {},
   "outputs": [],
   "source": [
    "funcs = {\n",
    "    'square': square,\n",
    "    'cube': cube,\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "44fd6211",
   "metadata": {},
   "source": [
    "调用这些函数:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "52beca84",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "9"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "funcs['square'](3)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d602c33a",
   "metadata": {},
   "source": [
    "常见的高阶内置函数有 `map()` 和 `filter()`。\n",
    "```python\n",
    "map(f, sq)\n",
    "```\n",
    "将函数f作用在序列sq的每个元素上,得到结果组成的新序列。例如"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "37aadbcc",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<map at 0x10b6b0130>"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "map(square, range(5))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "57b1ab3f",
   "metadata": {},
   "source": [
    "返回的结果是一个map迭代器,可以将其转换为列表:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "dfb14a37",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[0, 1, 4, 9, 16]"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "list(map(square, range(5)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6b4c448d",
   "metadata": {},
   "source": [
    "```python\n",
    "filter(f, sq)\n",
    "```\n",
    "将函数f作用在序列sq的每个元素上,保留所有结果为`True`的元素。例如:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "f0025e81",
   "metadata": {},
   "outputs": [],
   "source": [
    "def is_even(x):\n",
    "    return x % 2 == 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "007342c0",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<filter at 0x10b6b05b0>"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "filter(is_even, range(5))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "6ab0af5b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[0, 2, 4]"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "list(filter(is_even, range(5)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d5ef5539",
   "metadata": {},
   "source": [
    "函数的返回值也可以是个函数。例如,定义一个返回函数的函数:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "eca0808b",
   "metadata": {},
   "outputs": [],
   "source": [
    "def power_func(num):\n",
    "    def func(x):\n",
    "        return x ** num\n",
    "    return func"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c9cee080",
   "metadata": {},
   "source": [
    "平方和立方函数可以使用该函数定义出来:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "372fb5ec",
   "metadata": {},
   "outputs": [],
   "source": [
    "square2 = power_func(2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "cebe177e",
   "metadata": {},
   "outputs": [],
   "source": [
    "cube2 = power_func(3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "405b8974",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "function"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "type(square2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "7d62ee4c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "100"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "square2(10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "id": "eb9af915",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "27"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "cube2(3)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b1a7f3ab",
   "metadata": {},
   "source": [
    "## Lambda表达式\n",
    "\n",
    "Python提供了Lambda表达式,简化函数的定义,来定义一些匿名函数。\n",
    "\n",
    "```python\n",
    "lambda <variables>: <expression>\n",
    "```\n",
    "\n",
    "Lambda表达式返回的是一个函数对象,接受`<variables>`作为参数,返回`<expression>`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "f68cc2d3",
   "metadata": {},
   "outputs": [],
   "source": [
    "square3 = lambda x: x ** 2\n",
    "cube3 = lambda x: x ** 3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "id": "0bc83b6e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "function"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "type(square3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "id": "e561c2d9",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "100"
      ]
     },
     "execution_count": 40,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "square3(10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "7bfd0448",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "27"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "cube3(3)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3e566e61",
   "metadata": {},
   "source": [
    "## 关键字global\n",
    "\n",
    "在Python中,函数可以直接使用外部已定义好的变量值:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "id": "7be8cb1d",
   "metadata": {},
   "outputs": [],
   "source": [
    "x = 15\n",
    "\n",
    "def print_x():\n",
    "    print(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "id": "0c885e94",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "15\n"
     ]
    }
   ],
   "source": [
    "print_x()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a234f1c7",
   "metadata": {},
   "source": [
    "如果想在函数中直接改x的值,需要加上关键字`global`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "id": "5d3e45b1",
   "metadata": {},
   "outputs": [],
   "source": [
    "x = 15\n",
    "\n",
    "def print_newx():\n",
    "    global x\n",
    "    x = 18\n",
    "    print(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "id": "97a2c48f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "18\n"
     ]
    }
   ],
   "source": [
    "print_newx()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "id": "b6fe7566",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "18"
      ]
     },
     "execution_count": 46,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a236dc2a",
   "metadata": {},
   "source": [
    "如果不加,x的值不会改变:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "id": "12449e81",
   "metadata": {},
   "outputs": [],
   "source": [
    "x = 15\n",
    "\n",
    "def print_newx():\n",
    "    x = 18\n",
    "    print(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "id": "bd43caef",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "18\n"
     ]
    }
   ],
   "source": [
    "print_newx()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "id": "d5927808",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "15"
      ]
     },
     "execution_count": 49,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "106a7a1b",
   "metadata": {},
   "source": [
    "## 递归\n",
    "\n",
    "递归是指函数在执行的过程中调用了本身,一般用于分治法。例如,阶乘函数:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "id": "b170fc70",
   "metadata": {},
   "outputs": [],
   "source": [
    "def fact(n):\n",
    "    return 1 if n == 0 else n * fact(n-1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "id": "a9c58005",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "720"
      ]
     },
     "execution_count": 51,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fact(6)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dadb8173",
   "metadata": {},
   "source": [
    "递归可以更快地实现代码,不过在效率上可能会有一定的损失。例如,斐波那契数列:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "id": "eb80c5e3",
   "metadata": {},
   "outputs": [],
   "source": [
    "def fib1(n):\n",
    "    \"\"\"Fib with recursion.\"\"\"\n",
    "    return 1 if n in (0, 1) else fib1(n-1) + fib1(n-2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "id": "32a8c66e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]"
      ]
     },
     "execution_count": 53,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "list(map(fib1, range(10)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3c88745c",
   "metadata": {},
   "source": [
    "非递归的方式的实现:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "id": "63bab4c4",
   "metadata": {},
   "outputs": [],
   "source": [
    "def fib2(n):\n",
    "    \"\"\"Fib without recursion.\"\"\"\n",
    "    a, b = 1, 1\n",
    "    for i in range(1, n+1):\n",
    "        a, b = b, a+b\n",
    "    return a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "id": "22254370",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]"
      ]
     },
     "execution_count": 55,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "list(map(fib2, range(10)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "71b560a1",
   "metadata": {},
   "source": [
    "对这两个函数的运行时间进行比较:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "id": "d5235418",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2.98 ms ± 30.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n"
     ]
    }
   ],
   "source": [
    "%timeit -n 100 fib1(20)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "id": "c442f901",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1.5 µs ± 20.1 ns per loop (mean ± std. dev. of 7 runs, 100 loops each)\n"
     ]
    }
   ],
   "source": [
    "%timeit -n 100 fib2(20)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "53d2df9f",
   "metadata": {},
   "source": [
    "可以看到,两者的效率有很大的差别,非递归版本比递归版本要快很多,原因是递归版本中存在大量的重复计算。\n",
    "\n",
    "为了减少递归中的重复,可以利用默认参数实现缓存机制:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "id": "a0aeb950",
   "metadata": {},
   "outputs": [],
   "source": [
    "def fib3(n, cache={0: 1, 1: 1}):\n",
    "    \"\"\"Fib with recursion and caching.\"\"\"\n",
    "    try:\n",
    "        return cache[n]\n",
    "    except KeyError:\n",
    "        cache[n] = fib3(n-1) + fib3(n-2)\n",
    "        return cache[n]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "id": "e6f6e4f6",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]"
      ]
     },
     "execution_count": 59,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "list(map(fib3, range(10)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "id": "142964a0",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "158 ns ± 49.9 ns per loop (mean ± std. dev. of 7 runs, 100 loops each)\n"
     ]
    }
   ],
   "source": [
    "%timeit -n 100 fib3(20)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "380e5024",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}