Skip to content

Commit c155c47

Browse files
committed
add chapter[19,20,21,22,23]
1 parent 5bca978 commit c155c47

39 files changed

+364
-0
lines changed

chapter/19_python_arguments.md

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# 参数
2+
1.参数传递的性质:
3+
4+
* 参数的传递是通过自动将对象赋值给本地变量名来实现的(自动的隐式赋值)
5+
>被传递的参数对象本身并不会被拷贝
6+
* 在函数内部的参数名赋值不会影响到实参对象,只是将变量名重新引用到另一个对象
7+
* 若实参对象为可变对象,则在函数内原地修改参数对象会影响所有的指向该实参对象的引用
8+
>可变参数实参对象对函数来说,既可以作为输入也可以作为输出
9+
>
10+
>如果想限制对可变实参对象的修改,可以创建一个可变对象的拷贝作为参数;
11+
>或者直接转换成不可变对象作为参数
12+
13+
![参数传递](../imgs/python_19_1.JPG)
14+
15+
2.默认情况下,参数匹配是通过其位置进行匹配的,从左到右一一匹配。必须精确传递和函数签名中参数名一样多的实参。
16+
17+
3.关键字参数:允许通过变量名进行匹配,而不是通过位置。其中关键字顺序可以任意。
18+
![关键字参数](../imgs/python_19_2.JPG)
19+
20+
4.默认参数:函数定义时,可以为参数设定默认值,这样允许调用时传递较少的参数。
21+
>对于默认实参,可以不用给它传入实参
22+
23+
* 默认实参后面不能跟随非默认实参。如果出现这种情况则报语法错误。
24+
![默认参数](../imgs/python_19_3.JPG)
25+
26+
5.可变参数:
27+
28+
* 函数能用特定的参数(以`*`开头),收集任意多的额外位置参数,将收集到的位置相关的参数到一个新元组中。
29+
>若出现了额外的关键字参数,则报错
30+
31+
![可变位置参数](../imgs/python_19_4.JPG)
32+
* 函数能用特定的参数(以`**`开头),收集任意多的额外关键字参数,将收集关键字相关的参数到一个新字典中。
33+
>若出现了额外的位置参数,则报错
34+
35+
![可变关键字参数](../imgs/python_19_5.JPG)
36+
37+
6.可变参数解包:
38+
39+
* 调用者可以用`*`语法将实参(如元组、列表、`set`)打散,形成位置参数
40+
* 调用者可以用`**`语法将字典实参打散,形成关键字参数
41+
>这里的`*``**`均是在函数调用中出现,而不是在函数定义中出现
42+
43+
![可变参数解包](../imgs/python_19_6.JPG)
44+
45+
7.`keyword-only`参数:在Python3中,它是一种命名参数,出现在`*`参数之后,在`**`参数之前。所有的`keyword-only`参数必须使用关键字语法传递。
46+
>如果不这么做,则没有办法传递该实参
47+
48+
![keyword-only参数](../imgs/python_19_7.JPG)
49+
50+
8.函数调用时,位置参数与关键字参数可以组合
51+
52+
* 不能为同一个形参同时指定位置实参与关键字实参
53+
* 任何关键字实参必须位于任何位置实参之后
54+
![位置实参与关键字实参的组合](../imgs/python_19_8.JPG)
55+
56+
9.函数定义时的参数类型顺序:
57+
58+
```
59+
def func(a,b,c='c',*d,e,f='f',**g):
60+
pass
61+
# a,b:为一般参数
62+
# c:指定了默认实参
63+
# d:为可变位置参数
64+
# e,f:为 keyword-only参数,其中f指定了默认参数
65+
# g:为可变关键字参数
66+
```
67+
* 调用时必须先赋值形参`c`,才能进入`d`。无法跳过`c`去赋值`d`
68+
* `e,f,g`调用时必须都是关键字实参
69+
70+
10.函数调用时实参类型顺序:
71+
72+
```
73+
func('a','b',e='e',*seq,**dic)
74+
#seq是一个序列,它解包之后优先覆盖c,剩下的再收集成元组传给d
75+
#dic是一个字典,它解包之后优先考虑e,f,剩下的在收集成字典传递给g
76+
#e='e'这个关键字实参也可以位于'b'之后的任何位置
77+
#关键字实参必须位于位置实参之后
78+
```
79+
![函数定义与调用时参数匹配顺序](../imgs/python_19_9.JPG)
80+
81+
* 通过位置分配位置参数
82+
* 通过匹配变量名在分配关键字参数
83+
* 额外的非关键字参数分配到 `d`引用的元组中
84+
* 额外的关键字参数分配到`g`引用的字典中
85+
* 默认值分配给剩下未赋值的参数
86+
87+
Python最后检测确保每一个参数只传入了一个值
88+
89+
11.定义函数时,形参列表中`*`可以单独出现。此时函数并不表示接受一个可变长度的实参列表,而是表示`*`后面的所有实参必须作为关键字实参传入:
90+
>并不能用`**``*`一样单独出现在函数定义中。
91+
92+
![*定义的keyword-only参数](../imgs/python_19_10.JPG)
93+
94+
95+

