Python 学习笔记
Python 学习笔记
致谢
python 学习笔记
02. 数字类型
03. Set类型
04. 字符串
05. 列表
06. 元组
07. 通用序列
08. 字典
09. 文件
10. 语句和语法
11. 赋值语句
12. 打印
13. if语句
14. while、for循环
15. 迭代器和生成器
16. 文档
17. 函数
18. 作用域
19. 参数
20. 函数的高级特性
21. 模块
22. 模块包
23. 模块高级用法
24. 类 class
25. Python命名空间
26. 运算符重载
27. 类的设计模式
28. 类的高级主题
29. 异常
30. 异常对象
31. Unicode与字节串
32. 管理属性
33. 装饰器
34. 元类
致谢
书栈(BookStack.CN) 仅提供文档编写、整理、归类等功能,以及对文档内容的生成和导出工具。
文档内容由网友们编写和整理,书栈(BookStack.CN) 难以确认文档内容知识点是否错漏。如果您在阅读文档
获取知识的时候,发现文档内容有不恰当的地方,请向我们反馈,让我们共同携手,将知识准确、高效且有效地传递
给每一个人。
同时,如果您在日常工作、生活和学习中遇到有价值有营养的知识文档,欢迎分享到 书栈(BookStack.CN) ,
为知识的传承献上您的一份力量!
文档地址:http://www.bookstack.cn/books/python_learning_notes
书栈官网:http://www.bookstack.cn
书栈开源:https://github.com/TruthHun
分享,让知识传承更久远! 感谢知识的创造者,感谢知识的分享者,也感谢每一位阅读到此处的读者,因为我们
都将成为知识的传承者。
python 学习笔记
本文档是《learning python》中文第四版的学习笔记,是由我个人做的纸质读书笔记而来。
文档PDF版本可能会滞后于项目进度
纸质笔记可以从百度网盘下载:http://pan.baidu.com/s/1miEkaBu
个人所作的所有笔记也可以从百度网盘下载:http://pan.baidu.com/s/1boSzlx1
目标
这份笔记的目标是为了给出一份比较精炼,但是又要浅显易懂的Python教程。《Python学习手册》中文第四版虽然
比较简单,但是措辞比较罗嗦,而且一个语法点往往散落在多个章节,不方便读者总结。
我在做笔记时,将一个知识点的内容都统筹在一个章节里面,因此提炼性大大提高。而且还有《Python学习手册》中
文第四版的翻译在某些章节(可能难度较大?)措辞可能前后矛盾。当知识点提炼之后就能够很快的找到一些难以理
解的概念的上下文,方便吃透这些难点。
内容介绍
本文档一共35个章节。分别为:
1. Python的动态类型介绍
2. 数字类型
3. Set类型
4. 字符串
5. 列表
6. 元组
7. 通用序列
8. 字典
9. 文件
10. 语句和语法
11. 赋值语句
12. 打印
13. if语句
14. while/for循环
15. 迭代器和生成器
16. 文档
17. 函数
18. 作用域
19. 参数
20. 函数的高级特性
21. 模块
22. 包
23. 模块的高级用法
24. 类class
25. Python名字空间
26. 运算符重载
27. 类的设计模式
28. 类的高级主题
29. 异常机制
30. 异常对象
31. Unicode与字节串
32. 管理属性
33. 装饰器
34. 元类
35. Python的执行
基础知识
看这份笔记最好有面向对象的概念。因为这份文档里大量使用了面向对象的术语,比如”实例对象“、”类对象“、”名
字空间“等等。如果没有面向对象的概念,将会对理解后面的大部分章节有困难。
对于Python新手,这份文档难度不大。但是如果您对Python有一定的熟练程度,您会发现这份文档行云流水,一气
呵成,阅读起来就没有停顿感。如果您对于Python完全陌生,那么本文档阅读过程中,对于一些复杂的概念建议您动
手练手而不要完全依赖于文档中的示例。
补充
本文档所有的Python代码都是基于Python 3.5 64bit,在Python IDLE上运行的效果。操作系统为 Win7
64bit Professional
cutemarked 原版需要联网下载所需要的脚本文件,但是由于国内的网络问题,以及存在断网情况下使用等特殊需求
,我将它改造成了一个无需联网的本地化版本
本文档仅用于个人学习目的,未经许可不得用于商业目的,转载请注明出处
email: [email protected]
来源(书栈小编注)
本文档使用 书栈(BookStack.CN) 构建 -6-
python 学习笔记
https://github.com/huaxz1986/python_learning_notes
1. 作者:华校专
2. email: [email protected]
3. ** 本文档可用于个人学习目的,不得用于商业目的 **
Python 的动态类型介绍
1.在Python中没有变量的声明以及变量的类型:
变量的类型实在运行过程中自动决定的,而不是通过声明来决定的
变量首次赋值时,创建它。之后的再次赋值会改变该变量的值
2.类型的概念是存在于对象中而不是变量名中。变量名是通用的,它只是在特定时刻引用某个特定的对象而已。
当变量出现在表达式中时,它会马上被当前引用的对象所代替
任何变量名在使用前必须明确地赋值。用未赋值的变量会产生错误。
在Python内部,变量实际上是指向对象内存空间的一个指针
1. graph LR
2. id1(变量名)-->|引用|id2(对象);
3.每个表达式生成的结果,python都创建了一个新的对象去表示这个值
4.Python对象缓存了不变的对象并对其进行复用,如小整数和小字符串。但是逻辑上看,每个表达式的结果值都是不
同的对象,占用不同的内存。
5.每个对象都有两个标准的头部信息:
类型标志符:标识了该对象的类型(见第10条)
引用计数器:决定了是否可以回收这个对象(见第8条)
引用计数器记录了当前指向该对象的引用的数目。一旦它为0,
则该对象的内存空间就会自动回收
6.给一个变量赋新值,并不是替换原始的对象,而是让这个变量去引用完全不同的一个对象。
7.多个变量名引用同一个对象时,称为共享引用:
1. graph LR
2. id1(变量a) -->|引用|id2(对象)
3. id3(变量b) -->|引用|id2(对象)
4. style id2 fill:#ccf,stroke:#f66,stroke-width:2px,stroke-dasharray: 5, 5;
在共享引用中,对象的原地修改操作会影响到所有的引用该对象的变量
== 操作符比较的是两个变量引用的对象是否具有相同的值
is 操作符比较的是两个变量是否引用的是同一个对象
这里可以看到Python对象缓存了不变的对象并对其进行复用
11.Python提供了几种方法来查看对象的属性以及详细信息:
dir(x):查看x所指对象的属性
help(x.attr):查看x所指对象的attr属性
help(x):查看x所指对象的详细信息
None 是所有函数和方法的默认返回值
13.Python中,任何东西都是对象类型(见第10条),类型本身也是对象类型:
14.基本上在代码中进行类型检查是错误的,着破坏了代码的灵活性,限制了代码的类型。Python代码不关心特定的
数据类型,只关心接口,这就是Python的多态设计
一个操作的意义取决于被操作对象的类型。同样的操作对不同的对象来说意义可能不同,前提是该对象支持该操
作
若对象不支持某种操作,则Python会在运行时检测到错误并自动抛出一个异常
15.Python可以在旧版本中开启新版本的特性,只需用在模块文件中使用:
from __future__ import 特性名
1. 作者:华校专
2. email: [email protected]
3. ** 本文档可用于个人学习目的,不得用于商业目的 **
数字类型
1.Python的数字常量:
Python3中,整数不再区分一般整数与长整数
Python2.7中整数分为一般整数(32位)与长整数(支持无穷整数大小)。
整数以 l 或者 L 结尾时为长整数。当整数值超过32位时自动转换为长整数
2.数字类型转换:
3.混合类型表达式中,Python先将被操作对象转换成其中最复杂的操作对象的类型。
整数与浮点数混合操作时,将整数自动转换成浮点数
浮点数与复数混合操作时,将浮点数自动转换成复数
也可以通过 int() , float() ,以及 complex() 执行手动转换
4.Python允许执行连续比较,且比较链可以任意长:
本文档使用 书栈(BookStack.CN) 构建 - 10 -
02. 数字类型
Python3中的除法保留小数部分,无论是整数除法还是浮点除法
Python2.7中的除法:对整数除法会截取整数部分放弃小数部分,对小数除法会保留小数部分
即使是浮点的Floor除法,结果也是取整的浮点数
7.Python支持将整数当作二进制位串对待的位操作。
8.Python支持许多对数字处理的内置函数与内置模块:
本文档使用 书栈(BookStack.CN) 构建 - 11 -
02. 数字类型
9. random 模块提供的工具可以生成0~1之间的随机浮点数、两个数字之间的任意整数、
序列中的任意一项。
10.浮点数缺乏精确性,因为存储浮点数的空间有限(这是硬件相关的内存缺陷),
可以用 Decimal 对象解决精度问题。
Decimal 对象来自于 decimal 模块,它类似于浮点数,但是有固定的位数和小数点,
因此是固定精度的小数。相对于浮点数,它带来了微小的精度损失。
Fraction 对象能保证精确性,且能自动简化结果
从浮点数产生分数有两个方法:
本文档使用 书栈(BookStack.CN) 构建 - 12 -
02. 数字类型
1. graph LR
2. id1(整数)-->|提升|id2(浮点数);
3. id2(浮点数)-->|提升|id3(Fraction);
4. id2(浮点数)-->|提升|id4(Decimal);
15. 真 和 假 是Python中每个对象的固有属性:每个对象不是 真 就是 假 。
该属性可以用于 任何需要 bool`值的地方。
本文档使用 书栈(BookStack.CN) 构建 - 13 -
03. Set类型
Set类型
1.Python的 set 类型是集合内元素值唯一、元素值不可变的无序集。
set 类型并不要求其集合内各个元素都是相同类型。
2. set 本身的性质有:
set 对象是可迭代对象
set 对象可以增长或缩短
set 对象可能包含各种类型的对象作为元素
创建 set 对象的方法为调用 x=set(iter) ,其中 iter 为任何序列或可迭代对象
3. set 对象有以下操作:
本文档使用 书栈(BookStack.CN) 构建 - 14 -
03. Set类型
3. set 的方法有:
本文档使用 书栈(BookStack.CN) 构建 - 15 -
03. Set类型
本文档使用 书栈(BookStack.CN) 构建 - 16 -
04. 字符串
1. 作者:华校专
2. email: [email protected]
3. ** 本文档可用于个人学习目的,不得用于商业目的 **
字符串
1.Python的字符串是一种不可变序列,它包含的字符存在从左到右的位置顺序。
不可变是指:字符串创建以后无法修改它的内容。
序列包括:字符串、列表、元组
字符串由一对双引号或者单引号包围,二者无任何区别
如果希望字符串中包含引号,则有两种办法:
空字符串是一对引号之间不包含内容: ""
Python自动在任意的表达式中合并相邻的字符串常量
在字符串中反斜杠代表转义序列,每个转义序列代表一个字符(不一定能够打印出来):
\\ 转义反斜杠本身
\n 为换行符
\0 为 \0x00 (不是字符串结尾)
\xhh 为十六进制值
\o00 为八进制值
\uhhhh 为16位Unicode的十六进制值
\Uhhhhhhhh 为32位Unicode的十六进制值
Python中 \0 并不去结束一个字符串,Python会在内存中保持整个字符串的长度和文本
Python会以十六进制显示非打印的字符
若无合法的转义编码识别 \ 以及之后的字符,则Python会在最终的字符串中保留 \
本文档使用 书栈(BookStack.CN) 构建 - 17 -
04. 字符串
3.字符串块:以三重引号包围的字符串(引号为一对单引号或者一对双引号均可)。
三重引号之间的文本会被收集到一个单独的多行字符串中,并且将换行以 \n 代替。
4.字符串可以有以下操作:
加:两个字符串相加,返回一个新的字符串
乘:字符串与整数 N 相乘,返回一个新的字符串,该字符串是原字符串重复 N 次
len() :返回字符串长度
迭代:字符串对象是一个可迭代对象
未给出上界时,该分片默认上界为 len(S)
未给出下界时,该分片默认下界为 0
如果是 S[:] ,则返回字符串 S 的一个全新拷贝
若 k 为正数则从左到右步进;若 k 为负数,则从右向左步进
S[::-1] 返回S的翻转字符串
本文档使用 书栈(BookStack.CN) 构建 - 18 -
04. 字符串
负步进时,默认的上下界极限有所不同。
上界极限可以为空或者为 len(S) 或者为 len(S)-1
下界极限必须为空,否则 0 号元素会被排除掉
9.字符串是不可变序列,因此不能原地修改一个字符串,只能够生成新的字符串并赋值给原变量。
10.字符串格式化表达式是基于C语言的printf格式化表达式。其格式为:
本文档使用 书栈(BookStack.CN) 构建 - 19 -
04. 字符串
它返回一个新的字符串。
占位符有多种:
%s :字符串; %r :也是字符串,但用 repr() 得到的而不是 str() ;
%c :字符; %d :十进制整数; %i :整数; %e :浮点指数;
%f : 浮点十进制; %% :百分号 % , %g :自动转成浮点 %e 或者 %f
转换通用目标结构为: %[(key_name)][flags][width][.precision]type
key_name :用于从右边字典中取对应键的值(此时右边的是字典对象,而不是元组)
如: "%(n)%d %(x)%s" %{"n":3,"x":"apples"}
type 为类型,如 d , r , f , e 等
11.格式化字符串除了使用字符串格式化表达式之外,还可以通过字符串的 .format()
方法达到同样的效果。
.format() 方法支持位置参数、关键字参数、以及二者的混合。
位置参数: "{0},{1},{2}".format('abc','def','ghi')
关键字参数: "{k1},{k2},{k3}".format(k1='abc',k2='def',k3='ghi')
混合使用: "{0},{1},{k}".format('abc','def',k='ghi')
格式化字符串中可以指定对象的属性、字典键、序列的索引:
指定字典的键: "{0[a]}".format({'a':'value'}) ,注意这里的键 a 并没有引号包围
指定对象的属性: "{0.platform}".format(sys) ,也可以用关键字参数:
"{obj.platform}".format(obj=sys)
本文档使用 书栈(BookStack.CN) 构建 - 20 -
04. 字符串
通用目标结构为: {fieldname!conversionflag:formatspec}
本文档使用 书栈(BookStack.CN) 构建 - 21 -
04. 字符串
12.格式化单个值比较简单,可以有以下方法:
"%s" % 1.23
13.由于Python内部会暂存并重复使用短字符串来进行优化,因此该短字符串在内存中只有一份。
因为按照 %f 格式化输出时,浮点数有精度和位宽的设定(虽然这里没有显式指定,但是它们有默认值)。
而 %s 格式化输出时,首先调用了 str() 函数,然后再进行输出。
本文档使用 书栈(BookStack.CN) 构建 - 22 -
05. 列表
1. 作者:华校专
2. email: [email protected]
3. ** 本文档可用于个人学习目的,不得用于商业目的 **
列表
1.列表可以包含任何种类的对象。它是本身是一种可变对象,支持原地修改。
不可变对象有元组、字符串、 frozenset
2.列表的基本操作有:
list1+list2 :列表相加合并生成新的列表,
并不会修改 list1 和 list2 的值
list1*5 : 列表乘以数字生成重复的新列表,
并不会修改 list1 的值
本文档使用 书栈(BookStack.CN) 构建 - 23 -
05. 列表
索引和分片:
list1[index] :索引,获取指定偏移处的对象,
并不会修改 list1 的值
list1[index1:index2] :分片,返回一个新列表,
其元素值与旧列表对应片段处元素值相等,
并不会修改 list1 的值
当索引位于赋值左侧时,则是索引赋值。这会改变列表指定项的内容。修改 list1 的值
当分片位于赋值左侧时,则是分片赋值。这会改变列表指定片段的内容。
修改 list1 的值
被赋值的片断长度不一定要与赋值的片断长度相等
3.列表的方法调用有:
.append(val) 方法:在列表之后追加元素,原地修改
.sort(key=None, reverse=False) 方法:对列表进行排序,
原地修改
key 为一个排序方法
reverse 为是否逆序
.reverse() 方法:原地翻转列表,原地修改
.extend(iter_obj) 方法:在列表末端插入多个元素,原地修改
.pop() 方法:删除末尾元素并返回该元素,原地修改
本文档使用 书栈(BookStack.CN) 构建 - 24 -
05. 列表
.pop(index) 方法:删除指定位置元素并返回该元素,原地修改
del list1[0] 函数:删除指定位置处元素,原地修改
与 .pop() 的区别在于 del() 函数并不返回该元素
.index(val) :返回指定元素的位置,若有多个值,则只返回第一个遇到的值所在位置
4.列表相关的内置函数:
本文档使用 书栈(BookStack.CN) 构建 - 25 -
05. 列表
5.列表不允许引用超出列表末尾的索引。
6.列表解析表达式:通过对可迭代对象迭代生成的项运行一个表达式的方式创建一个新列表。如:
[c*2 for c in "apple"]
9.如果列表的元素是可变对象的,则对该可变对象的修改会影响到列表。
本文档使用 书栈(BookStack.CN) 构建 - 26 -
06. 元组
1. 作者:华校专
2. email: [email protected]
3. ** 本文档可用于个人学习目的,不得用于商业目的 **
元组
1.元组是由圆括号包围的一系列项,它由任意对象元素组成。它本身是不可变的,
即不可以原地修改。
元组的元素可以为可变对象,也可以为不可变对象。
元组是有序的序列
元组中的元素可以通过偏移访问,支持索引和分片,但是不支持索引赋值和分片赋值
通过索引访问返回一个值
通过分片访问返回一个新的元组
() 为空元祖, (0,) 为单元素元组(注意逗号 , ), (0) 为括号表达式
tuple(iter_obj) 函数从一个可迭代对象生成元组
len(tuple1) :该函数获取元组长度
item in tuple1 :判断元素值 item 是否在元组中
元组是一个可迭代对象,它支持迭代:
2. pass
本文档使用 书栈(BookStack.CN) 构建 - 27 -
06. 元组
本文档使用 书栈(BookStack.CN) 构建 - 28 -
07. 通用序列
通用序列
1.Python的通用序列包括:字符串、列表、元组。
字符串:不可变对象,元素只能是字符
列表:可变对象,元素类型不限
元组:不可变对象,元素类型不限
这里的 可变 指的是能否修改对象,如增加序列元素,修改序列元素等等
2.Python通用序列操作有:
3. set 不是序列,它是可变对象,但是元素只能是不可变类型。
字典也不是序列,它是可变对象,其元素的值是不限类型,但是键必须是不可变类型。
4.三种解析表达式:
本文档使用 书栈(BookStack.CN) 构建 - 29 -
07. 通用序列
6.序列的拷贝:
分片表达式能复制序列, 只能进行顶层拷贝
字典的 .copy() 方法能复制字典, 只能进行顶层拷贝
通过 list() 、 tuple() 等方法
通过 copy 标准库模块,可以进行深层拷贝
7.比较操作时,Python能够自动遍历嵌套的对象,从左到右递归比较,要多深有多深。过充中首次发现的差异将决定
比较的结果。
数字通过相对大小比较
字符串从左到右每个字符按照字符的字典序比较
列表和元组从左到右每部分内容都比较
本文档使用 书栈(BookStack.CN) 构建 - 30 -
07. 通用序列
本文档使用 书栈(BookStack.CN) 构建 - 31 -
08. 字典
字典
1.字典是一些 “键 —- 值” 对的无序集和。它通过键来索引。
字典是可变对象,它的元素的值的类型不限,它的元素的键类型是不可变类型
生成字典 {'a':3,'b':4}
1. 因此在Python3中如果想得到列表,必须将返回值传入`list()`函数中得到列表
本文档使用 书栈(BookStack.CN) 构建 - 32 -
08. 字典
字典的操作:
d1.update(d2) :合并两个字典,原地修改 d1 字典
d.pop(key) : 从字典中删除 key 并返回该元素的值
del d[key] :从字典中删除 key 但是不返回该元素的值
d[key]=value :原地的添加/修改字典。当向不存在的键赋值时,相当于添加新元素
获取字典中元素数量: len(d) 。它也等于键列表/值列表的长度
字典本身也是一个可迭代对象,它的迭代方法为:
1. for key in d:
2. pass
它在列表的键上迭代,也等价于
本文档使用 书栈(BookStack.CN) 构建 - 33 -
08. 字典
2. pass
2.Python3中字典的变化:
3.Python3中字典是一个迭代器对象,其迭代结果是返回键序列
本文档使用 书栈(BookStack.CN) 构建 - 34 -
09. 文件
文件
1.内置的 open() 函数会创建一个Python文件对象,可以作为计算机上的一个文件的引用。
2.打开文件: outfile=open(r'C:\filename','w') :
'r' :读打开(默认行为)
'w' :写打开
'a' :追加写打开
3.文件对象的方法:
文件读入:
.read() :读取接下来的整个文件到单个字符串
.read(n) :读取接下来的 n 个字节到一个字符串
.readline() :读取下一行到一个字符串(包括行末的换行符)
.readlines() :按行读取接下来的整个文件到字符串列表,每个字符串一行
写入文件:
.write(str) :写入字符串到文件(并不会自动添加换行符以及其他任何字符, str 是啥就写啥),
返回写入的字符数
.writelines(strlist) :将字符串列表内所有字符串依次写入文件(并不会自动添加换行符以及其他任何
字符)
本文档使用 书栈(BookStack.CN) 构建 - 35 -
09. 文件
文件迭代:文件对象也是一个可迭代对象,每一次迭代返回一行,对于大型文件一次性读取非常耗内存和性能:
读二进制文件用 openopen(r'filename','rb')
4.从文本文件中读取文字行的最佳方式是用文件迭代器,不要直接读取文件
5.当文件对象被自动收回时,Python会自动关闭该文件,这意味着不一定要手动调用 .close() 方法
7.文件的空行是含有换行符的字符串,而不是空字符串。因此如果读入操作返回空字符串,则表示已经到文件末尾
了。
不能以文本格式打开一个二进制数据文件,会乱码
本文档使用 书栈(BookStack.CN) 构建 - 36 -
09. 文件
sys.stdout 对象:标准输出对象
sys.stdin 对象:标准输入对象
本文档使用 书栈(BookStack.CN) 构建 - 37 -
09. 文件
sys.stderr 对象:标准错误输出对象
12. os 模块中的文件描述符对象支持文件锁定之类的低级工具
本文档使用 书栈(BookStack.CN) 构建 - 38 -
10. 语句和语法
1. 作者:华校专
2. email: [email protected]
3. ** 本文档可用于个人学习目的,不得用于商业目的 **
语句和语法
1.所有Python的复合语句,都是以冒号 : 结尾,下一行缩进开始进入代码块。同一个级别代码块的缩进形式相同
3.可以省略行尾的分号 ;
4.代码块的范围由缩进来决定。同一个块中,所有语句向右缩进相同的距离(块内语句垂直左对齐)。
缩进可以用空格或者制表符。不应该在同一段代码中混合使用制表符和空格
若缩进出现不一致,则会导致语法错误
5.若将多行语句列入一行,则必须用分号隔离 ;
7.当复合语句不包含任何复合从句时,复合语句的主体可以出现在Python首行冒号之后:
if x>y : print(x)
8.变量名由:下划线或字母开头,后面接任意字母、数字、下划线
前后双下划线的变量名是系统预定义的,对解析器有着特殊的意义,如变量名 __x__
仅前面有双下划线的变量名视为类的本地变量,如变量名 __x
9.表达式可以作为语句,但是其结果不会存储。因此只有当表达式工作产生副作用时,这种用法才有意义。
表达式可以作为语句,但是语句不能作为表达式。如 Python中不支持(C和C++可以,因为在C/C++中赋值表
达式产生左值):
1. if( a=file.read() ):
2. pass
10.Python的语句是逐条运行的,除非遇上控制流语句。
块|语句的边界是自动检测的。缩进定义了块边界,换行定义了语句边界
首行+ : +缩进语句定义了复合语句
空白行、空格、注释通常被解释器忽略
文档字符串会被解释器忽略,但是会保存它并由工具显示
11.Python顶层程序代码必须不能有缩进。缩进发生在复合语句的字块中。
本文档使用 书栈(BookStack.CN) 构建 - 39 -
11. 赋值语句
1. 作者:华校专
2. email: [email protected]
3. ** 本文档可用于个人学习目的,不得用于商业目的 **
赋值语句
1.赋值的左侧可以为变量名或者对象元素,右侧为任何表达式
赋值总是建立对象的引用值,而不是复制对象
变量名会在首次被赋值时创建。此后,每当这个变量名出现在表达式中时,会被它引用的对象所替代
变量名必须先赋值后引用,否则报错
模块导入、函数定义、类定义、 for 循环、函数参数传递 等过程都会触发隐式赋值,原理、规则同显式赋值
2.赋值语句的形式:
基本形式: x='abcd'
多目标赋值: a=b="abcd"
注意此时 a 和 b 都引用同一个对象。如果这个对象是个可变对象,则使用 a 或者 b
1. 对它进行原地修改可能导致陷阱
若变量名序列和值序列长度不等,则抛出 ValueError 异常
支持嵌套的赋值序列,Python会自动根据实际情况分解成其组成部分,然后递归赋值。要求左侧变量名序列的
嵌套形状必须符合右侧值序列的嵌套形状。
4.扩展的序列解包赋值:收集右侧值序列中未赋值的项为一个列表,将该列表赋值给带星号 * 的变量
左边的变量名序列长度不需要与值序列的长度相等,其中只能有一个变量名带星号 *
若带星号 * 变量名只匹配一项,则也是产生一个列表,列表中只有一个元素,
如 a,*b="12" , b 为 [2]
匹配过程优先考虑不带星号的变量名,剩下的才匹配带星号的变量名
以下情况会引发错误:
本文档使用 书栈(BookStack.CN) 构建 - 40 -
11. 赋值语句
左侧变量名序列有两个星号,如 *a,*b="abcd"
左侧变量名序列无星号但是左右长度不匹配,如 a,b="abcd"
左侧变量名序列星号的名称不在序列中,如 *a='abcd'
可以用手动分片来模拟扩展赋值行为
5.增强赋值的优点:
本文档使用 书栈(BookStack.CN) 构建 - 41 -
12. 打印
1. 作者:华校专
2. email: [email protected]
3. ** 本文档可用于个人学习目的,不得用于商业目的 **
打印
1.打印 print 类似于文件 .write() 方法,它将默认地把对象打印到 stdout 流中。它会自动添加一些自动化的格
式。
参数意义依次为:
待打印对象作为位置参数依次给出
sep 关键字参数指定分隔符,默认为空格
end 关键字参数指定结尾字符串,默认为换行符
file 指定输出位置,默认为标准输出文件,它必须是一个写打开的文件对象
每个被打印的对象依次自动通过内置的 str() 函数取得其文本表示
当没有打印对象时, print() 会把一个换行符(或者由 end 指定的其他字符串)打印到标准输出流中(或者
由 file 指定的文件中)
关键字参数可以以任何顺序出现,但必须在位置参数之后
3. print 实际上是向文件对象中写文本字符串,因此对于字符串常量的一对引号实际上是不输出的,它只是输出字
符串的内容。而交互式命令中,为了显示指定字符串,输出中带有一对引号。
1. temp=sys.stdout #保存旧值
2. sys.stdout=open('test.txt','a') #重新对stdout赋值,该文件对象必须写打开
3. print(obj1,obj2)
4. sys.stdout.close() #此句可以不要,此时文件对象自动回收,文件自动关闭
5. sys.stdout=temp #恢复旧值
本文档使用 书栈(BookStack.CN) 构建 - 42 -
12. 打印
本文档使用 书栈(BookStack.CN) 构建 - 43 -
13. if语句
1. 作者:华校专
2. email: [email protected]
3. ** 本文档可用于个人学习目的,不得用于商业目的 **
if 语句
1. if 语句的的通用格式:
1. if test_expr1: #必选
2. statement1#必选
3. elif test_expr2: #可选
4. statement2
5. else: #可选
6. statement3
字典也可以执行多路分支的逻辑,如:
1. mydict={'a':func1,'b':func2}
2. choice='a'
3. print(mydict[choice])
3.Python中的真值测试:
and :从左到右依次对操作对象求值,停在第一个为假的对象上并返回它,或者当前面所有操作对象为
真时返回最后一个操作对象
or :从左到右依次对操作对象求值,停在第一个为真的对象上并返回它,或者当前面所有操作对象为假
时返回最后一个操作对象
本文档使用 书栈(BookStack.CN) 构建 - 44 -
14. while、for循环
1. 作者:华校专
2. email: [email protected]
3. ** 本文档可用于个人学习目的,不得用于商业目的 **
while 、 for 循环
1. while 语句格式:
1. while test_expr:
2. statement1
3. else:#可选
4. statement2
在 while 子句中可以使用下列语句:
break :跳出最近所在的循环到循环外部
continute :跳过本次循环后续部分,直接掉转到下一轮循环起始处
pass :占位符,什么都不做
在Python3中,允许在使用表达式的地方使用 ... 代表,
这是 pass 语句的一种替代方案。它表示代码随后填充,是未确定的内容
2. for 语句格式:
3. else:#可选
4. statement2
任何赋值目标在语法上均有效,即使是嵌套的结构也能自动解包:
2. print(a,b,c)
本文档使用 书栈(BookStack.CN) 构建 - 45 -
14. while、for循环
当然你也可以手动解包:
3. for 扫描文件时,直接使用文件对象迭代,每次迭代时读取一行,执行速度快,占用内存少:
要得到列表,用 list(range(0,10,2))
1. S="abcdefg"
2. for i in range(0,len(S),2):
3. print(S[i],end=" ")
它也等价于下列循环:
1. S="abcdefg"
2. for c in S[::2]
3. print(c,end=" ")
用range()优点是它并未复制字符串
本文档使用 书栈(BookStack.CN) 构建 - 46 -
14. while、for循环
可以在循环中用自动列表解包:
2. pass
本文档使用 书栈(BookStack.CN) 构建 - 47 -
15. 迭代器和生成器
1. 作者:华校专
2. email: [email protected]
3. ** 本文档可用于个人学习目的,不得用于商业目的 **
迭代器和生成器
1.可迭代对象:在逻辑上它保存了一个序列,在迭代环境中依次返回序列中的一个元素值。
可迭代对象不一定是序列,但是序列一定是可迭代对象
任何对象只要实现了迭代协议,则它就是一个迭代器对象
迭代器对象调用 .__next__() 方法,会得到下一个迭代结果
在一系列迭代之后到达迭代器尾部,若再次调用 .__next__() 方法,则会触发 StopIteration 异常
迭代器在Python中是用C语言的速度运行的,因此速度最快
.readline() 方法在到达文件末尾时返回空字符串
6.字典的迭代器:字典的迭代器在迭代环境中,每次迭代返回的是一个键。
7.扩展的列表解析表达式:
[ x+y for x in 'abc' if x!='a' for y in 'lmn' if y!='l']
本文档使用 书栈(BookStack.CN) 构建 - 48 -
15. 迭代器和生成器
其通用结构为:
9.常见的迭代函数:
sorted(iterable,key=None,reverse=False) :排序并返回排好的新列表
sum(iterable,start) :返回可迭代对象中的累加值
本文档使用 书栈(BookStack.CN) 构建 - 49 -
15. 迭代器和生成器
range 不直接生成列表的优点是节约内存空间
由于 map 、 zip 、 filter 对象都是迭代器,因此不支持在它们身上安装多个活跃的迭代器。对他们调
用 iter() 其实返回的是它们本身。
生成器函数会保存上次执行的状态
定义生成器函数的语法为:
1. def genFunc(num):
2. for i in range(num):
3. yield i**2
结果或引发一个 StopIteration 异常
yield 语句会挂起生成器函数并向调用者发送一个值。当下一轮继续时,函数会在上一个 yield 表达式返回后
继续执行,其本地变量根据上一轮保持的状态继续使用
生成器函数运行代码随时间产生一系列的值,而不是一次性计算它们。这会节约内存并允许计算时间分散。
本文档使用 书栈(BookStack.CN) 构建 - 50 -
15. 迭代器和生成器
yield 表达式的返回值和生成值是不同的。
返回值是用于生成器函数内部, yield 表达式默认返回值为 None ;
而生成值是用于生成器函数外部的迭代返回。
17.生成器表达式:类似于列表解析,但是它是在圆括号中的,而不是方括号中的。
生成器表达式返回的是一个生成器对象
列表解析的结果等同于 list() 内参数为一个生成器表达式
当生成器表达式在其他括号之内时,它本身的圆括号可以不写
同样的迭代可以用生成器函数或者一个生成器表达式
生成器函数可以包含更多的逻辑
生成器表达式更简洁,没有函数调用产生生成器的过程
生成器函数与生成器表达式支持自动迭代与手动迭代
生成器对象本身是迭代器,因此只支持一个活跃的迭代器。
本文档使用 书栈(BookStack.CN) 构建 - 51 -
15. 迭代器和生成器
2. for i in range(10):
3. yield i
4. for j in range(10,20):
5. yield j
如果你想切分成两个迭代器,可以这么做:
1. def generator2():
2. for i in range(10):
3. yield i
4. def generator3():
5. for j in range(10):
6. yield j
7. def generator():
8. for i in generator2():
9. yield i
10. for j in generator3():
11. yield j
1. def generator2():
2. for i in range(10):
3. yield i
4. def generator3():
5. for j in range(10):
6. yield j
7. def generator():
1. def generator():
2. inner_gen=generator2()
3. yield from inner_gen #为了便于说明,这里分两行写
4. gen=generator()
本文档使用 书栈(BookStack.CN) 构建 - 52 -
15. 迭代器和生成器
本文档使用 书栈(BookStack.CN) 构建 - 53 -
16. 文档
1. 作者:华校专
2. email: [email protected]
3. ** 本文档可用于个人学习目的,不得用于商业目的 **
文档
1. # 是注释符,它之后的文字到行尾均为注释。Python解释器会忽略 # 之后的所有字符
2. dir(obj) 可以返回对象内所有的属性列表。它能够调用任何有属性的对象
模块文件、函数、类定义的多行注释一般用三重引号字符串
4.标准PyDoc工具用Python代码编写,它提取文档字符串并自动格式化其信息,展示成排列友好的报表。
Python在标准库中附带了PyDoc工具
有两种最主要的PyDoc接口:
内置的 help() 函数。可以对函数、方法、类型、对象使用 help() 函数。
对较大的对象(如模块、类型), help() 输出的内容会分成几段。
报表中的信息有些是文档字符串,有些是PyDoc自动查看对象内部而收集的结构化信息。
PyDoc的 GUI|HTML 接口。启动 Tools/scripts 目录下的 pydoc3.py 脚本:
pydoc3.py -b
5.Python标准手册随Python发布。手册以HTML和其他格式实现。最重要的项目是:
Library Reference:标准库文档,说明了内置类型、函数、异常等等
Language Reference:官方给出的语言层次的细节
本文档使用 书栈(BookStack.CN) 构建 - 54 -
17. 函数
函数
1.Python的函数是由 def 语句编写。Python中,函数也是一种对象类型
2.函数参数没有任何类型约束,返回类型也没有任何类型约束
3.Python函数定义语句:
1. def func_name(arg1,arg2):
2. statement
4.函数仅仅是对象类型,函数名也仅仅是变量名,它们没有任何特殊之处。
函数对象有函数调用方法 operator ()
函数对象允许任意的属性添加 func.attr=value
5.函数主体内的代码直到函数被调用时才运行。函数内的变量名在函数实际执行之前都不会解析。
本文档使用 书栈(BookStack.CN) 构建 - 55 -
18. 作用域
作用域
1.代码中变量名被赋值的位置决定了这个变量名的作用域(即可见范围)。因为变量是在首次赋值的时候定义的。
Python将一个变量名首次被赋值的地点关联为一个特定的命名空间
2.变量可以在3个不同的地方定义,对应三种不同的作用域:
def 内赋值定义的变量:作用域为本函数
这里的赋值包括显式 = 赋值和隐式赋值。隐式赋值包括
import 语句隐式赋值
def 函数定义来隐式赋值(函数名这个变量)
形参匹配来隐式赋值
3.作用域法则:
每个模块文件就是一个全局作用域。从外面看,模块的全局变量就成为该模块对象的属性;从内部看,模块的全
局变量就是普通的、作用域为全局的变量
全局作用域的范围仅限于变量所在的单个文件
每次调用函数,都创建一个新的局部作用域
默认情况下,所有函数定义内部的变量都是局部变量
global 语句声明会将变量名作用域提升至全局
nonlocal 语句声明会将变量名作用域提升至外层的 def
首先查找本地作用域 L
接着查找全局作用域 G
最后查找内置作用域 B
如果均未找到变量名则报错。
当前面作用域的变量名覆盖内置的作用域名字时,可以手动 import builtins 模块,在用 builtins.name 来直接使用
这个变量名。注意不要随意修改 builtins 模块内变量的值。
1. a=1
2. b=2
3. def func():
4. global a,b,c #一个名字或逗号分隔的多个名字,这些变量名被提升到全局作用域内
本文档使用 书栈(BookStack.CN) 构建 - 56 -
18. 作用域
5. a=2
6. b=0
7. c=0 #虽然c没有在def外定义,但这里的global 和 c=0会在全局作用域内定义c
7.要在局部作用域中修改全局变量,方法有以下几种:
global声明
通过 import modname 然后利用 modname.attr 来访问
通过 import sys 然后利用 sys.modules['modname'].attr 来访问
8.作用域示例:
1. x='global_x' #全局作用域
2. def f1():
3. x='f1_x' #f1的局部作用域
4. z='f1_z' #f1的局部作用域
5. def f2():
6. global y #全局作用域
7. y='f2_y'
8. print('in f2',x) #LGBE法则,找到的是f1局部作用域中的x
9. nonlocal z #f2的nonlocal作用域,是f1的局部作用域
10. z='f2_z'
9.嵌套的函数返回后也是有效的。
1. def f1():
2. x=99
3. def f2():
4. print(x)
5. return f2 # f2是个局部变量,仅在f1执行期间因为新建了局部作用域所以才存在。
6. action=f1() #f2指向的函数对象,由于action引用它,因此不会被收回。
7. #但是f2这个位于局部作用域中的变量名被销毁了
8. action() #此时f1执行结束,但是f2记住了在f1嵌套作用域中的x。这种行为叫闭包
类比闭包在语义上更明确,因为类可以明确定义自己的状态
10.在函数内部调用一个未定义的函数是可行的,只要在函数调用是,该未定义函数已定义即可。
本文档使用 书栈(BookStack.CN) 构建 - 57 -
18. 作用域
11.嵌套作用域中的变量在嵌套的函数调用时才进行查找,而不是定义时。 、
1. def func():
2. acts=[]
3. for i in range(5):
4. acts.append(lambda x:i**x) #添加匿名函数对象
5. return acts
6. acts=func()
7. acts[0](2) #调用时才开始查找i,此时i最后被记住的值是4
要解决这个这个陷阱,可以用默认参数:
1. def func():
2. acts=[]
3. for i in range(5):
4. acts.append(lambda x,i=i:i**x) #每次循环,形参i的默认实参均不同
5. return acts
6. acts=func()
7. acts[0](2)
1. def func():
2. a=0
3. b=1
4. def func1():
5. nonlocal a,b#限定了查找只能在func1所在的作用域(即func的本地作用域),且要求名字a,b已经存在。
6. a='a' #对a,b的赋值会影响到func中的a,b
本文档使用 书栈(BookStack.CN) 构建 - 58 -
19. 参数
参数
1.参数传递的性质:
参数的传递是通过自动将对象赋值给本地变量名来实现的(自动的隐式赋值)
被传递的参数对象本身并不会被拷贝
在函数内部的参数名赋值不会影响到实参对象,只是将变量名重新引用到另一个对象
若实参对象为可变对象,则在函数内原地修改参数对象会影响所有的指向该实参对象的引用
可变参数实参对象对函数来说,既可以作为输入也可以作为输出
如果想限制对可变实参对象的修改,可以创建一个可变对象的拷贝作为参数;
或者直接转换成不可变对象作为参数
2.默认情况下,参数匹配是通过其位置进行匹配的,从左到右一一匹配。必须精确传递和函数签名中参数名一样多的
实参。
3.关键字参数:允许通过变量名进行匹配,而不是通过位置。其中关键字顺序可以任意。
4.默认参数:函数定义时,可以为参数设定默认值,这样允许调用时传递较少的参数。
对于默认实参,可以不用给它传入实参
默认实参后面不能跟随非默认实参。如果出现这种情况则报语法错误。
5.可变参数:
函数能用特定的参数(以 * 开头),收集任意多的额外位置参数,将收集到的位置相关的参数到一个新元组
中。
若出现了额外的关键字参数,则报错
函数能用特定的参数(以 ** 开头),收集任意多的额外关键字参数,将收集关键字相关的参数到一个新字典
中。
若出现了额外的位置参数,则报错
6.可变参数解包:
本文档使用 书栈(BookStack.CN) 构建 - 59 -
19. 参数
调用者可以用 ** 语法将字典实参打散,形成关键字参数
这里的 * 和 ** 均是在函数调用中出现,而不是在函数定义中出现
如果不这么做,则没有办法传递该实参
8.函数调用时,位置参数与关键字参数可以组合
不能为同一个形参同时指定位置实参与关键字实参
任何关键字实参必须位于任何位置实参之后
9.函数定义时的参数类型顺序:
1. def func(a,b,c='c',*d,e,f='f',**g):
2. pass
3. # a,b:为一般参数
4. # c:指定了默认实参
5. # d:为可变位置参数
6. # e,f:为 keyword-only参数,其中f指定了默认参数
7. # g:为可变关键字参数
e,f,g 调用时必须都是关键字实参
10.函数调用时实参类型顺序:
1. func('a','b',e='e',*seq,**dic)
2. #seq是一个序列,它解包之后优先覆盖c,剩下的再收集成元组传给d
3. #dic是一个字典,它解包之后优先考虑e,f,剩下的在收集成字典传递给g
4. #e='e'这个关键字实参也可以位于'b'之后的任何位置
5. #关键字实参必须位于位置实参之后
通过位置分配位置参数
通过匹配变量名在分配关键字参数
额外的非关键字参数分配到 d 引用的元组中
额外的关键字参数分配到 g 引用的字典中
本文档使用 书栈(BookStack.CN) 构建 - 60 -
19. 参数
默认值分配给剩下未赋值的参数
Python最后检测确保每一个参数只传入了一个值
11.定义函数时,形参列表中 * 可以单独出现。此时函数并不表示接受一个可变长度的实参列表,而是表示 * 后
面的所有实参必须作为关键字实参传入:
并不能用 ** 像 * 一样单独出现在函数定义中。
本文档使用 书栈(BookStack.CN) 构建 - 61 -
20. 函数的高级特性
函数的高级特性
1.在Python中,函数的递归通常比 for 循环要慢而且空间消耗大,但是递归的优点是可以遍历任意形状的结构。
2.Python函数是对象,自身存储在内存块中,它可以自由地传递与引用。
函数对象支持一个特殊操作:有括号 () 以及参数列表执行调用行为
我们可以通用地检查函数对象的某些属性:如 .__name__ 属性、 .__code__ 属性
可以向函数对象附加任意的用户自定义属性,如 func.count=0 。这样的属性可以用来直接将状态信息附加到函
数对象上
Python3中,可以给函数对象附加注解。注解不作任何事情,而且注解是可选的,它被附加在函数对象
的 .__annotaions__ 属性中。注解的格式为:
lambda 表达式返回一个值(一个新的函数对象),可以将它手动赋值给一个变量名
def 总是将一个新的函数对象自动赋值给一个变量名(函数名)
lambda 内部甚至不能使用 if 语句
lambda 表达式也能使用默认实参
lambda 表达式主体中遵循 def 内一样的名字作用域查找法则
本文档使用 书栈(BookStack.CN) 构建 - 62 -
20. 函数的高级特性
6.Python是静态检测局部变量的:
1. x='global'
2. def func():
3. print(x)
4. x=3
即只要有局部变量的定义,无论在函数内哪个地方,其作用域都是本局部作用域全域
7.Python在内部会将每个默认实参保存成对应的对象,附加在这个函数本身。在不同的函数调用期间,这些默认实参
会保存同一个对象。因此对于可变对象作为默认实参注意保持警惕。
本文档使用 书栈(BookStack.CN) 构建 - 63 -
21. 模块
模块
1.从实际角度,模块对应Python程序文件(或者用外部语言如C|C#编写的扩展)。从逻辑上看,模块是最高级别的
程序组织单元
每个Python程序文件都是一个模块
模块导入另一个模块后,可以直接使用被导模块定义的全局变量名
2.Python程序是作为一个主体的、顶层文件来构造,配合零个或者多个支持的模块文件
3.Python自带了很多模块,称为标准链接库。他们提供了很多常用功能
找到模块文件
编译成字节码(即 .pyc 文件)。如果字节码文件不存在或者字节码文件比源代码文件旧,
则执行该步骤。否则跳过该步骤直接加载字节码
执行模块代码来创建其定义的对象
在这之后导入相同模块时,会跳过这三步而只是提取内存中已经加载的模块对象。
顶层文件通常设计成直接执行,而不是被导入的
6.Python模块文件搜索路径:
程序主目录
环境变量 PYTHONPATH 指定的目录
标准链接库目录(这个一般不动它)
任何 .pth 文件的内容,其中 .path 文件在前三者中查找到的。
Python会将每个 .pth 文件的每行目录从头到尾添加到 sys.path 列表的最后
(在此期间Python会过滤 .pth 文件中目录列表中重复的和不存在的目录)
7. sys.path 列表就是模块的搜索路径。Python在程序启动时配置它,自动将顶级文件的主目录(或代表当前工作
目录的一个空字符串)、环境变量 PYTHONPATH 指定的目录、标准库目录以及已创建的任何 .pth 文件的内容合并
本文档使用 书栈(BookStack.CN) 构建 - 64 -
21. 模块
可执行但不会被导入的顶层文件不必保存为.py文件
因为模块名在Python中会变成变量名,因此模块名必须遵守普通变量名的命名规则
有几点需要注意:
本文档使用 书栈(BookStack.CN) 构建 - 65 -
21. 模块
from 语句可能破坏命名空间
from 后跟随 reload 时, from 导入的变量名还是原始的对象
在Python内部,模块命名空间是作为字典对象存储的
我们在模块文件中赋值的变量名在Python内部称为命名空间字典的键
15.一个模块内无法使用其他模块内的变量,除非明确地进行了导入操作
reload 函数可以修改程序的一部分,而无需停止整个程序
reload 函数只能用于Python编写的模块,而无法用于其它语言编写的扩展模块
reload 并不会删除并重建模块对象,它只是修改模块对象。即原来模块的每个属性对象内存空间还在,所有旧
的引用指向他们,新的引用指向修改后的属性对象内存空间
reload 会在模块当前命名空间内执行模块文件的新代码
reload 会影响所有使用 import 读取了模块的用户,用户会发现模块的属性已变
reload 只会对以后使用 from 的代码造成影响,之前用 from 的代码并不受影响。之前的名字还可用,且引用
的是旧对象
本文档使用 书栈(BookStack.CN) 构建 - 66 -
22. 模块包
模块包
1. import 时,也可以指定目录。目录称为包,这类的导入称为包导入。
包导入是将计算机上的目录变成另一个Python命名空间,它的属性对应于目录中包含的子目录和模块文件
包导入的语法:
1. import dir1.dir2.modname
2. from dir1.dir2.modname import x
__init__.py 就像普通模块文件,它可以为空的
Python首次导入某个目录时,会自动执行该目录下 __init__.py 文件的所有程序代码
import dir1.dir2.modname 包导入后,每个目录名都成为模块对象
(模块对象的命名空间由该目录下的 __init__.py 中所有的全局变量定义
(包含显式定义和隐式定义)决定)
__init__.py 中的全局变量称为对应目录包的属性
本文档使用 书栈(BookStack.CN) 构建 - 67 -
23. 模块高级用法
模块高级用法
1.Python模块会默认导出其模块文件顶层所赋值的所有变量名,不存在私有变量名。所有的私有数据更像是一个约
定,而不是语法约束:
使用 __name__ 最常见的是用于自我测试代码:在文件末尾添加测试部分:
1. if __name__=='__main__':
2. #pass
这种方法速度较快
本文档使用 书栈(BookStack.CN) 构建 - 68 -
23. 模块高级用法
6. reload(modname) 只会重载模块 modname ,而对于模块 modname 文件中 import 的模块, reload 函数不会自
动加载。
要想 reload 模块 A 以及 A import 的所有模块,可以手工递归扫描 A 模块的 __dict__ 属性,并检查每
一项的 type 以找到所有 import 的模块然后 reload 这些模块
7.可以通过下列几种办法获取模块的某个属性:
modname.attr :直接通过模块对象访问
modname.__dict__['attr'] :通过模块对象的 __dict__ 属性字典访问
sys.modules['modname'].name :通过Python的 sys.modules 获取模块对象来访问
getattr(modname,'attr') :通过模块对象的 .getattr() 方法来访问
本文档使用 书栈(BookStack.CN) 构建 - 69 -
24. 类 class
类 class
1.Python中,类 class 与实例 instance 是两种不同的对象类型
类对象是实例对象的工厂
类对象与实例对象都有各自独立的命名空间
类对象来自于类定义语句,实例对象来自于函数调用语句
实例对象可自动存取类对象中的变量名
2.类的定义:
1. class class_name:
2. name1=val
3. def method(self):
4. pass
类属性为所有的实例对象提供状态和行为,它是由该类创建的所有实例对象共享的
3.生成实例对象:
1. instance_name=class_name()
像函数那样调用类对象会创建新的实例对象。
每次调用时,均会返回新的实例对象
每个实例对象都有自己的命名空间。同一个类的实例对象不一定属性都相同
每一个实例对象继承类的属性并创建了自己的命名空间
类创建的实例对象是有新的命名空间。刚开始该命名空间是空的,
但它会继承创建该实例所属类对象的属性。
继承的意思是,虽然实例对象的命名空间是空的。
但是名字查找会自动上升到类对象的名字空间去查找
可以通过方法调用: instance_name.func()
也可以通过类调用: class_name.func(instance_name)
本文档使用 书栈(BookStack.CN) 构建 - 70 -
24. 类 class
1. classA.attr=val
1. a=classA()
2. a.attr=val
6.类可以继承。被继承的类称为超类,继承类称为子类。
本文档使用 书栈(BookStack.CN) 构建 - 71 -
24. 类 class
2. pass
类对象会继承其超类对象中定义的所有类属性名称。读属性时,若该属性不存在于本类中,Python会自动在超
类的命名空间中寻找
若是写属性,则会创建新属性(此时仅操作本类的命名空间)
实例对象会继承所有可访问到的类的属性。读变量名时,Python会首先检查实例的命名空间,然后是类的命名
空间,最后是沿继承链查找所有超类的命名空间
若子类重新定义了超类的变量名(无论是在 class 内部定义,还是在 class 外部通过赋值来定义),子类会取
代并定制所继承的行为。这称为重载
本文档使用 书栈(BookStack.CN) 构建 - 72 -
24. 类 class
10.Python的继承与C++继承不同。在Python中,当对象通过点号运算读取属性值时就会发生继承,而且涉及了搜索
属性定义树。
1. graph BT;
2. A(实例命名空间)-->B[类命名空间];
3. B-->C[超类1命名空间];
4. B-->D[超类2命名空间];
5. style A fill:#f9f,stroke:#333;
11.类对象与实例对象都是内存中的临时对象。可以通过对象持久化来把他们保存在磁盘中。
pickle 模块:通用的对象序列化与反序列化工具。它可以将任何对象转换为字节串,以及将该字节串在内存
中重建为最初的对象。 pickle 常用接口为:
序列化:
pickle.dump(obj, file, protocol=None, *, fix_imports=True) : 将 obj 对象序列化并写入 file 文
件对象中
pickle.dumps(obj, protocol=None, *, fix_imports=True) :将 obj 对象序列化并返回对应的字节串对
象(并不写入文件中)
本文档使用 书栈(BookStack.CN) 构建 - 73 -
24. 类 class
反序列化:
dbm 模块:一个可以通过键访问的文件系统.它的键、值都是字节串或者字符串。它以类似字典的方式访问
(但是首先要 open )。
存取语法
存储的语法:
1. import shelve
2. db=shelve.open('filename') #打开
本文档使用 书栈(BookStack.CN) 构建 - 74 -
24. 类 class
5. db.close() #关闭
读取的语法:
1. import shelve
2. db=shelve.open('filename') #打开
3. for key in db:#像字典一样访问
4. print(key,'=>',db[key]) #读取
5. db.close() #关闭
优缺点:
13.类可以有文档字符串。文档字符串是位于各种结构顶部的字符串常量。
文档字符串在运行时能保持
可以通过 .__doc__ 属性获取
本文档使用 书栈(BookStack.CN) 构建 - 75 -
25. Python命名空间
Python命名空间
1.有点号和无点号的变量名,会使用不同的方式处理
2.模块、类、实例对象的命名空间实际上是以字典的形式实现的,并由内置属性 .__dict__ 表示
属性点号运算其实内部就是字典的索引运算
属性继承其实就是搜索链接的字典
每个实例都有各自独立的命名空间字典。初始时为空字典。
随着对 self 或者对象的属性赋值,命名空间字典不断扩张
3.读取属性可以通过点运算符或者直接通过键索引:
1. obj.attr #通过点运算符
2. obj.__dict__['attr']#通过键索引
通过键索引时必须给出属性名字符串;通过点运算符时给出的是属性名(不是字符串)
4. dir 函数可以输出对象的所有可访问属性,包括它继承的名字(以及其他一些内置的系统属性)
本文档使用 书栈(BookStack.CN) 构建 - 76 -
26. 运算符重载
运算符重载
1.运算符重载只是意味着在类方法中拦截内置的操作
运算符重载让类拦截常规的Python运算
类可以重载所有的Python表达式运算符。当实例对象作为内置运算符的操作数时,这些方法会自动调用
类也可以重载打印、函数调用、属性点号运算符等内置运算
重载可以使得实例对象的行为更像内置类型
重载运算符通常并不是必须的,也不是默认的行为
2.Python中所有可以被重载的方法名称前、后均有两个下划线字符,以便将它与其他类内定义的名字区分开来,
如 __add__
3.若使用未定义运算符重载方法,则它可能继承自超类。若超类中也没有则说明你的类不支持该运算,强势使用该运
算符则抛出异常
本文档使用 书栈(BookStack.CN) 构建 - 77 -
26. 运算符重载
.__setitem(self,index,value) 方法类似地拦截索引赋值和分片赋值。第一个参数为实例对象,第二个参数为基
本索引或者分片对象,第三个参数为值
6. .__index__(self) 方法:该方法将实例对象转换为整数值。即当要求整数值的地方出现了实例对象时自行调用。
本文档使用 书栈(BookStack.CN) 构建 - 78 -
26. 运算符重载
.__iter__(self) 方法必须返回一个迭代器对象。Python的迭代环境通过重复调用这个迭代器对象
的 .__next__(self) 方法,直到发生了 StopIteration 异常
.__iter__(self) 返回的迭代器对象会在调用 .__next__(self)
本文档使用 书栈(BookStack.CN) 构建 - 79 -
26. 运算符重载
每个激活状态下的迭代器都有自己的状态信息,而不管其他激活状态下的迭代器
本文档使用 书栈(BookStack.CN) 构建 - 80 -
26. 运算符重载
于 .__getitem__(self,index) 方法采纳
当Python可以从继承树中找到该属性名时,并不会调用 .__getattr__(self,'name') 方法
属性不仅仅是变量名,也可以是方法名
本文档使用 书栈(BookStack.CN) 构建 - 81 -
26. 运算符重载
对于属性赋值语句,因为如果该属性曾经不存在,则一旦赋值就增加了一个新的属性
属性不仅仅是变量名,也可以是方法名
属性不仅仅是变量名,也可以是方法名
本文档使用 书栈(BookStack.CN) 构建 - 82 -
26. 运算符重载
属性不仅仅是变量名,也可以是方法名
本文档使用 书栈(BookStack.CN) 构建 - 83 -
26. 运算符重载
本文档使用 书栈(BookStack.CN) 构建 - 84 -
26. 运算符重载
17.加法有三种:
当不同类的实例对象混合出现在 + 两侧时,Python优先选择左侧的那个类来拦截 +
注意当在这三种加法函数体内出现了 + 或者 += 时可能出现递归调用
本文档使用 书栈(BookStack.CN) 构建 - 85 -
26. 运算符重载
18.每个二元运算符都有类似 + 的右侧和原地重载方法。他们以相似的方式工作。
右侧方法通常只有在需要满足交换律时用得到,一般较少使用
在实现这些方法时,函数体内注意不要出现递归调用
.__call__(self,*pargs,**kwargs) 方法支持所有的参数传递方式
本文档使用 书栈(BookStack.CN) 构建 - 86 -
26. 运算符重载
本文档使用 书栈(BookStack.CN) 构建 - 87 -
26. 运算符重载
Python的析构函数不常用。原因有二:
对于空间管理来说,通常不需要用户手动管理
用户无法预测实例对象的具体回收时机,这个时机有Python自动调度
本文档使用 书栈(BookStack.CN) 构建 - 88 -
27. 类的设计模式
类的设计模式
1.Python不会执行同名函数的重载,而只会用新对象覆盖旧对象
1. class A:
2. def func(self,x):
3. pass
4. def func(self,x,y):
5. pass
代理类可以有被包装对象的借口,且自己还可以有其他接口
该做法常用于避免实例中潜在的变量名冲突
本文档使用 书栈(BookStack.CN) 构建 - 89 -
27. 类的设计模式
4.Python3中,实例方法有两种形式:
若调用的是一般的方法,则遵守普通函数调用规则即可 classname.func(arg)
绑定方法调用时,不需要手动传入实例对象,如 obj.func(arg)
子类与其实例继承了列出的所有超类的命名空间
本文档使用 书栈(BookStack.CN) 构建 - 90 -
27. 类的设计模式
6.工厂函数:通过传入类对象和初始化参数来产生新的实例对象:
1. def factory(classname,*args,**kwargs):
2. return classname(*args,**kwargs)
7.抽象超类:类的部分行为未定义,必须由其子类提供
若子类也未定义预期的方法,则Python会引发未定义变量名的异常
类的编写者也可以用 assert 语句或者 raise 异常来显式提示这是一个抽象类
1. class A:
2. def func(self):
3. self.act() #该方法未实现
4. def act(self):
5. assert False, 'act must be defined!'
6. class ChildA(A):
7. def act(self):
8. print('in ChildA act')
本文档使用 书栈(BookStack.CN) 构建 - 91 -
27. 类的设计模式
9. x=child()
10. x.func()
本文档使用 书栈(BookStack.CN) 构建 - 92 -
28. 类的高级主题
类的高级主题
1.通过在自定义类中嵌入内置类型,类似委托;这样自定义类就可以实现内置类型的接口。
这些接口在内部通过操作嵌入的内置类型来实现。
这是一种扩展内置类型的方式
内置类型的子类实例可以用于内置类型对象能够出现的任何地方
3.在Python3中所有的类都是新式类。
Python2.2之前的类不是新式类
本文档使用 书栈(BookStack.CN) 构建 - 93 -
28. 类的高级主题
.__slots__ 属性的使用可以优化内存和读取速度
在继承中:
没有意义。因为子类继承了超类的 .__dict__ 属性
本文档使用 书栈(BookStack.CN) 构建 - 94 -
28. 类的高级主题
1. class A:
2. age=property(getMethod,setMethod,delMethod,docMethod)
3. # 或者直接指定docstring
4. def getMethod(self):
5. pass
6. def setMethod(self,val):
7. pass
8. def delMethod(self):
9. pass
11. ...
12. # return a string
本文档使用 书栈(BookStack.CN) 构建 - 95 -
28. 类的高级主题
一个添加了语法糖的方案为:
1. class A:
2. def __init__(self):
3. self._x = None
定义 staticmethod 方法:
1. class A:
2. @staticmethod #定义一个staticmethod
3. def func(*args,**kwargs)
4. pass
本文档使用 书栈(BookStack.CN) 构建 - 96 -
28. 类的高级主题
调用,则提取该实例所属的类对象)传入函数的第一个参数 cls 中
定义 classmethod 方法:
1. class A:
2. @classmethod #classmethod
3. def func(cls,*args,**kwargs)
4. pass
总结一下,类中可以定义四种方法:
普通方法:方法就是类对象的一个属性,执行常规函数调用语义 classname.method(args)
实例方法:传入一个实例作为方法的第一个实参。调用时可以:
obj.method(args) :通过实例调用
classname.method(obj,args) :通过类调用
staticmethod 方法:* obj.method(args) 通过实例调用时,执行的是 classname.method(args) 语义
本文档使用 书栈(BookStack.CN) 构建 - 97 -
28. 类的高级主题
8.类对象与实例对象都是可变对象,可以给类属性、实例属性进行赋值,这就是原地修改。这种行为会影响对它的多
处引用
任何在类层次所作的修改都会反映到所有实例对象中
9.若类的某个属性是可变对象(如列表、字典),则对它的修改会立即影响所有的实例对象
本文档使用 书栈(BookStack.CN) 构建 - 98 -
28. 类的高级主题
类的 .__mro__ 是动态的,当继承层次改变时它也随之改变
元类可以重写一个类的 .mro() 方法来定义该类的 __.mro__ 属性。该方法在类被创建时调用,结果存放在类
的 .__mro__ 属性中
有两种特殊用法:
1. def super(cls,instance):
2. mro=instance.__class__.__mro__ #通过 instance生成 mro
本文档使用 书栈(BookStack.CN) 构建 - 99 -
28. 类的高级主题
示例:
1. class Root:
2. def method1(self):
3. print("this is Root")
4. class B(Root):
5. def method1(self):
6. print("enter B")
7. print(self)
8. super(B,self).method1() #也可以简写为 super().method1()
9. print("leave B")
类的 classmethod 依次类推
异常
1.Python中,异常会根据错误自动地被触发,也能由代码主动触发和截获
2.捕捉异常的代码:
1. try:
2. statements #该代码执行主要的工作,并有可能引起异常
3. except ExceptionType1: #except子句定义异常处理,这里捕捉特定的ExceptionType1类型的异常
4. statements
5. except (ExceptionType2,ExceptionType3): #except子句定义异常处理,
6. #这里捕捉任何列出的异常(即只要是ExceptionType2类型或者ExceptionType3类型)
7. statements
3. try/finally 语句:
1. try:
2. statements
3. finally:
4. statements
1. try:
2. statements #该代码执行主要的工作,并有可能引起异常
11. statements
12. else: # 如果没有发生异常,这来到这里;当发生了异常则不执行else子句
13. statements
15. statements
finally 执行时机:无论有没有异常抛出,在程序跳出整体语句之前的最后时刻一定会执行
整体语句就是指上面的 try..except..else...finally
BaseException 类是所有内建异常的父类。
1. if __debug__:
2. if not <test>:
3. raise AssertionError(<data>)
通常 assert 用于给定约束条件,而不是用于捕捉程序的错误。
expression 必须返回一个对象,该对象必须支持环境管理协议。其工作方式为:
执行 statements 代码块
异常对象
1.Python3中,内置异常与用户自定义异常都是类的实例对象
3.Python中的内置异常类继承树:
1. graph BT
2. id1(OverflowError) -->|继承|id2(ArithmeticError)
3. id2 -->|继承|id3(Exception)
4. id4(IndexError) -->|继承|id3
5. id3-->|继承|id5(BaseException)
Exception 是所有内置异常类的超类。用户自定义的异常类都继承自它
4.自定义异常类:通常继承自 Exception 类
若想自定义打印显示,则必须重写 .__str__(self) 方法
异常的传递:向上返回到先前进入但是尚未离开的 try
6.Python中所有的错误都是异常。但是并非所有的异常都是错误
7.用户自定义的异常可以用于触发信号条件。这是利用异常来传递信息的方法
8. try...finally 通常用于释放系统资源。虽然垃圾收集时资源会自动释放,但是垃圾收集的时机不可控,由算法自
动调度
type :异常类型
value :异常实例对象
空的 except 子句拦截任何异常,包括内存错误、系统推出、键盘中断等等
但是太具体化不利于扩展
Unicode与字节串
1.字符编码:
2. Unicode 文本通常叫做“宽字符”字符串,因为每个字符可能表示为多个字节
有些编码对应多个不同的名称
5.Python3中有三种字符串相关类型:
7.Python3中,当一个文件以文本模式打开时,读取其数据会自动将其内容解码,并返回一个字符串;当一个文件以
文本模式写打开时,写入一个字符串会在将该字符串写入文件之前自动编码它。
编码和解码的类型是系统的平台默认编码类型,或者你手动设定的编码类型
根据编码类型,Python自动处理文件起始处的字节标记序列(通常用于标记文件编码类型)
Python自动对行尾换行符转换。在windows下,换行符 \n 在写入文件时转换为windows下的换行符 \r\n 。
在读取文件时windows下的换行符 \r\n 转换为标准换行符 \n
当一个文件以二进制模式打开时,读取其数据直接返回其原生内容而并不以任何方式解码,也不做任何方式修改(即
不转换换行符),直接作为 bytes 实例返回;写入会接受一个 bytes 实例或者一个 bytearray 实例,并且不加修
改地写入到文件(即不转换换行符)
尽管 bytes 打印出来是字符串(若无对应的字符则输出内存表示),但它本质上是一个小整数序列
Python3中所有字符串都是Unicode字符(是ASCII字符的超集)
10.Python的字符串常量支持:
'\uNNNN' :双字节字符,16位
'\UNNNNNNNN' :4字节字符,32位
这里的 N 均为十六进制整数的一个整数位[0~F]
11.编解码ASCII字符非常简单,无需显示指定编解码类型(当然你可以随意指定一个编解码类型,因为ASCII编码是
任何编码类型的子集)
编解码非ASCII字符则要注意,对该字符的编码类型必须与解码类型一致,否则乱码或者抛出 UnicodeDecodeError 。
14.指定Python源文件字符集编码声明:在脚本的第一行写入:
bytearray('abc',encoding='ascii') :通过构造函数传入字符串和编码构造
1. 作者:华校专
2. email: [email protected]
3. ** 本文档可用于个人学习目的,不得用于商业目的 **
管理属性
1.管理属性的工具
1. class A:
2. def fget(...):
3. pass
4. def fset(...):
5. pass
6. def fdel(...):
7. pass
8. attribute=property(fget,fset,fdel,"doc") #必须在fget,fset,fdel之后定义
9. a=A()
3.描述符:描述符是作为独立的类创建,它的实例是赋值给了类属性
描述符的实例可以由子类继承
描述符的实例管理一个单一的特定的属性
从技术上讲, property() 创建的是一个描述符实例( property 实例)
描述符实例针对想要拦截的属性名访问操作,它提供了特定的方法
描述符类的接口为(即描述符协议):
1. class Descriptor:
2. '''
3. This is docstring
4. '''
5. def __get__(self,instance,owner):
6. pass
7. def __set__(self,instance,value):
8. pass
9. def __delete__(self,instance):
10. pass
11. class A:
12. attr=Descriptor()
13. ...
instance 参数为:
当访问类实例或者类属性时,自动调用该类的描述符实例的方法。如果该类的描述符中某些方法空缺则:
若 __set__(self,instance,value) 未定义,则写该属性抛出 AttributeError ,该属性只读
若 __get__(self,instance,owner) 未定义,则读该属性返回一个 Descriptor 实例,
因为从继承树中可知,该属性返回由类的 attr 变量名指定的对象
4. .__delattr__(self,name) 方法拦截属性的删除
6.Python3中,所有使用内置操作隐式的获取方法名属性(如 print(x) 用到
了 .__str__(self) ), .__getattr__(self,name) 、 .__setattr__(self,name,value) 、
.__getattribute__(self,name) 方法都不会拦截,因为Python在类中查找这样的属性,完全忽略了在实例中查找
7.属性拦截优先级:
面,
__del__ 优先级最高
装饰器
1.装饰器是用于包装其他可调用对象的一个可调用对象,它是一个可调用对象,其调用参数为另一个可调用对象<,它
返回一个可调用对象
一个函数对象是可调用对象。
一个类对象是可调用对象,对它调用的结果就是返回类的实例
装饰器有两种使用形式:
函数的装饰器:在函数对象定义的时候使用装饰器,用于管理该函数对象
类的装饰器:在类定义的时候使用该装饰器,用于管理该类以及类的实例
装饰器是装饰器模式的一个实现
2.函数的装饰器:用于管理函数。函数的装饰器声明为:
1. @decorator
2. def func(*pargs,**kwargs):
3. pass
1. def func(*pargs,**kwargs):
2. pass
3. func=decorator(func)
3.类的装饰器:用于管理类。类的装饰器声明为:
1. @decorator
2. class A:
3. pass
1. class A:
2. pass
3. A=decorator(A)
类的装饰器并不是拦截创建实例的函数调用,而是返回一个不同的可调用对象
3.装饰器只是一个返回可调用对象的可调用对象,它没有什么特殊的地方。
可以用函数实现装饰器:
2. #某些处理
3. return func #返回可调用对象
也可以用类来实现装饰器:
1. class decorator:
2. def __init__(self,func):
3. self.func=func
4. def __call__(self,*args,**kwargs):
5. return self.func
通常用嵌套类来实现装饰器:
2. def wrapper(*args):
3. #使用func或其他的一些工作
4.装饰器的嵌套:
函数的装饰器的嵌套:
1. @decoratorA
2. @decoratorB
3. @decoratorC
4. def func():
5. pass
等价于
1. def f():
2. pass
3. f=A(B(C(f)))
类的装饰器的嵌套:
1. @decoratorA
2. @decoratorB
3. @decoratorC
4. class M:
5. pass
等价于
1. class M:
2. pass
3. M=A(B(C(M)))
每个装饰器处理前一个装饰器返回的结果,并返回一个可调用对象
5.装饰器可以携带参数。
函数定义的装饰器带参数:它其实是一个嵌套函数。
外层函数的参数为装饰器参数,返回一个函数(内层函数)
内层函数的参数为 func ,返回一个可调用参数,内层函数才是真正的装饰器
1. def decorator(*args,**kwargs):
2. print("this is decorator1:",args,kwargs)
5. return func
6. return actualDecorator
类定义的装饰器带参数:它其实是一个嵌套类。
外层类的初始化函数的参数为装饰器参数,外层类的 __call__ 函数的参数为 func ,返回值为一个类的
实例(内部类实例)
内层类的初始化函数参数为 func ;内层类的 __call__ 函数使用 func ,内层类才是真正的装饰器
1. class decorator2:
4. ...
5. self.func=func#记住func
6. def __call__(self,*args,**kwargs):
7. ...
12. ...
13. return decorator2.ActualDecorator(func)
总结:
6.利用装饰器可以实现单例模式:
1. def Singleton(cls):
2. instance=None
3. def onCall(*args,**kwargs):
4. nonlocal instance
5. if instance == None:
6. instance=cls(*args,**kwargs)
7. return instance
8. return onCall
9. @Singleton
10. class A:
11. pass
7.利用装饰器可以跟踪对象的调用接口,从而管理对实例的接口访问(如统计调用次数,打印调用日志)
1. def Tracer(cls):
2. class Wrapper:
3. def __init__(self,*args,**kwargs):
4. self.wrapped=cls(*args,**kwargs)
5. def __getattr__(self,name):
6. print('Trace:'+name)
7. return getattr(self.wrapped,name)
8. return Wrapper
9. @Tracer
10. class A:
11. pass
8.装饰器也可以直接管理函数和类,而不仅仅只是管理对他们的调用
利用装饰器添加函数和类到注册表:
1. register_dict={}
2. def register(obj):
3. register_dict[obj.__name__]=obj
4. return obj
5. @register
6. def func():
7. pass
利用装饰器为函数和类添加属性
1. def register(obj):
2. obj.label=0
3. return obj
4. @register
5. def func():
6. pass
元类
1.元类是一种特殊的类,它用于创建类。元类机制允许我们在一条 class 语句的末尾自动插入某些逻辑。它在类对
象创建时运行,是管理和扩展类的钩子。元类不是管理类的实例,而是管理类本身
2.尽管类的装饰器通常用来管理或者扩展类实例,但是他们也可以用于管理和扩展类对象本身,也与元类的功能重叠
1. MyClass=type(classname,superclasses,attributedict) #新建了一个类,类名叫MyClass
2. # classname:类名,会成为MyClass类的 .__name__属性
3. # superclasses:类的超类元组,会成为MyClass类的 .__bases__属性
4. # attributedict:类的命名空间字典,会成为MyClass类的 .__dict__ 属性
5. # 这个语句也是动态创建类对象的方法
.__init__(customclass,classname,superclasses,attributedict) 方法,
它初始化新建的 MyClass 类
customclass :为被创建的类,这里是 MyClass 类
classname :为被创建的类的类名,这里是 'MyClass'
superclasses :为被创建的类的超类元组
attributedict :为被创建的类的名字空间字典
1. class MetaClass(type):
2. def __new__(mclass,classname,superclasses,attributedict):
3. return type.__new__(mclass,classname,superclasses,attributedict)
4. def __init__(customclass,classname,superclasses,attributedict):
5. return type.__init__(customclass,classname,superclasses,attributedict)
使用元类:
1. class MyClass(metaclass=MetaClass):
2. pass
继承的超类也列在括号中,但是要在元类之前,也用逗号分隔:
class MyClass(BaseCls1,BaseCls2,metaclass=MetaClass)
元类 MetaClass 要实现元类协议:
6.元类有的时候不一定是个真正的类,它也可能是一个函数。任何可调用对象都可以作为一个元类,只需要按照以下
的做法:
1. def MetaFactory(classname,superclasses,attributedict):
2. ...
5. pass
7.事实上元类只用于创建类对象,元类并不产生元类自己的实例。因此元类的名字查找规则有些不
同: .__call__ , .__new__ , .__init__ 方法均在类中查找
8.元类的继承:
元类声明由子类继承,即子类的构建也是由父类的元类负责
如果元类是以函数的方式声明,则子类的构建不再继承这个函数式元类
元类中的属性并不进入自定义类的命名空间,即元类中声明的一些类属性与被创建类的名字空间无关(他们是两
个不同的类)
1. 作者:华校专
2. email: [email protected]
3. ** 本文档可用于个人学习目的,不得用于商业目的 **
Python 执行细节
1.Python脚本执行时,Python内部会首先将源代码编译成字节码的形式。字节码是平台无关的。
字节码是平台无关的
如果Python进程拥有写入权限,则它会将脚本的字节码以一个 .pyc 为扩展名的文件。当脚本运行后你可以在
源代码所在的目录附近看到 .pyc 文件。
下一次运行脚本时,如果你在上次保存字节码之后没有修改源代码时,Python会自动加载 .pyc 文件并
跳过编译步骤
如果Python进程没有写入权限,则字节码会在内存中生成并在脚本执行结束后抛弃。
.pyc 文件也是发布Python程序的方法之一。此时并不需要提供 .py 源代码。