|
4 | 4 | "cell_type": "markdown",
|
5 | 5 | "metadata": {},
|
6 | 6 | "source": [
|
7 |
| - "# Python 作用域基础 \n", |
| 7 | + "# 1. Python 作用域基础 \n", |
8 | 8 | "在一个程序中使用变量名时,Python 创建、改变或查找变量名都是在所谓的命名空间(一个保存变量名的地方)中进行的。代码中变量名被赋值的位置决定了这个变量名能被访问到的范围。 \n",
|
9 | 9 | "\n",
|
10 | 10 | "一个函数的所有变量名都是与函数的命名空间相关联的:\n",
|
|
16 | 16 | "- 如果一个变量在一个嵌套的 def 中赋值,对于嵌套的函数来说,它是非本地的。\n",
|
17 | 17 | "- 如果在 def 之外赋值,它就是整个文件全局的。\n",
|
18 | 18 | "\n",
|
19 |
| - "## 作用域法则 \n", |
| 19 | + "## 1.1 作用域法则 \n", |
20 | 20 | "函数定义了本地作用域,模块定义的是全局作用域。\n",
|
21 | 21 | "- **内嵌的模块是全局作用域。**\n",
|
22 | 22 | "- **全局作用域的作用范围仅限于单个文件。**\n",
|
23 | 23 | "- **每次对函数的调用都创建了一个新的本地作用域。**\n",
|
24 | 24 | "- **赋值的变量名除非声明为全局变量或非本地变量,否则均为本地变量。**\n",
|
25 | 25 | "- **所有其他的变量名都可以归纳为本地、全局或者内置的。**\n",
|
26 | 26 | "\n",
|
27 |
| - "## 变量名解析:LEGB原则 \n", |
| 27 | + "## 1.2 变量名解析:LEGB原则 \n", |
28 | 28 | "对于一个 def 语句:\n",
|
29 | 29 | "- 在默认情况下,变量名赋值会创建或者改变本地变量。\n",
|
30 | 30 | "- 变量名引用分为四个作用域进行查找:首先是本地,之后是函数内,之后全局,最后是内置。\n",
|
|
46 | 46 | "\n",
|
47 | 47 | "与函数不同的是,类名不是每次调用都创建的:类对象调用生成实例,实例继承类中赋值的变量名,并将每个对象状态记录为属性。虽然 LEGB 规则是用来解析在类本身的顶层以及嵌套在其中的方法函数的顶层中使用的变量名,类本身被作用域查找跳过——它们的变量名必须是作为对象属性被获取。由于 Python 搜索包含的函数以查找引用的变量名,而不搜索包含的类,所以 LEGB 规则仍然适用于 OOP 代码。 \n",
|
48 | 48 | "\n",
|
49 |
| - "## 作用域实例 " |
| 49 | + "## 1.3 作用域实例 " |
50 | 50 | ]
|
51 | 51 | },
|
52 | 52 | {
|
|
92 | 92 | "cell_type": "markdown",
|
93 | 93 | "metadata": {},
|
94 | 94 | "source": [
|
95 |
| - "## 内置作用域 \n", |
| 95 | + "## 1.4 内置作用域 \n", |
96 | 96 | "内置作用域仅仅是一个名为 `builtins` 的内置模块,但是必须要导入 `builtins` 之后才能使用内置作用域。"
|
97 | 97 | ]
|
98 | 98 | },
|
|
406 | 406 | "cell_type": "markdown",
|
407 | 407 | "metadata": {},
|
408 | 408 | "source": [
|
409 |
| - "# global 语句 \n", |
| 409 | + "# 2. global 语句 \n", |
410 | 410 | "global 是一个命名空间的声明,它告诉 Python 函数生成一个或多个存在于整个模块内部作用域(命名空间)的全局变量名。 \n",
|
411 | 411 | "- 全局变量是位于模块文件内部的顶层的变量名。\n",
|
412 | 412 | "- 全局变量如果是在函数内被赋值的话,必须经过声明。\n",
|
|
462 | 462 | "cell_type": "markdown",
|
463 | 463 | "metadata": {},
|
464 | 464 | "source": [
|
465 |
| - "## 其他访问全局变量的方法 " |
| 465 | + "## 2.1 其他访问全局变量的方法 " |
466 | 466 | ]
|
467 | 467 | },
|
468 | 468 | {
|
|
495 | 495 | "cell_type": "markdown",
|
496 | 496 | "metadata": {},
|
497 | 497 | "source": [
|
498 |
| - "# 作用域和嵌套函数 \n", |
| 498 | + "# 3. 作用域和嵌套函数 \n", |
499 | 499 | "LEGB 查找法则中的 E 这一层包括了任意嵌套函数内部的本地作用域。 \n",
|
500 |
| - "## 嵌套作用域的细节 \n", |
| 500 | + "## 3.1 嵌套作用域的细节 \n", |
501 | 501 | "对于一个函数:\n",
|
502 | 502 | "- **一个引用**(X)首先在本地(函数内)作用域查找变量名 X;之后会在代码的语法上嵌套了的函数中的本地作用域,从内到外查找;之后查找当前的全局作用域(模块文件);最后再内置作用域内(模块 builtins)。global 声明将会直接从全局(模块文件)作用域进行搜索。\n",
|
503 | 503 | "- 默认情况下,**一个赋值**(X = value)创建或改变了变量名 X 的当前作用域。如果 X 在函数内部声明为 global,赋值将会创建或改变变量名 X 为整个模块的作用域。另一方面,如果 X 在函数内声明为 nonlocal,赋值会修改最近的嵌套函数的本地作用域中的变量名 X。\n",
|
504 | 504 | "\n",
|
505 |
| - "## 嵌套作用域举例 " |
| 505 | + "## 3.2 嵌套作用域举例 " |
506 | 506 | ]
|
507 | 507 | },
|
508 | 508 | {
|
|
577 | 577 | "cell_type": "markdown",
|
578 | 578 | "metadata": {},
|
579 | 579 | "source": [
|
580 |
| - "## 工厂函数:闭包 \n", |
| 580 | + "## 3.3 工厂函数:闭包 \n", |
581 | 581 | "函数对象记住嵌套作用域中的值,而不管这些作用域是否仍然存在于内存中。实际上,它们已经附加了内存包(即状态保留),这些内存包在创建的嵌套函数的每个副本中都是本地的,并且通常为类提供一个简单的替代方案。 \n",
|
582 | 582 | "\n",
|
583 | 583 | "**一个简单的工厂函数** \n",
|
|
768 | 768 | "cell_type": "markdown",
|
769 | 769 | "metadata": {},
|
770 | 770 | "source": [
|
771 |
| - "# nonlocal 语句 \n", |
| 771 | + "# 4. nonlocal 语句 \n", |
772 | 772 | "使用 nonlocal 语句,嵌套的 def 可以对嵌套函数中的名称进行读取和写入访问。 \n",
|
773 | 773 | "\n",
|
774 | 774 | "nonlocal 应用于一个嵌套的函数的作用域中的一个变量名,而不是所有 def 之外的全局模块作用域。在声明 nonlocal 的时候,它必须已经存在于该嵌套函数的作用域中——它们可能只存在于一个嵌套的函数中,并且不能由一个嵌套的 def 中的第一次赋值创建。 \n",
|
775 | 775 | "\n",
|
776 | 776 | "换句话说,nonlocal 即允许对嵌套的函数作用域中的名称赋值,并且把这样的名称的作用域查找限制在嵌套的 def。 \n",
|
777 | 777 | "\n",
|
778 |
| - "## nonlocal 基础 \n", |
| 778 | + "## 4.1 nonlocal 基础 \n", |
779 | 779 | "nonlocal 语句只在一个函数内有意义: "
|
780 | 780 | ]
|
781 | 781 | },
|
|
799 | 799 | "\n",
|
800 | 800 | "当执行到 nonlocal 语句的时候,nonlocal 中列出的名称必须在一个嵌套的 def 中提前定义过,否则会产生一个错误。nonlocal 名称只能出现在嵌套的 def 中,而不能在模块的全局作用域中或 def 之外的内置作用域中。 \n",
|
801 | 801 | "\n",
|
802 |
| - "## nonlocal 应用 " |
| 802 | + "## 4.2 nonlocal 应用 " |
803 | 803 | ]
|
804 | 804 | },
|
805 | 805 | {
|
|
1066 | 1066 | "cell_type": "markdown",
|
1067 | 1067 | "metadata": {},
|
1068 | 1068 | "source": [
|
1069 |
| - "# 为什么使用 nonlocal ?状态保持选项 \n", |
| 1069 | + "# 5. 为什么使用 nonlocal ?状态保持选项 \n", |
1070 | 1070 | "nonlocal 语句允许在内存中保持可变状态的多个副本,并且解决了在类无法保证的情况下的简单的状态保持。 \n",
|
1071 | 1071 | "\n",
|
1072 | 1072 | "nonlocal 只能在 Python 3.X 中工作,也有一些替代方法:使用 global 与全局共享状态;使用带属性的类;使用函数属性的状态。"
|
1073 | 1073 | ]
|
| 1074 | + }, |
| 1075 | + { |
| 1076 | + "cell_type": "code", |
| 1077 | + "execution_count": null, |
| 1078 | + "metadata": {}, |
| 1079 | + "outputs": [], |
| 1080 | + "source": [] |
1074 | 1081 | }
|
1075 | 1082 | ],
|
1076 | 1083 | "metadata": {
|
|
1089 | 1096 | "name": "python",
|
1090 | 1097 | "nbconvert_exporter": "python",
|
1091 | 1098 | "pygments_lexer": "ipython3",
|
1092 |
| - "version": "3.6.6" |
| 1099 | + "version": "3.6.5" |
1093 | 1100 | }
|
1094 | 1101 | },
|
1095 | 1102 | "nbformat": 4,
|
|
0 commit comments