chapter/20_python_function_more.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# 函数的高级特性
2+
1.在Python中,函数的递归通常比`for`循环要慢而且空间消耗大,但是递归的优点是可以遍历任意形状的结构。
3+
4+
2.Python函数是对象,自身存储在内存块中,它可以自由地传递与引用。
5+
6+
* 函数对象支持一个特殊操作:有括号`()`以及参数列表执行调用行为
7+
* 我们可以通用地检查函数对象的某些属性:如`.__name__`属性、`.__code__`属性
8+
* 可以向函数对象附加任意的用户自定义属性,如`func.count=0`。这样的属性可以用来直接将状态信息附加到函数对象上
9+
* Python3中,可以给函数对象附加注解。注解不作任何事情,而且注解是可选的,它被附加在函数对象的`.__annotaions__`属性中。注解的格式为:
10+
11+
```
12+
def func(a:'a',b:(1,10),c:float) -> int:
13+
return a+b+c
14+
```
15+
* 注解分两种:参数注解紧随形参名字的冒号`:`之后;返回值注解紧随参数列表的`->`之后
16+
* 当出现注解时,Python将它们收集到字典中并附加到`.__annotations__`属性中
17+
* 注解可以与默认值同时出现,此时形参形式为`c:float=4.0`
18+
* 注解只有在`def`中有效,在`lambda`表达式中无效
19+
20+
![函数对象](../imgs/python_20_1.JPG)
21+
22+
3.匿名函数:`lambda`表达式
23+
`lambda`表达式创建了一个函数对象,它返回该函数对象而不是将其赋值给一个变量名。
24+
创建`lambda`表达式的语法为:
25+
26+
```
27+
labda arg1,arg2,...argN: expression using args
28+
```
29+
* `lambda`表达式是个表达式而不是语句,它能出现在不允许`def`出现的某些地方,比如参数中
30+
* `lambda`表达式返回一个值(一个新的函数对象),可以将它手动赋值给一个变量名
31+
>`def`总是将一个新的函数对象自动赋值给一个变量名(函数名)
32+
33+
* `lambda`的主体是一个单一的表达式,而不是一个代码块。因此`lambda`通常比`def`功能简单
34+
>`lambda`内部甚至不能使用`if`语句
35+
* `lambda`主体中表达式的值就是调用时的返回值,不需要显式`return`
36+
* `lambda`表达式也能使用默认实参
37+
* `lambda`表达式主体中遵循`def`内一样的名字作用域查找法则
38+
![lambda表达式](../imgs/python_20_2.JPG)
39+
40+
4.出于可读性要求,最好不要嵌套使用`lambda`表达式
41+
42+
5.`lambda`表达式应用于`map()``filter()``reduce()`等函数中较多
43+
44+
6.Python是静态检测局部变量的:
45+
46+
```
47+
x='global'
48+
def func():
49+
print(x)
50+
x=3
51+
```
52+
编译时,Python看到了赋值语句`x=3`,因此决定了在函数内的任何地方,`x`都是本地变量。但是`print(x)`时赋值语句并未发生,此时即使全局中有全局的`x`,也会报错。
53+
54+
* 任何在函数体内的赋值、`import`,嵌套`def`,嵌套类等都受这种行为影响
55+
>即只要有局部变量的定义,无论在函数内哪个地方,其作用域都是本局部作用域全域
56+
57+
![局部作用域的全域效果](../imgs/python_20_3.JPG)
58+
59+
7.Python在内部会将每个默认实参保存成对应的对象,附加在这个函数本身。在不同的函数调用期间,这些默认实参会保存同一个对象。因此对于可变对象作为默认实参注意保持警惕。
60+
![可变的默认实参](../imgs/python_20_4.JPG)
61+
62+

