PyCourse/化名与匿名.ipynb

566 lines
13 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# 化名与匿名"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 化名"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"在 Python 中,我们可以给一个函数取个**化名**alias。\n",
"\n",
"以下的代码,我们先是定义了一个名为 `_is_leap` 的函数,而后为它另取了一个化名:"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<function __main__._is_leap(year)>"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"text/plain": [
"4379191184"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"text/plain": [
"4379191184"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"text/plain": [
"function"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"text/plain": [
"function"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from IPython.core.interactiveshell import InteractiveShell\n",
"InteractiveShell.ast_node_interactivity = \"all\"\n",
"\n",
"def _is_leap(year):\n",
" return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)\n",
"\n",
"year_leap_bool = _is_leap\n",
"year_leap_bool #<function __main__._is_leap(year)>\n",
"year_leap_bool(800) # _is_leap(800) -> True\n",
"\n",
"id(year_leap_bool) # id() 这个函数可以查询某对象的内存地址\n",
"id(_is_leap) # year_leap_bool 和 _is_leap 其实保存在同一个地址中,也就是说,它们是同一个对象。\n",
"\n",
"type(year_leap_bool)\n",
"type(_is_leap) # 它们都是 function"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"我们可以看到的是,`id(year_leap_bool)` 和 `id(_is_leap)` 的内存地址是一样的 —— 它们是同一个对象,它们都是函数。所以,当你写 `year_leap_bool = _is_leap` 的时候,相当于给 `_is_leap()` 这个函数取了个化名。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## lambda"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"写一个很短的函数可以用 `lambda` 关键字。\n",
"\n",
"下面是用 `def` 关键字写函数:"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"8"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def add(x, y):\n",
" return x + y\n",
"add(3, 5)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"下面是用 `lambda` 关键字写函数:"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"8"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"add = lambda x, y: x + y\n",
"add(3, 5)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"lambda 的语法结构如下:\n",
"\n",
"> `lambda_expr ::= \"lambda\" [parameter_list] \":\" expression`\n",
"\n",
"```python\n",
"lambda x, y: x + y\n",
"```\n",
"\n",
"先写上 `lambda` 这个关键字,其后分为两个部分,`:` 之前是参数,之后是表达式;这个表达式的值,就是这个函数的返回值。\n",
"\n",
"> **注意**`lambda` 语句中,`:` 之后有且只能有一个表达式。\n",
"\n",
"而这个函数呢,没有名字,所以被称为 “匿名函数”。\n",
"\n",
"`add = lambda x, y: x + y`\n",
"\n",
"就相当于是给一个没有名字的函数取了个名字。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## lambda 的使用场景"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"那 lambda 这种匿名函数的用处在哪里呢?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 作为某函数的返回值"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"第一个常见的用处是*作为另外一个函数的返回值*。\n",
"\n",
"让我们看看 [The Python Tutorial](https://docs.python.org/3/tutorial/controlflow.html#lambda-expressions) 中的一个例子。"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"42"
]
},
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"text/plain": [
"43"
]
},
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def make_incrementor(n):\n",
" return lambda x: x + n\n",
"\n",
"f = make_incrementor(42)\n",
"f(0)\n",
"\n",
"f(1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"这个例子乍看起来很令人迷惑。我们先看看 `f = make_incrementor(42)` 之后,`f` 究竟是什么东西:"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<function __main__.make_incrementor.<locals>.<lambda>(x)>"
]
},
"execution_count": 23,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"text/plain": [
"4428443296"
]
},
"execution_count": 23,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"text/plain": [
"4428726888"
]
},
"execution_count": 23,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def make_incrementor(n):\n",
" return lambda x: x + n\n",
"\n",
"f = make_incrementor(42)\n",
"f\n",
"\n",
"id(make_incrementor)\n",
"id(f)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"首先,要注意,`f` 并不是 `make_incrementor()` 这个函数的化名,如果是给这个函数取个化名,写法应该是:\n",
"\n",
"```python\n",
"f = make_incrementor\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"那 `f` 是什么呢?它是 `<function __main__.make_incrementor.<locals>.<lambda>(x)>`\n",
"\n",
"> * `f = make_incrementor(42)` 是将 `make_incrementor(42)` 的返回值保存到 `f` 这个变量之中;\n",
"> * 而 `make_incrementor()` 这个函数接收到 `42` 这个参数之后,返回了一个函数:`lambda x: x + 42`\n",
"> * 于是,`f` 中保存的函数是 `lambda x: x + 42`\n",
"> * 所以,`f(0)` 是向这个匿名函数传递了 `0`,而后,它返回的是 `0 + 42`。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 作为某函数的参数"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"可以拿一些可以接收函数为参数的内建函数做例子。比如,[`map()`](https://docs.python.org/3/library/functions.html#map)。\n",
"\n",
"> `map`(*function*, *iterable*, *...*)\n",
"> \n",
"> Return an iterator that applies *function* to every item of *iterable*, yielding the results. If additional *iterable* arguments are passed, *function* must take that many arguments and is applied to the items from all iterables in parallel. With multiple iterables, the iterator stops when the shortest iterable is exhausted. For cases where the function inputs are already arranged into argument tuples, see [`itertools.starmap()`](https://docs.python.org/3/library/itertools.html#itertools.starmap)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`map()` 这个函数的第一个参数,就是用来接收函数的。随后的参数,是 `iterable` —— 就是可被迭代的对象,比如,各种容器,例如:列表、元组、字典什么的。"
]
},
{
"cell_type": "code",
"execution_count": 35,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[2, 4, 6, 8, 10, 12]"
]
},
"execution_count": 35,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"text/plain": [
"[2, 4, 6, 8, 10, 12]"
]
},
"execution_count": 35,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def double_it(n):\n",
" return n * 2\n",
"\n",
"a_list = [1, 2, 3, 4, 5, 6]\n",
"\n",
"b_list = list(map(double_it, a_list))\n",
"b_list\n",
"\n",
"c_list = list(map(lambda x: x * 2, a_list))\n",
"c_list"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"显然用 `lambda` 更为简洁。另外,类似完成 `double_it(n)` 这种简单功能的函数,常常有 “用过即弃” 的必要。"
]
},
{
"cell_type": "code",
"execution_count": 60,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[{'name': 'john', 'phone': 9876},\n",
" {'name': 'mike', 'phone': 5603},\n",
" {'name': 'stan', 'phone': 6898},\n",
" {'name': 'eric', 'phone': 7898}]"
]
},
"execution_count": 60,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"text/plain": [
"['john', 'mike', 'stan', 'eric']"
]
},
"execution_count": 60,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"text/plain": [
"[9876, 5603, 6898, 7898]"
]
},
"execution_count": 60,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"phonebook = [\n",
" {\n",
" 'name': 'john',\n",
" 'phone': 9876\n",
" },\n",
" {\n",
" 'name': 'mike',\n",
" 'phone': 5603\n",
" },\n",
" {\n",
" 'name': 'stan',\n",
" 'phone': 6898\n",
" },\n",
" {\n",
" 'name': 'eric',\n",
" 'phone': 7898\n",
" }\n",
"]\n",
"\n",
"phonebook\n",
"list(map(lambda x: x['name'], phonebook))\n",
"list(map(lambda x: x['phone'], phonebook))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"可以给 map() 传递若干个可被迭代对象:"
]
},
{
"cell_type": "code",
"execution_count": 63,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[2, 12, 30]"
]
},
"execution_count": 63,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a_list = [1, 3, 5]\n",
"b_list = [2, 4, 6]\n",
"\n",
"list(map(lambda x, y: x * y, a_list, b_list))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"以上的例子都弄明白了,再去看 [The Python Tutorial](https://docs.python.org/3/tutorial/controlflow.html#lambda-expressions) 中的例子,就不会有任何疑惑了:"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')]"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')]\n",
"pairs.sort(key=lambda p: p[1])\n",
"pairs"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"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.8.2"
}
},
"nbformat": 4,
"nbformat_minor": 2
}