chapter/21_python_module.md

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# 模块
2+
1.从实际角度,模块对应Python程序文件(或者用外部语言如C|C#编写的扩展)。从逻辑上看,模块是最高级别的程序组织单元
3+
4+
* 每个Python程序文件都是一个模块
5+
* 模块导入另一个模块后,可以直接使用被导模块定义的全局变量名
6+
![模块](../imgs/python_21_1.JPG)
7+
8+
2.Python程序是作为一个主体的、顶层文件来构造,配合零个或者多个支持的模块文件
9+
10+
3.Python自带了很多模块,称为标准链接库。他们提供了很多常用功能
11+
12+
4.导入模块用`import`。其通用格式为`import modname`。其中`modname`为模块名,它没有文件后缀名`.py`,也没有文件路径名。
13+
导入并非是C语言的`#include`。导入其实是运行时的运算。程序首次导入一个模块时,执行三个步骤:
14+
15+
* 找到模块文件
16+
* 编译成字节码(即`.pyc`文件)。如果字节码文件不存在或者字节码文件比源代码文件旧,
17+
则执行该步骤。否则跳过该步骤直接加载字节码
18+
* 执行模块代码来创建其定义的对象
19+
20+
在这之后导入相同模块时,会跳过这三步而只是提取内存中已经加载的模块对象。
21+
> 从内部看,Python将加载的模块存储到一个名为`sys.modules`的字典中,键就是模块名字符串。在每次导入模块开始时都检查这个字典,若模块不存在则执行上述三步。
22+
23+
![模块导入过程](../imgs/python_21_2.JPG)
24+
25+
5.当文件`import`时,会进行编译产生字节码文件`.pyc`,因此只有被导入文件才会在机器上留下`.pyc`文件。顶层文件的字节码在内部使用后就丢弃了,并未保留下来。
26+
> 顶层文件通常设计成直接执行,而不是被导入的
27+
28+
6.Python模块文件搜索路径:
29+
30+
* 程序主目录
31+
* 环境变量`PYTHONPATH`指定的目录
32+
* 标准链接库目录(这个一般不动它)
33+
* 任何`.pth`文件的内容,其中`.path`文件在前三者中查找到的。
34+
>Python会将每个`.pth`文件的每行目录从头到尾添加到`sys.path`列表的最后
35+
>(在此期间Python会过滤`.pth`文件中目录列表中重复的和不存在的目录)
36+
37+
以上四者优先级从高到低。这四部分组合起来就是`sys.path`列表的内容
38+
![sys.path](../imgs/python_21_3.JPG)
39+
40+
7.`sys.path`列表就是模块的搜索路径。Python在程序启动时配置它,自动将顶级文件的主目录(或代表当前工作目录的一个空字符串)、环境变量`PYTHONPATH`指定的目录、标准库目录以及已创建的任何`.pth`文件的内容合并
41+
42+
* 模块搜索时,从左到右搜索`sys.path`,直到第一次找到要`import`的文件
43+
44+
8.`import`模块时,省略文件后缀名因为模块可能是`.py`文件、`.pyc`文件,或者扩展的C模块等。
45+
46+
9.创建模块:任何保存为`.py`文件的文件均被自动认为是Python模块。所有该模块顶层指定的变量均为模块属性。
47+
> 可执行但不会被导入的顶层文件不必保存为.py文件
48+
49+
* 因为模块名在Python中会变成变量名,因此模块名必须遵守普通变量名的命名规则
50+
51+
10.`import``from`语句:
52+
53+
* `import`使得一个变量名引用整个模块对象:`import module1`
54+
* `from`将一个变量名赋值给另一个模块中同名的对象:`from module1 import printer`。在本模块内`printer`名字引用了`module1.printer`对象
55+
* `from *`语句将多个变量名赋值给了另一个模块中同名的对象:`from module1 import *`。在本模块内,所有`module1.name`对象赋值给了`name`变量名
56+
![import与from语句](../imgs/python_21_4.JPG)
57+
58+
有几点需要注意:
59+
60+
* `from`语句首先与`import`一样导入模块文件。但它多了一步:定义一个或多个变量名指向被导入模块中的同名对象
61+
* `from``import`都是隐性赋值语句
62+
* `from``import`对本模块的命名空间影响不同:`from`会在命名空间中引入`from import`的变量名而不会引入模块名,
63+
`import`会在命名空间中引入模块名
64+
![import与from语句](../imgs/python_21_4_dict.JPG)
65+
* `from``import``def`一样是可执行语句,而不是编译器声明
66+
* 当出现交叉导入时,可以使用`import` ,用`from`可能出现死锁的问题:`modA`需要`from import` `modB`的变量
67+
,而此时`modB`也在`from import` `modA`的变量
68+
![import与from语句](../imgs/python_21_4_cross_import.JPG)
69+
70+
11.要修改被导入的全局变量,必须用`import`,然后用模块名的属性修改它;不能用以`from`隐式创建的变量名来修改。
71+
![修改模块属性](../imgs/python_21_5.JPG)
72+
73+
12.用`from`时,被导入模块对象并没有赋值给变量名:
74+
75+
* `import module1`:`module1`既是模块名,也是一个变量名(引用被导入模块对象)
76+
* `from module1 import func``module1`仅仅是模块名,而不是变量名
77+
![模块名与变量名](../imgs/python_21_6.JPG)
78+
79+
13.`from`语句陷阱:
80+
81+
* `from`语句可能破坏命名空间
82+
* `from`后跟随`reload`时,`from`导入的变量名还是原始的对象
83+
84+
14.模块的命名空间可以通过属性`.__dict__`或者`dir(modname)`来获取
85+
86+
* 在Python内部,模块命名空间是作为字典对象存储的
87+
* 我们在模块文件中赋值的变量名在Python内部称为命名空间字典的键
88+
![模块命名空间](../imgs/python_21_7.JPG)
89+
90+
15.一个模块内无法使用其他模块内的变量,除非明确地进行了导入操作
91+
92+
17.重载函数`reload()`:它会强制已加载的模块代码重新载入并重新执行
93+
94+
* `reload`函数可以修改程序的一部分,而无需停止整个程序
95+
* `reload`函数只能用于Python编写的模块,而无法用于其它语言编写的扩展模块
96+
![reload函数](../imgs/python_21_8.JPG)
97+
98+
18.`reload()``import``from`的差异:
99+
100+
* `reload`是Python内置函数,返回值为模块对象,`import``from`是语句
101+
* 传递给`reload`是已经存在的模块对象,而不是一个变量名
102+
* `reload`在Python3.0中位于`imp`标准库模块中,必须首先导入才可用。
103+
104+
19.`reload`工作细节:
105+
106+
* `reload`并不会删除并重建模块对象,它只是修改模块对象。即原来模块的每个属性对象内存空间还在,所有旧的引用指向他们,新的引用指向修改后的属性对象内存空间
107+
* `reload`会在模块当前命名空间内执行模块文件的新代码
108+
* `reload`会影响所有使用`import`读取了模块的用户,用户会发现模块的属性已变
109+
* `reload`只会对以后使用`from`的代码造成影响,之前用`from`的代码并不受影响。之前的名字还可用,且引用的是旧对象
110+
![reload与import、from](../imgs/python_21_9.JPG)

chapter/22_python_package.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# 模块包
2+
1.`import`时,也可以指定目录。目录称为包,这类的导入称为包导入。
3+
4+
* 包导入是将计算机上的目录变成另一个Python命名空间,它的属性对应于目录中包含的子目录和模块文件
5+
* 包导入的语法:
6+
7+
```
8+
import dir1.dir2.modname
9+
from dir1.dir2.modname import x
10+
```
11+
12+
![包导入](../imgs/python_22_1.JPG)
13+
14+
* 包导入语句的路径中,每个目录内部必须要有`__init__.py`这个文件。否则包导入会失败
15+
* `__init__.py`就像普通模块文件,它可以为空的
16+
* Python首次导入某个目录时,会自动执行该目录下`__init__.py`文件的所有程序代码
17+
* `import dir1.dir2.modname`包导入后,每个目录名都成为模块对象
18+
(模块对象的命名空间由该目录下的`__init__.py`中所有的全局变量定义
19+
(包含显式定义和隐式定义)决定)
20+
* `__init__.py`中的全局变量称为对应目录包的属性
21+
22+
![__init__.py](../imgs/python_22_2.JPG)
23+
24+
2.任何已导入的目录包也可以用`reload`重新加载,来强制该目录包重新加载
25+
>`reload`一个目录包的用法与细节与`reload`一个模块相同
26+
27+
![reload包](../imgs/python_22_3.JPG)
28+
29+
3.包与`import`使用时输入字数较长,每次使用时需要输入完整包路径。可以用from语句来避免
30+
![import包与from包区别](../imgs/python_22_4.JPG)
31+
32+
4.包相对导入:`from`语句可以用`.``..`
33+
34+
```
35+
from . import modname1 #modname1与本模块在同一包中(即与本文件在同一目录下)
36+
from .modname1 import name #modname1与本模块在同一包中(即与本文件在同一目录下)
37+
from .. import modname2 #modname2在本模块的父目录中(即在本文件上层)
38+
```
39+
>Python2中,`import modname`会优先在本模块所在目录下加载`modname`以执行相对导入。
40+
>因此局部的模块可能会因此屏蔽`sys.path`上的另一个模块
41+
>要想启用相对导入功能,使用`from __future__ import absolute_import`
42+
43+
* Python3中,没有点号的导入均为绝对导入。`import`总是优先在包外查找模块
44+
![包相对导入](../imgs/python_22_5.JPG)
45+
46+
47+

chapter/23_python_module_more.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# 高级模块用法
2+
1.Python模块会默认导出其模块文件顶层所赋值的所有变量名,不存在私有变量名。所有的私有数据更像是一个约定,而不是语法约束:
3+
4+
* 下划线开始的变量名`_x``from *`导入该模块时,这类变量名不会被复制出去
5+
![私有模块变量](../imgs/python_23_1.JPG)
6+
* 模块文件顶层的变量名列表`__all__`:它是一个变量名的字符串列表。`from *`语句只会把列在`__all__`列表中的这些变量名复制出来。
7+
![__all__变量名列表](../imgs/python_23_2.JPG)
8+
>Python会首先查找模块内的`__all__`列表;否该列表未定义,则`from *`会复制那些非
9+
>`_`开头的所有变量名
10+
>所有这些隐藏变量名的方法都可以通过模块的属性直接绕开
11+
12+
2.当文件是以顶层程序文件执行时,该模块的`__name__`属性会设为字符串`"__main__"`。若文件被导入,则`__name__`属性就成为文件名去掉后缀的名字
13+
14+
* 模块可以检测自己的`__name__`属性,以确定它是在执行还是被导入
15+
* 使用`__name__`最常见的是用于自我测试代码:在文件末尾添加测试部分:
16+
17+
```
18+
if __name__=='__main__':
19+
#pass
20+
```
21+
22+
3.在程序中修改`sys.path`内置列表,会对修改点之后的所有导入产生影响。因为所有导入都使用同一个`sys.path`列表
23+
24+
4.`import``from`可以使用`as`扩展,通过这种方法解决变量名冲突:
25+
26+
```
27+
import modname as name1
28+
from modname import attr as name2
29+
```
30+
在使用`as`扩展之后,必须用`name1``name2`访问,而不能用`modname`或者`attr`,因为它们事实上被`del`掉了
31+
![import、from as语句](../imgs/python_23_3.JPG)
32+
33+
5.在`import``from`时有个问题,即必须编写变量名,而无法通过字符串指定。有两种方法:
34+
35+
* 使用`exec: `exec("import "+modname_string)`
36+
* 使用内置的`__import__`函数:`__import__(modname_string)`,它返回一个模块对象
37+
> 这种方法速度较快
38+
39+
![通过字符串指定导入包名](../imgs/python_23_4.JPG)
40+
41+
6.`reload(modname)`只会重载模块`modname`,而对于模块`modname`文件中`import`的模块,`reload`函数不会自动加载。
42+
要想`reload`模块`A`以及`A` `import`的所有模块,可以手工递归扫描`A`模块的`__dict__`属性,并检查每一项的`type`以找到所有`import`的模块然后`reload`这些模块
43+
44+
7.可以通过下列几种办法获取模块的某个属性:
45+
46+
* `modname.attr`:直接通过模块对象访问
47+
* `modname.__dict__['attr']`:通过模块对象的`__dict__`属性字典访问
48+
* `sys.modules['modname'].name`:通过Python的`sys.modules`获取模块对象来访问
49+
* `getattr(modname,'attr')`:通过模块对象的`.getattr()`方法来访问
50+

imgs/python_19_1.JPG

26.9 KB
Loading

imgs/python_19_10.JPG

26.9 KB
Loading

imgs/python_19_2.JPG

17.1 KB
Loading

imgs/python_19_3.JPG

25 KB
Loading

imgs/python_19_4.JPG

26.6 KB
Loading

0 commit comments

Comments
 (0)