diff --git a/README.md b/README.md index c58c102..4730162 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,81 @@ -# python_learning_notes +# python 学习笔记 + +本文档是《learning python》中文第四版的学习笔记,是由我个人做的纸质读书笔记而来。 -《learning python》中文第四版的学习笔记,由纸值文档转换而来。看这份笔记的时候最好有 C|C++ 的经验。这份笔记的特点: +另:本人搜集了个人笔记并整理成册,命名为《AI算法工程师手册》,详见:www.huaxiaozhuan.com -1. 减少了《learning python》这本书里面很多罗哩罗嗦的话,是一份总结 +>* 文档PDF版本可能会滞后于项目进度 +>* 纸质笔记可以从百度网盘下载:http://pan.baidu.com/s/1miEkaBu +>* 个人所作的所有笔记也可以从百度网盘下载:http://pan.baidu.com/s/1boSzlx1 + + ![文档截图](imgs/picture_all.JPG) + +# 目标 +这份笔记的目标是为了给出一份比较精炼,但是又要浅显易懂的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. 异常对象 +32. Unicode与字节串 +32. 管理属性 +33. 装饰器 +34. 元类 +35. Python的执行 + +# 基础知识 +看这份笔记最好有面向对象的概念。因为这份文档里大量使用了面向对象的术语,比如”实例对象“、”类对象“、”名字空间“等等。如果没有面向对象的概念,将会对理解后面的大部分章节有困难。 + +对于Python新手,这份文档难度不大。但是如果您对Python有一定的熟练程度,您会发现这份文档行云流水,一气呵成,阅读起来就没有停顿感。如果您对于Python完全陌生,那么本文档阅读过程中,对于一些复杂的概念建议您动手练手而不要完全依赖于文档中的示例。 + +# 补充 + +* 本文档所有的Python代码都是基于Python 3.5 64bit,在Python IDLE上运行的效果。操作系统为 Win7 64bit Professional + +* 本文档由` markdown` 语法制作而成,其中使用到了扩展的非标准`markdown`语法(流程图功能)。本人制作了一份`markdown`教程,项目地址在:https://github.com/huaxz1986/markdown_documentation_chinese .你也可以在百度网盘下载PDF版本:http://pan.baidu.com/s/1qWXaJRA +* 本文档编辑器使用`cutemarked`软件。它是一款开源的`markdown`文件编辑器,支持流程图扩展与`LATEX`数学公式扩展。本人fork了一个版本,然后改装成了一个本地化版本,项目地址: https://github.com/huaxz1986/CuteMarkEd 。你也可以在百度网盘下载我编译打包好的版本(解压缩直接双击运行即可),地址:http://pan.baidu.com/s/1dEqupZ7 ,运行环境为 Win7 64bit Professional +>`cutemarked`原版需要联网下载所需要的脚本文件,但是由于国内的网络问题,以及存在断网情况下使用等特殊需求 +>,我将它改造成了一个无需联网的本地化版本 + + **本文档仅用于个人学习目的,未经许可不得用于商业目的,转载请注明出处** + + **email: huaxz1986@163.com** -2. 对于大多数的条款,都给出了 Python IDLE 运行效果。其中运行环境为: - * win7 64bit professional - * Python 3.5 64 bit -![Python笔记特点](imgs/picture_notes.JPG) diff --git a/chapter/10_python_syntax.md b/chapter/10_python_syntax.md index 3ab64aa..62af650 100644 --- a/chapter/10_python_syntax.md +++ b/chapter/10_python_syntax.md @@ -1,3 +1,8 @@ + # 语句和语法 1.所有Python的复合语句,都是以冒号`:`结尾,下一行缩进开始进入代码块。同一个级别代码块的缩进形式相同 diff --git a/chapter/11_python_assignment.md b/chapter/11_python_assignment.md index 4f278fa..942c254 100644 --- a/chapter/11_python_assignment.md +++ b/chapter/11_python_assignment.md @@ -1,3 +1,8 @@ + # 赋值语句 1.赋值的左侧可以为变量名或者对象元素,右侧为任何表达式 diff --git a/chapter/12_python_print.md b/chapter/12_python_print.md index 9453936..509ea8f 100644 --- a/chapter/12_python_print.md +++ b/chapter/12_python_print.md @@ -1,3 +1,8 @@ + # 打印 1.打印`print`类似于文件`.write()`方法,它将默认地把对象打印到`stdout`流中。它会自动添加一些自动化的格式。 > 和文件的`.write()`方法不同的是,`print`不需要将对象转换为字符串 diff --git a/chapter/13_python_if.md b/chapter/13_python_if.md index f79e308..277a406 100644 --- a/chapter/13_python_if.md +++ b/chapter/13_python_if.md @@ -1,3 +1,8 @@ + # `if`语句 1.`if`语句的的通用格式: diff --git a/chapter/14_python_loop.md b/chapter/14_python_loop.md index 157985a..dca5470 100644 --- a/chapter/14_python_loop.md +++ b/chapter/14_python_loop.md @@ -1,3 +1,8 @@ + # `while`、`for`循环 1.`while`语句格式: diff --git a/chapter/15_python_iterator.md b/chapter/15_python_iterator.md index 8616026..b28899e 100644 --- a/chapter/15_python_iterator.md +++ b/chapter/15_python_iterator.md @@ -1,3 +1,8 @@ + # 迭代器和生成器 1.可迭代对象:在逻辑上它保存了一个序列,在迭代环境中依次返回序列中的一个元素值。 >可迭代对象不一定是序列,但是序列一定是可迭代对象 diff --git a/chapter/16_python_doc.md b/chapter/16_python_doc.md index 5aa502d..8d8c3b0 100644 --- a/chapter/16_python_doc.md +++ b/chapter/16_python_doc.md @@ -1,3 +1,8 @@ + # 文档 1.`#`是注释符,它之后的文字到行尾均为注释。Python解释器会忽略`#`之后的所有字符 diff --git a/chapter/17_python_function.md b/chapter/17_python_function.md index 5927d8c..60c4960 100644 --- a/chapter/17_python_function.md +++ b/chapter/17_python_function.md @@ -1,3 +1,8 @@ + # 函数 1.Python的函数是由`def`语句编写。Python中,函数也是一种对象类型 diff --git a/chapter/18_python_scope.md b/chapter/18_python_scope.md index bd3b6a2..7e77f3e 100644 --- a/chapter/18_python_scope.md +++ b/chapter/18_python_scope.md @@ -1,3 +1,8 @@ + # 作用域 1.代码中变量名被赋值的位置决定了这个变量名的作用域(即可见范围)。因为变量是在首次赋值的时候定义的。 diff --git a/chapter/19_python_arguments.md b/chapter/19_python_arguments.md index aa430af..4c77b19 100644 --- a/chapter/19_python_arguments.md +++ b/chapter/19_python_arguments.md @@ -1,3 +1,8 @@ + # 参数 1.参数传递的性质: diff --git a/chapter/1_python_type_introduction.md b/chapter/1_python_type_introduction.md index a80332f..d0290a9 100644 --- a/chapter/1_python_type_introduction.md +++ b/chapter/1_python_type_introduction.md @@ -1,3 +1,8 @@ + # Python 的动态类型介绍 1.在Python中没有变量的声明以及变量的类型: diff --git a/chapter/20_python_function_more.md b/chapter/20_python_function_advanced.md similarity index 96% rename from chapter/20_python_function_more.md rename to chapter/20_python_function_advanced.md index b0f2ef5..dda00bf 100644 --- a/chapter/20_python_function_more.md +++ b/chapter/20_python_function_advanced.md @@ -1,3 +1,8 @@ + # 函数的高级特性 1.在Python中,函数的递归通常比`for`循环要慢而且空间消耗大,但是递归的优点是可以遍历任意形状的结构。 diff --git a/chapter/21_python_module.md b/chapter/21_python_module.md index a608c91..9f94832 100644 --- a/chapter/21_python_module.md +++ b/chapter/21_python_module.md @@ -1,3 +1,8 @@ + # 模块 1.从实际角度,模块对应Python程序文件(或者用外部语言如C|C#编写的扩展)。从逻辑上看,模块是最高级别的程序组织单元 diff --git a/chapter/22_python_package.md b/chapter/22_python_package.md index 2edbb4b..66931fd 100644 --- a/chapter/22_python_package.md +++ b/chapter/22_python_package.md @@ -1,3 +1,8 @@ + # 模块包 1.`import`时,也可以指定目录。目录称为包,这类的导入称为包导入。 diff --git a/chapter/23_python_module_more.md b/chapter/23_python_module_advanced.md similarity index 94% rename from chapter/23_python_module_more.md rename to chapter/23_python_module_advanced.md index 98a1ec7..2117c80 100644 --- a/chapter/23_python_module_more.md +++ b/chapter/23_python_module_advanced.md @@ -1,4 +1,9 @@ -# 高级模块用法 + +# 模块高级用法 1.Python模块会默认导出其模块文件顶层所赋值的所有变量名,不存在私有变量名。所有的私有数据更像是一个约定,而不是语法约束: * 下划线开始的变量名`_x`:`from *`导入该模块时,这类变量名不会被复制出去 diff --git a/chapter/24_python_class.md b/chapter/24_python_class.md index 172b700..23a7377 100644 --- a/chapter/24_python_class.md +++ b/chapter/24_python_class.md @@ -1,3 +1,8 @@ + # 类 class 1.Python中,类`class`与实例`instance`是两种不同的对象类型 diff --git a/chapter/25_python_namespace.md b/chapter/25_python_namespace.md index cbae04b..7c486c4 100644 --- a/chapter/25_python_namespace.md +++ b/chapter/25_python_namespace.md @@ -1,3 +1,8 @@ + # Python命名空间 1.有点号和无点号的变量名,会使用不同的方式处理 diff --git a/chapter/26_python_operator.md b/chapter/26_python_operator.md new file mode 100644 index 0000000..53bfa58 --- /dev/null +++ b/chapter/26_python_operator.md @@ -0,0 +1,174 @@ + +# 运算符重载 +1.运算符重载只是意味着在类方法中拦截内置的操作 + +* 运算符重载让类拦截常规的Python运算 +* 类可以重载所有的Python表达式运算符。当实例对象作为内置运算符的操作数时,这些方法会自动调用 +* 类也可以重载打印、函数调用、属性点号运算符等内置运算 +* 重载可以使得实例对象的行为更像内置类型 +* 重载运算符通常并不是必须的,也不是默认的行为 + + ![运算符重载](../imgs/python_26_1.JPG) + +2.Python中所有可以被重载的方法名称前、后均有两个下划线字符,以便将它与其他类内定义的名字区分开来,如`__add__` + +3.若使用未定义运算符重载方法,则它可能继承自超类。若超类中也没有则说明你的类不支持该运算,强势使用该运算符则抛出异常 + + ![运算符重载](../imgs/python_26_2.JPG) + +4.`.__init__(self,args)`方法:称为构造函数。当新的实例对象构造时,会调用`.__init__(self,args)`方法。它用于初始化实例的状态 + + ![运算符重载](../imgs/python_26_3.JPG) + +5.`.__getitem__(self,index)`和`.__setitem(self,index,value)`方法: + +* 对于实例对象的索引运算,会自动调用`.__getitem__(self,index)`方法,将实例对象作为第一个参数传递,方括号内的索引值传递给第二个参数 + +* 对于分片表达式也调用`.__getitem__(self,index)`方法。实际上分片边界如`[2:4]`绑定到了一个`slice`分片对象上,该对象传递给了`.__getitem__`方法。 + 对于带有一个`.__getitem__`方法的类,该方法必须既能针对基本索引(一个整数),又能针对分片调用(一个`slice`对象作为参数) +* `.__setitem(self,index,value)`方法类似地拦截索引赋值和分片赋值。第一个参数为实例对象,第二个参数为基本索引或者分片对象,第三个参数为值 + + ![重载索引和分片](../imgs/python_26_4.JPG) + +6.`.__index__(self)`方法:该方法将实例对象转换为整数值。即当要求整数值的地方出现了实例对象时自行调用。 + + ![重载对象转整数](../imgs/python_26_5.JPG) + +7.`.__getitem__(self,index)`也是Python的重载迭代方式之一。一旦定义了这个方法,`for`循环每一次循环时可以调用`.__getitem__(self,index)`方法。因此任何响应了索引运算的内置或者用户自定义的实例对象通用可以响应迭代。 + +* `for`可以检测到超出边界异常`IndexError`,从而终止迭代 + + ![.__getitem__用于迭代](../imgs/python_26_6.JPG) + +8.目前Python的所有迭代环境都会首先尝试调用`.__iter__(self)`方法,再尝试调用`.__getitem__(self,index)`方法。 + +* `.__iter__(self)`方法必须返回一个迭代器对象。Python的迭代环境通过重复调用这个迭代器对象的`.__next__(self)`方法,直到发生了`StopIteration`异常 + * `.__iter__(self)`返回的迭代器对象会在调用`.__next__(self)` + 的过程中明确保留状态信息,因此比`.__getitem__(self,index)`方法具有更好的通用性 + * 迭代器对象没有重载索引表达式,因此不支持随机的索引运算 + * `.__iter__(self)`返回的迭代器只能顺序迭代一次。 + 因此每次要进行新的一轮循环时必须创建一个新的迭代器对象 +* 对于调用`.__getitem__(self,index)`的环境,Python的迭代环境通过重复调用该方法,其中`index`每轮迭代中从 0 依次递增,直到发生了`IndexError`异常 + + ![Python迭代环境原理](../imgs/python_26_7.JPG) + +9.要让实例对象支持多个迭代器,`.__iter__(self)`方法必须创建并返回新的迭代器对象。 +>每个激活状态下的迭代器都有自己的状态信息,而不管其他激活状态下的迭代器 + + ![实例安装多个迭代器](../imgs/python_26_8.JPG) + +10.类通常把`in`成员关系运算符实现为一个迭代,用`.__iter__(self)`方法或`.__getitem__(self,index)`方法。也能实现`.__contains__(self,value)`方法来实现特定成员关系。 + +* `.__contains__(self,value)`方法优先于`.__iter__(self)`方法,`.__iter__(self)`方法优先于`.__getitem__(self,index)`方法采纳 + + ![in 运算符的实现原理](../imgs/python_26_9.JPG) + +11.`.__getattr__(self,'name')`方法:拦截属性点号运算`obj.name`。只有当对未定义(即不存在)的属性名称进行点号运算时,实例对象会调用此方法 +> 当Python可以从继承树中找到该属性名时,并不会调用`.__getattr__(self,'name')`方法 +> +>属性不仅仅是变量名,也可以是方法名 + +* 内置的`getattr(obj,'name')`函数等价于调用`obj.name`,它执行继承搜索。搜不到时调用`.__getattr__(self,“name”)`方法 +* 如果没有定义`.__getattr__(self,“name”)`方法,则对于不知道如何处理的属性(即找不到的),则Python抛出内置的`AttributeError`异常 + + ![重载.__getattr__方法](../imgs/python_26_10.JPG) + +12.`.__setattr__(self,'name',value)`方法:拦截所有的属性赋值语句(无论该属性名是否存在) +> 对于属性赋值语句,因为如果该属性曾经不存在,则一旦赋值就增加了一个新的属性 +> +> 属性不仅仅是变量名,也可以是方法名 + +注意:`.__setattr__(self,'name',value)`方法的函数体内,任何对`self`属性赋值语句(`self.name=value`)都会再次递归调用`.__setattr__(self,'name',value)`函数 + +* 为了防止`.__setattr__(self,'name',value)`函数体内的无穷递归,在该方法内的`self`属性赋值要采用属性字典索引的方法:`self.__dict__['name']=value` +>属性不仅仅是变量名,也可以是方法名 + +* 内置的`setattr(obj,'name',value)`函数等价于调用`obj.name=value` + + ![重载.__setattr__方法](../imgs/python_26_11.JPG) + +13.`.__getattribute__(self,'name')`方法:拦截所有的属性读取,而不仅仅是那些未定义的。 +注意:`.__getattribute__(self,'name')`方法的函数体内,任何对`self`属性读取语句(`self.name`)都会再次递归调用`.__getattribute__(self,'name')`函数。尽量不要重载`.__getattribute__(self,'name')`方法避免无穷递归 +>属性不仅仅是变量名,也可以是方法名 + + ![重载.__getattribute__方法](../imgs/python_26_12.JPG) + + ![.__getattribute__方法递归调用](../imgs/python_26_13.JPG) + +14.通过`.__getattr__`与`.__setattr__`方法混合使用可以模拟实例对象的私有属性: + +* 实例对象保存一个`self.private`变量名列表 +* 对`.__setattr__`与`.__getattr__`,判断属性名是否在`self.private`变量名列表中。 + 若是,则抛出异常 +> 对于通过`obj.__dict__['name']`访问,可以绕过这种机制 + +15.`.__add__(self,value)`方法:当实例对象在加法中时调用 + +16.`.__repr__(self)`和`.__str__(self)`方法:当实例对象在打印或者转成字符串时调用 + +* 打印会首先尝试`.__str__(self)`方法和`str(x)`内置函数。如果没有,则使用 + `.__repr__(self)`方法 +* `.__repr__(self)`主要应用于交互式下提示回应以及`repr`函数。如果没有,它不会调用 + `.__str__(self)`方法 + + ![重载.__repr__方法和.__str__方法](../imgs/python_26_14.JPG) + +17.加法有三种: + +* 常规加法:实例对象在`+`左侧,由`.__add__(self,value)`拦截 +* 右侧加法:实例对象在`+`右侧,由`.__radd__(self,value)`拦截 +* 原地加法:实例对西在`+=`左侧,由`.__iadd__(self,value)`拦截 + +要实现满足交换律的运算符,要同时重载`.__add__(self,value)`与`.__radd__(self,value)`方法。 + +* 当不同类的实例对象混合出现在`+`两侧时,Python优先选择左侧的那个类来拦截`+` + >注意当在这三种加法函数体内出现了`+`或者`+=`时可能出现递归调用 +* 原地`+=`优先采用`.__iadd__(self,value)`,如果它没有重载,则采用`.__add__(self,value)` + + ![三种加法](../imgs/python_26_15.JPG) + + ![三种加法注意事项](../imgs/python_26_16.JPG) + +18.每个二元运算符都有类似`+`的右侧和原地重载方法。他们以相似的方式工作。 + +* 右侧方法通常只有在需要满足交换律时用得到,一般较少使用 +* 在实现这些方法时,函数体内注意不要出现递归调用 + +19.`.__call__(self,*pargs,**kwargs)`方法:函数调用方法。当调用实例对象时,由`.__call__(self,*pargs,**kwargs)`方法拦截。 + +* `.__call__(self,*pargs,**kwargs)`方法支持所有的参数传递方式 + + ![重载函数调用.__call__方法](../imgs/python_26_17.JPG) + +20.实例对象可以拦截6种比较运算符:`< > <= >= == !=`,对应于 + +``` + .__lt__(self, other) # < + .__le__(self, other) # <= + .__gt__(self, other) # > + .__ge__(self, other) # >= + .__eq__(self, other) # == + .__ne__(self, other) # != +``` + +* 比较运算符全部是左端形式,无右端形式:`3<=obj`会转换成`obj>=3` +* 比较运算符并没有隐式关系。`==`为真,并不意味着`!=`为假。 + 因此`.__eq__(self, other)`与`.__ne__(self, other)`必须同时实现而且语义要一致。 + + ![重载比较运算符](../imgs/python_26_18.JPG) + +21.在布尔环境中,Python会首先尝试`.__bool__(self)`方法来获取一个直接的布尔值。如果没有这个方法,则 尝试`.__len__(self)`方法根据其结果确定实例对象的真值(非0则为真,0为假) + + ![重载.__bool__方法](../imgs/python_26_19.JPG) + +22.每当实例对象空间被收回时(在垃圾收集时),析构函数`.__del__(self)`自动调用。 +>Python的析构函数不常用。原因有二: +> +>* 对于空间管理来说,通常不需要用户手动管理 +>* 用户无法预测实例对象的具体回收时机,这个时机有Python自动调度 + + ![重载.__del__方法](../imgs/python_26_20.JPG) \ No newline at end of file diff --git a/chapter/27_python_class_design_pattern.md b/chapter/27_python_class_design_pattern.md new file mode 100644 index 0000000..5354c18 --- /dev/null +++ b/chapter/27_python_class_design_pattern.md @@ -0,0 +1,89 @@ + +# 类的设计模式 +1.Python不会执行同名函数的重载,而只会用新对象覆盖旧对象 + +``` + class A: + def func(self,x): + pass + def func(self,x,y): + pass +``` +由于`class`、`def`均为可执行代码,因此`func`变量名这里被重新赋值了。 + + ![同名函数的覆盖](../imgs/python_27_1.JPG) + +2.委托设计:在Python中委托通常以拦截`.__getattr__(self,'name')`来实现。该方法会拦截对不存在属性的读取 + +* 代理类实例对象可以利用`.__getattr__(self,'name')`将任意的属性读取转发给被包装的对象 +* 代理类可以有被包装对象的借口,且自己还可以有其他接口 + + ![代理类](../imgs/python_27_2.JPG) + +3.Python支持变量名压缩的概念:`class`语句内以`__`(两个下划线)开头但是结尾没有`__`(两个下划线)的变量名(如`__x`)会自动扩张为包含所在类的名称(如`_classname__x`) + +* 变量名压缩只发生在`class`语句内,且仅仅针对`__x`这种以`__`开头的变量名 +* 该做法常用于避免实例中潜在的变量名冲突 + + ![class的变量名压缩](../imgs/python_27_3.JPG) + +4.Python3中,实例方法有两种形式: + +* 普通函数方法:通过对类名进行点号运算而获得类的函数属性,如`classname.func`,会返回普通函数方法。 + * 若调用的是实例方法,必须明确提供实例对象作为第一个参数,如`classname.func(obj,arg)` + * 若调用的是一般的方法,则遵守普通函数调用规则即可`classname.func(arg)` +* 绑定方法:通过对实例对象进行点号运算而获得类的函数属性,如`obj.func`,会返回绑定方法对象。Python在绑定方法对象中,自动将实例和函数打包 + * 绑定方法调用时,不需要手动传入实例对象,如`obj.func(arg)` + * 绑定方法的`__self__`属性引用被绑定的实例对象,`__func__`属性引用该类的该函数对象 + + ![普通方法和绑定方法](../imgs/python_27_4.JPG) + +5.多重继承:子类可以继承一个以上的超类。超类在`class`语句首行括号内列出,以逗号分隔 + +* 子类与其实例继承了列出的所有超类的命名空间 +* 搜索属性时,Python会从左到右搜索`class`首行中的超类,直到找到匹配的名字 + + ![多重继承](../imgs/python_27_5.JPG) + +6.工厂函数:通过传入类对象和初始化参数来产生新的实例对象: + +``` + def factory(classname,*args,**kwargs): + return classname(*args,**kwargs) +``` + + ![多重继承](../imgs/python_27_6.JPG) + +7.抽象超类:类的部分行为未定义,必须由其子类提供 + +* 若子类也未定义预期的方法,则Python会引发未定义变量名的异常 +* 类的编写者也可以用`assert`语句或者`raise`异常来显式提示这是一个抽象类 + +``` + class A: + def func(self): + self.act() #该方法未实现 + def act(self): + assert False, 'act must be defined!' + class ChildA(A): + def act(self): + print('in ChildA act') + x=child() + x.func() +``` + +这里的核心在于:超类中`self.act()`调用时,`self`指向的有可能是真实的实例对象(子类对象) + + ![抽象超类](../imgs/python_27_7.JPG) + + + + + + + + diff --git a/chapter/28_python_class_advanced.md b/chapter/28_python_class_advanced.md new file mode 100644 index 0000000..21c30ae --- /dev/null +++ b/chapter/28_python_class_advanced.md @@ -0,0 +1,204 @@ +# 类的高级主题 +1.通过在自定义类中嵌入内置类型,类似委托;这样自定义类就可以实现内置类型的接口。 +这些接口在内部通过操作嵌入的内置类型来实现。 +>这是一种扩展内置类型的方式 + +2.通过子类扩展内置类型:所有内置类型都可以直接创建子类,如`list`、`str`、`dict`、`tuple`、`set`等 + +* 内置类型的子类实例可以用于内置类型对象能够出现的任何地方 + +3.在Python3中所有的类都是新式类。 +> Python2.2之前的类不是新式类 + +* 所有的类都是从`object`内置类派生而来 +* `type(obj)`返回对象实例所属的类对象 + >对于实例对象的`type(obj)`返回值也是`obj.__class__` +* `type(classname)`返回`"type"`,因为所有`class`对象都是`type`的实例 +* 由于所有`class`均直接或者间接地派生自`object`类,因此每个实例对象都是`object`类的实例 +* `object`是`type`类的实例,但是同时`type`又派生自`object` + + ![新式类](../imgs/python_28_1.JPG) + +4.Python3中的类有一个`.__slots__`属性,它是一个字符串列表。这个列表限定了类的实例对象的合法属性名。如果给实例赋了一个`.__slots__`列表之外的属性名会引发异常 + +* 虽然有了`.__slots__`列表,但是实例对象的属性还是必须先赋值才存在 + + ![.__slots__属性](../imgs/python_28_2.JPG) + +* 当有`.__slots__`列表存在时,默认会删除`.__dict__`属性,而`getattr()`,`setattr()` + 以及`dir()`等函数均使用`.__slots__`属性,因此仍旧可以正常工作 + * 可以在`.__slots__`列表中添加`.__dict__`字符串, + 因此对于使用`.__dict__`的地方均能正常工作 + + ![.__slots__和 .__dict__](../imgs/python_28_3.JPG) + +* `.__slots__`属性的使用可以优化内存和读取速度 +* 在继承中: + * 若子类继承自一个没有`.__slots__`的超类,则超类的`.__dict__`属性可用,则子类中的`.__slots__` + 没有意义。因为子类继承了超类的`.__dict__`属性 + + ![.__slots__和 .__dict__](../imgs/python_28_4.JPG) + + * 若子类有`.__slots__`,超类也有`.__slots__`,子类的合法属性名为父类和子类的`.__slots__`列表的并集 + + ![超类子类都有`.__slots__`](../imgs/python_28_5.JPG) + + * 若超类有`.__slots__`,子类未定义`.__slots__`,则子类将会有一个`.__dict__`属性 + + ![超类有`.__slots__`子类没有](../imgs/python_28_6.JPG) + +5.Python3的`property`机制: +`property`是一个对象,通过它给类变量名赋值。 + +``` + class A: + age=property(getMethod,setMethod,delMethod,docMethod) + # 或者直接指定docstring + def getMethod(self): + pass + def setMethod(self,val): + pass + def delMethod(self): + pass + def docMethod(self): + ... + # return a string +``` + +* `property`优点:代码简单,运行速度更快;缺点:当类编写时可能还无法确定`property`名字,因此无法提供动态的接口 +* 如果`property`的`docstring`或者`docMethod`为`None`,则Python使用`getMethod`的`docstring`。 + + ![property](../imgs/python_28_7.JPG) + +一个添加了语法糖的方案为: + +``` + class A: + def __init__(self): + self._x = None + @property #定义了一个property get函数,必选 + def x(self): # property name 就是 get函数的函数名 + """I'm the 'x' property.""" + return self._x + @x.setter #定义了一个property set函数,可选 + def x(self, value): + self._x = value + @x.deleter #定义了一个property del函数,可选 + def x(self): + del self._x +``` + +6.Python类中有两种特殊的方法:`staticmethod`方法和`classmethod`方法 + +* `staticmethod`方法:当以实例对象调用`staticmethod`方法时,Python并不会将实例对象传入作为参数;而普通的实例方法,通过实例对象调用时,Python将实例对象作为第一个参数传入 + * 定义`staticmethod`方法: + + ``` + class A: + @staticmethod #定义一个staticmethod + def func(*args,**kwargs) + pass + ``` +* `classmethod`方法:当以实例对象或者类对象调用`classmethod`方法时,Python将类对象(如果是实例对象调用,则提取该实例所属的类对象)传入函数的第一个参数`cls`中 + * 定义`classmethod`方法: + + ``` + class A: + @classmethod #classmethod + def func(cls,*args,**kwargs) + pass + ``` + +总结一下,类中可以定义四种方法: + +* 普通方法:方法就是类对象的一个属性,执行常规函数调用语义`classname.method(args)` +* 实例方法:传入一个实例作为方法的第一个实参。调用时可以: + * `obj.method(args)`:通过实例调用 + * `classname.method(obj,args)`:通过类调用 +* `staticmethod`方法:* `obj.method(args)`通过实例调用时,执行的是`classname.method(args)`语义 +* `classmethod`方法:* `obj.method(args)`执行的是`classname.method(classname,args)`语义 + + ![Python类中四种方法](../imgs/python_28_8.JPG) + +7.类的实例方法中,用哪个实例调用的该方法,`self`就是指向那个实例对象 +类的`classmethod`方法中,用哪个类调用该方法,`cls`就指向那个类对象 + + ![实例方法和类方法中的self、cls](../imgs/python_28_9.JPG) + +8.类对象与实例对象都是可变对象,可以给类属性、实例属性进行赋值,这就是原地修改。这种行为会影响对它的多处引用 + 任何在类层次所作的修改都会反映到所有实例对象中 + + ![类对象与实例对象都是可变对象](../imgs/python_28_10.JPG) + +9.若类的某个属性是可变对象(如列表、字典),则对它的修改会立即影响所有的实例对象 + + ![类属性为可变对象](../imgs/python_28_11.JPG) + +10.多重继承中,超类在`class`语句首行内的顺序很重要。Python搜索继承树时总是根据超类的顺序,从左到右搜索超类。 + + ![多重继承超类定义顺序](../imgs/python_28_12.JPG) + + +11.类的`.__mro__`属性:类对象的`.__mro__`属性。它是一个`tuple`,里面存放的是类的实例方法名解析时需要查找的类。Python根据该元组中类的前后顺序进行查找。类对象的`.__mro__`列出了`getattr()`函数以及`super()`函数对实例方法名字解析时的类查找顺序。 + + ![类的 __mro__属性](../imgs/python_28_13.JPG) + + +* 类的`.__mro__`是动态的,当继承层次改变时它也随之改变 +* 元类可以重写一个类的`.mro()`方法来定义该类的`__.mro__`属性。该方法在类被创建时调用,结果存放在类的`.__mro__`属性中 + +12.`super()`函数:`super()`返回一个`super`实例对象,它用于代理实例方法/类方法的执行 + +* `super(class,an_object)`:要求`isinstance(an_object,class)`为真。代理执行了实例方法调用 +* `super(class,class2)`:要求 `issubclass(class2,class)`为真。代理执行了类方法调用 + +有两种特殊用法: + +* `super(class)`:返回一个非绑定的`super`对象 +* 在类的实例方法中,直接调用`super()`,等价于`super(classname,self)`(这里`self`可能是`classname`子类实例) +* 在类的类方法中,直接调用`super()`,等价于`super(classname,cls)`(这里`cls`可能是`classname`子类) + +原理:`super`的原理类似于: + +``` +def super(cls,instance): + mro=instance.__class__.__mro__ #通过 instance生成 mro + return mro[mro.index(cls)+1] #查找cls在当前mro中的index,饭后返回cls的下一个元素 +``` + +示例: + +``` +class Root: + def method1(self): + print("this is Root") +class B(Root): + def method1(self): + print("enter B") + print(self) + super(B,self).method1() #也可以简写为 super().method1() + print("leave B") +class C(Root): + def method1(self): + print("enter C") + print(self) + super().method1() #也可以写成super(C,self).method1() + print("leave C") +class D(B,C): + pass +``` + +* 调用`D().method1()`--> `D`中没有`method1` +* `B`中找到(查找规则:`D.__mro__`) --> 执行`B`中的`method1`。此时`self`为D实例。`D.__mro__`中,`B`的下一个是`C`,因此`super(B,self).method1()`从类`C`中查找`method1`。 +* 执行`C`的`method1`。此时`self`为D实例。`D.__mro__`中,`C`的下一个是`Root`,因此`super(C,self).method1()`从类`Root`中查找`method1`。 +* 执行`Root`的`method1`。 +* `print(self)`可以看到,这里的`self`全部为 `D`的实例 +> 类的`classmethod`依次类推 +> +> 类、实例的属性查找规则没有那么复杂。因为属性变量只是一个变量,它没办法调用`super(...)`函数。 +>只有实例方法和类方法有能力调用`super(...)`函数,才会导致这种规则诞生 + + ![super()和self](../imgs/python_28_14.JPG) + + + \ No newline at end of file diff --git a/chapter/29_python_try_except.md b/chapter/29_python_try_except.md new file mode 100644 index 0000000..2326cd4 --- /dev/null +++ b/chapter/29_python_try_except.md @@ -0,0 +1,142 @@ + +# 异常 +1.Python中,异常会根据错误自动地被触发,也能由代码主动触发和截获 + +2.捕捉异常的代码: + +``` +try: + statements #该代码执行主要的工作,并有可能引起异常 +except ExceptionType1: #except子句定义异常处理,这里捕捉特定的ExceptionType1类型的异常 + statements +except (ExceptionType2,ExceptionType3): #except子句定义异常处理, + #这里捕捉任何列出的异常(即只要是ExceptionType2类型或者ExceptionType3类型) + statements +except ExceptionType4 as excp: #这里捕捉特定的ExceptionType4类型异常,但是用变量名excp引用异常对象 + statements #这里可以使用excp引用捕捉的异常对象 +except: # 该子句捕获所有异常 + statements +else: #如果没有发生异常,这来到这里;当发生了异常则不执行else子句 + statements +``` + +* 当`try`子句执行时发生异常,则Python会执行第一个匹配该异常的`except`子句。当`except`子句执行完毕之后(除非该`except`子句 又引发了另一个异常),程序会跳转到整体语句之后执行。 + >整体语句就是指上面的`try..except..else` +* 如果异常发生在`try`代码块内,且无匹配的`except`子句,则异常向上传递到本`try`块外层的`try`块中。如果已经传递到了顶层了异常还没有被捕捉,则Python会终止程序并且打印默认的出错消息 +* 如果`try`代码块内语句未产生异常,则Python会执行`else`子句,然后程序会在整体语句之后继续执行 + + ![try..except..else语句](../imgs/python_29_1.JPG) + +3.`try/finally`语句: + +``` +try: + statements +finally: + statements +``` +无论`try`代码块执行时是否发生了异常,`finally`子句一定会被执行 + +* 若`try`子句无异常,则Python会接着执行`finally`子句,执行完之后程序会跳转到整体语句之后执行 +* 若`try`子句有异常,则Python会跳转到`finally`子句中,并接着把异常向上传递 + + ![try..finally语句](../imgs/python_29_2.JPG) + +4.Python中的`try|except|finally`统一格式: + +``` +try: + statements #该代码执行主要的工作,并有可能引起异常 +except ExceptionType1: #except子句定义异常处理,这里捕捉特定的ExceptionType1类型的异常 + statements +except (ExceptionType2,ExceptionType3): #except子句定义异常处理, + #这里捕捉任何列出的异常(即只要是ExceptionType2类型或者ExceptionType3类型) + statements +except ExceptionType4 as excp: #这里捕捉特定的ExceptionType4类型异常,但是用变量名excp引用异常对象 + statements #这里可以使用excp引用捕捉的异常对象 +except: # 该子句捕获所有异常 + statements +else: # 如果没有发生异常,这来到这里;当发生了异常则不执行else子句 + statements +finally: # 一定会执行这个子句 + statements +``` +* `else`、`finally`子句可选;`except`子句可能有0个或者多个。但是如果有`else`子句,则至少有一个`except` +* `finally`执行时机:无论有没有异常抛出,在程序跳出整体语句之前的最后时刻一定会执行 + >整体语句就是指上面的`try..except..else...finally` + + ![try..except...finally语句](../imgs/python_29_3.JPG) + +5.要显式触发异常,可以用`raise`语句。有三种形式的形式: + +* `raise exception_obj`:抛出一个异常实例 +* `raise Exception_type`:抛出一个指定异常类型的实例,调用`Exception_type()`获得 +* `raise from `: + 第二个异常实例会附加到第一个异常实例的`.__cause__`属性中并抛出第一个异常实例 +* `raise`:转发当前作用域中激活的异常实例。若当前作用域中没有激活的异常实例,则抛出`RuntimeError`实例对象 + +* 一旦异常在程序中由某个`except`子句捕获,则它就死掉了不会再传递 +* `raise`抛出的必须是一个`BaseException`实例或者`BaseException`子类,否则抛出`TypeError` + >`BaseException`类是所有内建异常的父类。 + > + >`Exception`类是所有内建异常、`non-system-exiting`异常的父类。用于自定义的异常类也应该从该类派生 + + ![raise语句](../imgs/python_29_4.JPG) + + ![异常的死亡与活跃](../imgs/python_29_5.JPG) + +6.在一个异常处理器内部`raise`一个异常时,前一个异常会附加到新异常的`__context__`属性 + +* 如果在异常处理器内部`raise`被捕获的异常自己,则并不会添加到`__context__`属性 + + ![异常处理器内的raise](../imgs/python_29_6.JPG) + +* 在异常处理器内部`raise`与`raise e`效果相同 + + ![raise与raise e](../imgs/python_29_7.JPG) + +7.`assert`语句可能会引起`AssertionError`。其用法为:`assert ,`。这等价于: + +``` +if __debug__: + if not : + raise AssertionError() +``` + +* ``表达式用于计算真假,``表达式用于作为异常的参数。若``计算为假,则抛出`AssertionError` +* 若执行时用命令行 `-0`标志位,则关闭`assert`功能(默认是打开的)。 + > `__debug__`是内置变量名。当有`-0`标志位时,它为0;否则为1 +* 通常`assert`用于给定约束条件,而不是用于捕捉程序的错误。 + + ![assert](../imgs/python_29_8.JPG) + +8.Python3中有一种新的异常相关语句:`with/as`语句。它是作为`try/finally`的替代方案。用法为: + +``` +with expression [as var]: + statements +``` +`expression`必须返回一个对象,该对象必须支持环境管理协议。其工作方式为: + +* 计算`expression`表达式的值,得到环境管理器对象。环境管理器对象必须有`.__enter__(self)`方法和`.__exit__(self, exc_type, exc_value, traceback)`方法 +* 调用环境管理器对象的`.__enter__(self)`方法。如果有`as`子句,`.__enter__(self)`方法返回值赋值给`as`子句中的变量`var`;如果没有`as`子句,则`.__enter__(self)`方法返回值直接丢弃。**并不是将环境管理器对象赋值给`var`** +* 执行`statements`代码块 +* 如果`statements`代码块抛出异常,则`.__exit__(self, exc_type, exc_value, traceback)`方法自动被调用 + >在内部这几个实参由`sys.exc_info()`返回`(exc_type, exc_value, traceback)`信息, + + * 若`.__exit__()`方法返回值为`False`,则重新抛出异常到`with`语句之外 + * 若`.__exit__()`方法返回值为`True`,则异常终止于此,并不会抛出`with`语句之外 +* 如果`statements`代码块未抛出异常,则`.__exit__(self, exc_type, exc_value, traceback)`方法自动被调用,调用参数为:`.__exit__(self,None,None,None)` + + ![with语句](../imgs/python_29_9.JPG) + +9.Python3.1之后,`with`语句可以指定多个环境管理器,以逗号分隔。根据定义的顺序这些环境管理器对象的`.__enter__(self)`方法顺序调用,`.__exit__(self, exc_type, exc_value, traceback)`方法逆序调用 +>如果对象要支持环境管理协议,则必须实现`.__enter__(self)`方法和`.__exit__(self, exc_type, exc_value, traceback)`方法 + + ![多个with](../imgs/python_29_10.JPG) + + diff --git a/chapter/2_python_number_type.md b/chapter/2_python_number_type.md index 2b6bf0e..63c7d4b 100644 --- a/chapter/2_python_number_type.md +++ b/chapter/2_python_number_type.md @@ -1,3 +1,8 @@ + # 数字类型 1.Python的数字常量: diff --git a/chapter/30_python_exception_type.md b/chapter/30_python_exception_type.md new file mode 100644 index 0000000..b8d7e28 --- /dev/null +++ b/chapter/30_python_exception_type.md @@ -0,0 +1,67 @@ + +# 异常对象 +1.Python3中,内置异常与用户自定义异常都是类的实例对象 + +2.在`try...except`语句进行`except ExceptionType`子句匹配时,采用的是`isinstance(exception_obj,ExceptionType)`这种匹配规则。因此如果`ExceptionType`是`exception_obj`所属类的超类,则匹配也成功。 + +3.Python中的内置异常类继承树: + +~~~mermaid +graph BT +id1(OverflowError) -->|继承|id2(ArithmeticError) +id2 -->|继承|id3(Exception) +id4(IndexError) -->|继承|id3 +id3-->|继承|id5(BaseException) +~~~ + +* 用户自定义异常类不要直接从`BaseException`继承。`BaseException`提供了默认的打印和状态保持行为 + * 在构造时传给异常类的所有参数都将作为一个元组存储在`.args`属性中 + * 在构造时传入的字符串作为`.__str(self)__`方法返回。如果传入的不是字符串, + 则将先调用`str()`将该参数转换为字符串 +* `Exception`是所有内置异常类的超类。用户自定义的异常类都继承自它 + * 系统退出事件`SystemExit`、`KeyboardInterrupt`、`GeneratorExit`不能继承自它 + + ![BaseException](../imgs/python_30_1.JPG) + +4.自定义异常类:通常继承自`Exception`类 + +* 若想自定义打印显示,则必须重写`.__str__(self)`方法 +* 如果想定制初始化方法,必须重写`.__init__(self,args)`方法。此时超类的`.args`属性同样也会起作用 + + ![用户的自定义异常类](../imgs/python_30_2.JPG) + +5.Python在运行时会将`try`语句放入堆栈中。抛出异常时,Python跳转至最近的`try`块中,找到匹配该异常的异常处理器(即`except子句`),执行异常处理的`except`子句。一旦异常被捕获并且处理,则其生命周期结束 + +* 异常的传递:向上返回到先前进入但是尚未离开的`try` + +6.Python中所有的错误都是异常。但是并非所有的异常都是错误 + +* 内置的`input`函数每次调用时,遇到文件末尾时引发内置的`EOFError` +* 调用`sys.exit()`会触发`SystemExit`异常 +* 在键盘上按下`Ctrl-C`键时,会触发`KeyboardInterrupt`异常 + + ![系统级的异常事件](../imgs/python_30_3.JPG) + +7.用户自定义的异常可以用于触发信号条件。这是利用异常来传递信息的方法 + +8.`try...finally`通常用于释放系统资源。虽然垃圾收集时资源会自动释放,但是垃圾收集的时机不可控,由算法自动调度 + +9.可以在顶层代码中使用`try`以及空的`except`来进行调试,从捕获程序有什么意外情况发生 + +10.`sys.exc_info()`函数返回最近引发的异常信息,它返回一个三元素的元组:`(type,value,traceback)` + +* `type`:异常类型 +* `value`:异常实例对象 +* `traceback`:一个`traceback`对象,代表异常发生时所调用的堆栈 + + ![sys.exc_info函数](../imgs/python_30_4.JPG) + +11.为了拦截具体的异常,`except `应该具体化,避免拦截无关事件 + +* 空的`except`子句拦截任何异常,包括内存错误、系统推出、键盘中断等等 +* 但是太具体化不利于扩展 + diff --git a/chapter/31_python_unicode_bytes.md b/chapter/31_python_unicode_bytes.md new file mode 100644 index 0000000..a4d9017 --- /dev/null +++ b/chapter/31_python_unicode_bytes.md @@ -0,0 +1,128 @@ + +# Unicode与字节串 +1.字符编码: + +* `ASCII`编码:每个字符存储在一个字节中。字符码值从 0~127 +* `Latin-1`编码:每个字符存储在一个字节中。字符码值从 0~255。其中码值128~255分配给特殊字符;码值0~127部分与 + `ASCII`编码相同。 +* `UTF-8`编码:每个字符存储的字节数量可变,不再是固定编码 + > `ASCII`编码是`UTF-8`编码的子集,也是`Latin-1`编码的子集 + +2.`Unicode`文本通常叫做“宽字符”字符串,因为每个字符可能表示为多个字节 + +3.查看字符的`Unicode`码值: `ord()`函数; +查看`Unicode`码值对应的字符:`chr()`函数 +>这里的`Unicode`码值都是整数,可以是十进制、二进制、八进制、十六进制整数等 + +![字符与Unicode码值的转换](../imgs/python_31_1.JPG) + +4.Python大约支持上百中不同的编码。可以导入`encodings`模块,并运行`help(encodings)`显示很多编码名称。有一些编码是Python中实现的,一些是C中实现的。 +>有些编码对应多个不同的名称 + +![encodings模块](../imgs/python_31_2.JPG) + +5.Python3中有三种字符串相关类型: + +* `str`类型表示`Unicode`文本(8位和更宽的位数),为不可变的字符序列,称为字符串 +* `bytes`表示二进制数据,称为字节串。`bytes`对象其实是小整数的一个序列,每个整数的范围在0~255之间。 + * 索引一个`bytes`实例返回一个整数 + * 分片一个`bytes`实例返回一个新的`bytes`实例 + * `list(bytes_obj)`返回一个整数列表而不是字符列表 + > `bytes`类型几乎支持所有的`str`操作,但是不支持字符串格式化操作(没有字节串格式化操作) + +* `bytearray`是一种可变的`bytes`类型,称为可变字节串。`bytearray`是`bytes`的一个变体, + 它是可变的且支持原地修改。它支持`str`与`bytes`的常见操作,以及与列表相同的一些原地修改操作。 + + ![str、bytes、bytearray](../imgs/python_31_3.JPG) + +6.`sys.getdefaultencoding()`函数返回平台默认的编码方式。`sys.getfilesystemencoding()`返回系统文件的默认编码方式。 + + ![系统默认编码](../imgs/python_31_4.JPG) + +7.Python3中,当一个文件以文本模式打开时,读取其数据会自动将其内容解码,并返回一个字符串;当一个文件以文本模式写打开时,写入一个字符串会在将该字符串写入文件之前自动编码它。 + +* 编码和解码的类型是系统的平台默认编码类型,或者你手动设定的编码类型 +* 根据编码类型,Python自动处理文件起始处的字节标记序列(通常用于标记文件编码类型) +* Python自动对行尾换行符转换。在windows下,换行符`\n`在写入文件时转换为windows下的换行符`\r\n`。在读取文件时windows下的换行符`\r\n`转换为标准换行符`\n` + +当一个文件以二进制模式打开时,读取其数据直接返回其原生内容而并不以任何方式解码,也不做任何方式修改(即不转换换行符),直接作为`bytes`实例返回;写入会接受一个`bytes`实例或者一个`bytearray`实例,并且不加修改地写入到文件(即不转换换行符) + + ![文件和编码](../imgs/python_31_5.JPG) + +8.在Python3中,`'xxx'`、 `"xxx"` 、`'''xxx'''`均创建一个字符串常量,而添加一个`b`或者`B`中创建一个`bytes`常量`b'xxx'`、 `B"xxx"` 、`b'''xxx'''` + +* 尽管`bytes`打印出来是字符串(若无对应的字符则输出内存表示),但它本质上是一个小整数序列 +* Python3中所有字符串都是Unicode字符(是ASCII字符的超集) + + ![bytes常量](../imgs/python_31_6.JPG) + +9.Python3中,虽然字符串与`bytes`的内存表示相同,但是二者不能混用,因为二者无法自动转换。对于期待一个`str`实例作为参数的函数,它不能接受一个`bytes`实例;反之亦然 + +* 字符串的`.encode(encoding)`方法和`bytes`的`bytes(a_string,encoding)`函数将一个字符串实例转换为它原生`bytes`形式 +* 字符串的`str(a_bytes,encoding)`函数和`bytes`的`.decode(encoding)`方法将一个`bytes`实例解码成字符串形式。 + +>字符串的`.encode(encoding)`方法的`encoding`参数可以为空,此时表示使用平台默认编码 + +>`str(a_bytes)`函数返回的是`bytes`实例的打印字符串,而不是执行编码转换过程 + + ![bytes和字符串的编解码](../imgs/python_31_7.JPG) + +10.Python的字符串常量支持: + +* `'\xNN'`:单字节字符(8位),等价于`\u00NN` +* `'\uNNNN'`:双字节字符,16位 +* `'\UNNNNNNNN'`:4字节字符,32位 + >这里的`N`均为十六进制整数的一个整数位[0~F] + + ![单字节字符与多字节字符](../imgs/python_31_8.JPG) + +11.编解码ASCII字符非常简单,无需显示指定编解码类型(当然你可以随意指定一个编解码类型,因为ASCII编码是任何编码类型的子集) + + ![ASCII字符编码](../imgs/python_31_9.JPG) + +编解码非ASCII字符则要注意,对该字符的编码类型必须与解码类型一致,否则乱码或者抛出`UnicodeDecodeError`。 + + ![ASCII字符编码](../imgs/python_31_10.JPG) + +12.生成Unicode字符串你可以通过Unicode转义序列来创建,如`'A\u4e2d\u56fd'`;也可以通过`chr()`函数来创建,如 + `'A'+chr(0x4e2d)+chr(0x56fd)`,最终结果都是`'A中国'` + +13.字符串常量与`bytes`常量区别: + +* 对字符串常量,`'\xNN'`与`'\u00NN'`是等价的;对`bytes`常量,`b'\xNN'`与`b'\u00NN'`是不等的 + >`b'\xE8'`长度为2字节,`b'\u00E8'`长度为6字节 +* 字符串常量可以包含任意字符;`bytes`常量要求字符要么是ASCII字符,要么是转义字符 +* `len(string_literal)`得到字符串常量的字符个数;`len(bytes_literal)`得到`bytes`常量的字节数 + + ![字符串常量与bytes常量](../imgs/python_31_11.JPG) + +14.指定Python源文件字符集编码声明:在脚本的第一行写入: + +``` +# -*- coding: latin-1 -*- +``` + +15.`bytes`实例的构造: + +* `b'abc'`:构造`bytes`常量 +* `bytes('abc',encoding='ascii')`:通过构造函数传入字符串和编码构造 +* `bytes([97,98,99])`:通过传入小整数可迭代对象构造 +* `'abc'.encode('ascii')`:从字符串编码获取 + +16.`bytearray`实例的构造: + +* `bytearray('abc',encoding='ascii')`:通过构造函数传入字符串和编码构造 +* `bytearray(b'abc')`:通过`bytes`常量构造 + + ![bytes构造与bytearray构造](../imgs/python_31_12.JPG) + +17.打开文件时,可以通过`encoding`关键字参数指定打开文件的编码方式 + +18.Python的`struct`模块可以从字符串创建和提取打包的`bytes` + +19.`pickle`模块存储`pickle`化的对象用的是`bytes` + diff --git a/chapter/32_python_attribute_management.md b/chapter/32_python_attribute_management.md new file mode 100644 index 0000000..24dc694 --- /dev/null +++ b/chapter/32_python_attribute_management.md @@ -0,0 +1,100 @@ + +# 管理属性 +1.管理属性的工具 + +* `.__getattr__(self,name)`方法:拦截所有未定义属性的读取(它要么返回一个值,要么抛出`AttributeError`异常;`.__setattr__(self,name,value)`方法:拦截所有属性的读取赋值(包括未定义的、已定义的) +* `.__getattribute__(self,name)`方法:拦截所有属性的读取(包括未定义的、已定义的) +* `property`特性:将特定属性访问定位到`get`方法和`set`方法 +* 描述符协议:将特定属性访问定位到具有任意`get`和`set`方法的实例对象 + +2.`property`:每个`property`管理一个单一的、特定的属性。用法为: + +``` +class A: + def fget(...): + pass + def fset(...): + pass + def fdel(...): + pass + attribute=property(fget,fset,fdel,"doc") #必须在fget,fset,fdel之后定义 +a=A() +a.attribute #调用的是property特性 +``` + +* `property()`函数返回的是一个`property`对象 +* 子类继承了超类的`property`,就和类的普通属性一样 + + ![property](../imgs/python_32_1.JPG) + +3.描述符:描述符是作为独立的类创建,它的实例是赋值给了类属性 + +* 描述符的实例可以由子类继承 +* 描述符的实例管理一个单一的特定的属性 +* 从技术上讲,`property()`创建的是一个描述符实例(`property`实例) +* 描述符实例针对想要拦截的属性名访问操作,它提供了特定的方法 + +描述符类的接口为(即描述符协议): + +``` +class Descriptor: + ''' + This is docstring + ''' + def __get__(self,instance,owner): + pass + def __set__(self,instance,value): + pass + def __delete__(self,instance): + pass +class A: + attr=Descriptor() + ... +``` + +* `instance`参数为: + * `None`:当用于类的属性访问时(如`cls.attr`) + * 类`A`的实例对象:当用于实例的属性访问时(如`instance.attr`) +* `owner`参数为:使用该描述符的类`A` +* 当访问类实例或者类属性时,自动调用该类的描述符实例的方法。如果该类的描述符中某些方法空缺则: + * 若` __set__(self,instance,value)`未定义,则写该属性抛出`AttributeError`,该属性只读 + * 若` __get__(self,instance,owner)`未定义,则读该属性返回一个`Descriptor`实例, + 因为从继承树中可知,该属性返回由类的`attr`变量名指定的对象 +* 状态信息可以保持在实例对象中,也可以保存在描述符实例中。因为在这3个方法中,`self`,`instance`都可以访问 + + ![描述符属性](../imgs/python_32_2.JPG) + +4.`.__delattr__(self,name)`方法拦截属性的删除 +> `delattr(x,'name')`删除了`x.name`属性 + +5.由于`.__getattribute__(self,name)`方法和`.__setattr__(self,name,value)`方法对所有的属性拦截,因此他们的实现特别要小心,注意不要触发无穷递归。 + +* `.__getattribute__(self,name)`方法中,若要取属性则可以用超类的`.__getattribute__(self,name)`获取。如果通过`.__dict__`方法获取则会再次触发`.__getattribute__(self,name)`的调用 +* `.__setattr__(self,name,value)`方法中,若要设置属性可以用`self.__dict__[name]=value`的方法,或者用超类的`.__setattr__(self,name,value)`方法 + + ![__getattribute__与__setattr__陷阱](../imgs/python_32_3.JPG) + +6.Python3中,所有使用内置操作隐式的获取方法名属性(如`print(x)`用到了`.__str__(self)`),`.__getattr__(self,name)`、`.__setattr__(self,name,value)`、 +`.__getattribute__(self,name)`方法都不会拦截,因为Python在类中查找这样的属性,完全忽略了在实例中查找 + + ![__getattribute__与__setattr__陷阱](../imgs/python_32_4.JPG) + +7.属性拦截优先级: + +* 在读取属性方面,`__getattribute__`优先级最高;在写属性方面,`__setattr__`优先级最高;在删除属性方面, + `__del__`优先级最高 + + ![__getattribute__优先级最高](../imgs/python_32_5.JPG) + +* 如果没有`__getattribute__`,`__setattr__`与`__del__`,则读写删属性取决于描述符(`property`也是一种特殊的描述符)。其中如果同一个属性指定了多个描述符,则后面的描述符覆盖前面的描述符 + >因为本质上`property`是一种`descriptor` + + ![__getattribute__优先级最高](../imgs/python_32_6.JPG) + +* `__getattribute__`与`__getattr__`区别:`__getattribute__`在任何属性读取的时候拦截,而`__getattr__`只有在未定义属性读取的时候拦截(约定俗成地,它要么返回一个值,要么返回`AttributeError`)。其中若二者同时存在则`__getattribute__`优先级较高 + + ![__getattribute__与__getattr__区别](../imgs/python_32_7.JPG) diff --git a/chapter/33_python_decorator.md b/chapter/33_python_decorator.md new file mode 100644 index 0000000..dc7884e --- /dev/null +++ b/chapter/33_python_decorator.md @@ -0,0 +1,248 @@ + +# 装饰器 +1.装饰器是用于包装其他可调用对象的一个可调用对象,它是一个可调用对象,其调用参数为另一个可调用对象<,它返回一个可调用对象 + +* 一个函数对象是可调用对象。 +* 一个类对象是可调用对象,对它调用的结果就是返回类的实例 +* 实现了`.__call__()`方法的类,其实例对象是可调用对象,对它调用的结果就是调用`.__call__()`方法 + + ![可调用对象](../imgs/python_33_1.JPG) + +装饰器有两种使用形式: + +* 函数的装饰器:在函数对象定义的时候使用装饰器,用于管理该函数对象 +* 类的装饰器:在类定义的时候使用该装饰器,用于管理该类以及类的实例 + +>装饰器是装饰器模式的一个实现 + +2.函数的装饰器:用于管理函数。函数的装饰器声明为: + +``` +@decorator +def func(*pargs,**kwargs): + pass +``` +即在正常的函数定义之前冠以`@decorator`说明符(即装饰器声明)。它等价于: + +``` +def func(*pargs,**kwargs): + pass +func=decorator(func) +``` + +* 类中的`@staticmethod`、`@classmethod`、`@property`均为装饰器 +* 执行了装饰器的`def`之后,函数名指向的不再是原来的函数对象,而是: + * 一个可调用对象, 当`decorator`是个函数时由`decorator(func)`函数返回的 + * `decorator`类的实例,当`decorator`是个类时,由`decorator(func)`构造方法返回 + + ![函数的装饰器](../imgs/python_33_2.JPG) + +3.类的装饰器:用于管理类。类的装饰器声明为: + +``` +@decorator +class A: + pass +``` +即在正常的类定义之前冠以`@decorator`说明符(即装饰器声明)。它等价于: + +``` +class A: + pass +A=decorator(A) +``` + +* 类的装饰器并不是拦截创建实例的函数调用,而是返回一个不同的可调用对象 +* 执行了装饰器的`class`之后,类名指向的不再是原来的类对象,而是: + * 一个可调用对象, 当`decorator`是个函数时由`decorator(func)`函数返回的 + * `decorator`类的实例,当`decorator`是个类时,由`decorator(func)`构造方法返回 + + ![类的装饰器](../imgs/python_33_3.JPG) + +3.装饰器只是一个返回可调用对象的可调用对象,它没有什么特殊的地方。 + +* 可以用函数实现装饰器: + +``` +def decorator(func): #定义了一个叫decorator的装饰器 + #某些处理 + return func #返回可调用对象 +``` + +* 也可以用类来实现装饰器: + +``` +class decorator: + def __init__(self,func): + self.func=func + def __call__(self,*args,**kwargs): + return self.func +``` + +* 通常用嵌套类来实现装饰器: + +``` +def decorator(func): #定义了一个叫decorator的装饰器 + def wrapper(*args): + #使用func或其他的一些工作 + return wrapper #返回可调用对象 +``` + + ![三种装饰器的实现](../imgs/python_33_4.JPG) + +4.装饰器的嵌套: + +* 函数的装饰器的嵌套: + +``` +@decoratorA +@decoratorB +@decoratorC +def func(): + pass +``` +等价于 + +``` +def f(): + pass +f=A(B(C(f))) +``` +* 类的装饰器的嵌套: + +``` +@decoratorA +@decoratorB +@decoratorC +class M: + pass +``` +等价于 + +``` +class M: + pass +M=A(B(C(M))) +``` +>每个装饰器处理前一个装饰器返回的结果,并返回一个可调用对象 + +5.装饰器可以携带参数。 + +* 函数定义的装饰器带参数:它其实是一个嵌套函数。 + * 外层函数的参数为装饰器参数,返回一个函数(内层函数) + * 内层函数的参数为`func`,返回一个可调用参数,内层函数才是真正的装饰器 + +``` +def decorator(*args,**kwargs): + print("this is decorator1:",args,kwargs) + def actualDecorator(func): # 这才是真实的装饰器 + ... + return func + return actualDecorator +``` + + ![带参数的函数定义的装饰器](../imgs/python_33_5.JPG) + +* 类定义的装饰器带参数:它其实是一个嵌套类。 + * 外层类的初始化函数的参数为装饰器参数,外层类的`__call__`函数的参数为`func`,返回值为一个类的实例(内部类实例) + * 内层类的初始化函数参数为`func`;内层类的`__call__`函数使用`func`,内层类才是真正的装饰器 + +``` +class decorator2: + class ActualDecorator: #这才是真实的装饰器 + def __init__(self,func): + ... + self.func=func#记住func + def __call__(self,*args,**kwargs): + ... + return self.func(*args,**kwargs) #使用func + def __init__(self,*args,**kwargs): + ... + def __call__(self,func): + ... + return decorator2.ActualDecorator(func) +``` + + ![带参数的函数定义的装饰器](../imgs/python_33_6.JPG) + +总结: + +* 不带参数的装饰器`decorator`装饰一个名字`F`(可能为函数名、也可能为类名)`@decorator`:则执行的是:`F=decorator(F)`,直接使用`F` +* 带参数的装饰器`decorator`装饰一个名字`F`(可能为函数名、也可能为类名)`@decorator(args)`:则执行的是:`F=decorator(args)(F)`,间接使用`F` + +6.利用装饰器可以实现单例模式: + +``` +def Singleton(cls): + instance=None + def onCall(*args,**kwargs): + nonlocal instance + if instance == None: + instance=cls(*args,**kwargs) + return instance + return onCall +@Singleton +class A: + pass +``` + ![利用装饰器实现单例模式](../imgs/python_33_7.JPG) + +7.利用装饰器可以跟踪对象的调用接口,从而管理对实例的接口访问(如统计调用次数,打印调用日志) + +``` +def Tracer(cls): + class Wrapper: + def __init__(self,*args,**kwargs): + self.wrapped=cls(*args,**kwargs) + def __getattr__(self,name): + print('Trace:'+name) + return getattr(self.wrapped,name) + return Wrapper +@Tracer +class A: + pass +``` + + ![利用装饰器跟踪对象接口](../imgs/python_33_8.JPG) + +8.装饰器也可以直接管理函数和类,而不仅仅只是管理对他们的调用 + +* 利用装饰器添加函数和类到注册表: + +``` +register_dict={} +def register(obj): + register_dict[obj.__name__]=obj + return obj +@register +def func(): + pass +``` + + ![利用装饰器添加函数到注册表](../imgs/python_33_9.JPG) + +* 利用装饰器为函数和类添加属性 + +``` +def register(obj): + obj.label=0 + return obj +@register +def func(): + pass +``` + + ![利用装饰器为函数添加属性](../imgs/python_33_10.JPG) + + + + + + + + + \ No newline at end of file diff --git a/chapter/34_python_metaclass.md b/chapter/34_python_metaclass.md new file mode 100644 index 0000000..302b52d --- /dev/null +++ b/chapter/34_python_metaclass.md @@ -0,0 +1,96 @@ + +# 元类 +1.元类是一种特殊的类,它用于创建类。元类机制允许我们在一条`class`语句的末尾自动插入某些逻辑。它在类对象创建时运行,是管理和扩展类的钩子。元类不是管理类的实例,而是管理类本身 + +2.尽管类的装饰器通常用来管理或者扩展类实例,但是他们也可以用于管理和扩展类对象本身,也与元类的功能重叠 + +3.Python3中,所有用户定义的类都是`type`类对象的实例,`type`类是应用最广的元类 + +4.`class`语句的内部机制:在一条`class`语句的末尾,Python会调用`type`类的构造函数来创建一个`class`对象。 + +``` +MyClass=type(classname,superclasses,attributedict) #新建了一个类,类名叫MyClass +# classname:类名,会成为MyClass类的 .__name__属性 +# superclasses:类的超类元组,会成为MyClass类的 .__bases__属性 +# attributedict:类的命名空间字典,会成为MyClass类的 .__dict__ 属性 +# 这个语句也是动态创建类对象的方法 +``` + +* `type`类定义了一个`.__call__(...)`方法。该方法运行`type`类定义的两个其他方法: + * `.__new__(mclass,classname,superclasses,attributedict)`方法,它返回新建的`MyClass`类 + > `mclass`:为本元类,这里是`type`类 + > `classname`:为被创建的类的类名,这里是`'MyClass'` + > `superclasses`:为被创建的类的超类元组 + > `attributedict`:为被创建的类的名字空间字典 + * `.__init__(customclass,classname,superclasses,attributedict)`方法, + 它初始化新建的`MyClass`类 + > `customclass`:为被创建的类,这里是`MyClass`类 + > `classname`:为被创建的类的类名,这里是`'MyClass'` + > `superclasses`:为被创建的类的超类元组 + > `attributedict`:为被创建的类的名字空间字典 + +5.所有的类型均由`type`类创建。要通知Python用一个定制的元类来创建类,可以直接声明一个元类来拦截常规的类创建过程。 + +定义元类:(所有元类必须是`type`的子类) + +``` +class MetaClass(type): + def __new__(mclass,classname,superclasses,attributedict): + return type.__new__(mclass,classname,superclasses,attributedict) + def __init__(customclass,classname,superclasses,attributedict): + return type.__init__(customclass,classname,superclasses,attributedict) +``` +使用元类: + +``` +class MyClass(metaclass=MetaClass): + pass +``` + +* 继承的超类也列在括号中,但是要在元类之前,也用逗号分隔: + `class MyClass(BaseCls1,BaseCls2,metaclass=MetaClass)` +* 使用元类声明后,在`class`语句底部进行创建`MyClass`类时,改为调用元类`MetaClass`而不是默认的`type`: + `MyClass=Meta('MyClass`,superclasses,attributedict)` +* 元类`MetaClass`要实现元类协议: + * 重载元类的`.__new__(Meta,classname,superclasses,attributedict)`方法,它返回新建的`MyClass`类 + * 重载元类的`.__init__(customclass,classname,superclasses,attributedict)`方法, + 它初始化新建的`MyClass`类 + >`type`类的`.__call__(...)`方法将创建和初始化`MyClass`类对象的调用委托给元类MetaClass` + + ![元类](../imgs/python_34_1.JPG) + +6.元类有的时候不一定是个真正的类,它也可能是一个函数。任何可调用对象都可以作为一个元类,只需要按照以下的做法: + +``` +def MetaFactory(classname,superclasses,attributedict): + ... + return type(classname,superclasses,attributedict) #动态创建类型 +class A(metaclass=MetaFactory): + pass +``` + +* 在`class`语句的末尾会调用`MetaFactory`函数 + + ![函数做元类](../imgs/python_34_2.JPG) + +7.事实上元类只用于创建类对象,元类并不产生元类自己的实例。因此元类的名字查找规则有些不同:`.__call__`,`.__new__`,`.__init__`方法均在类中查找 + +8.元类的继承: + +* 元类声明由子类继承,即子类的构建也是由父类的元类负责 + + ![元类的继承](../imgs/python_34_3.JPG) + +* 如果元类是以函数的方式声明,则子类的构建不再继承这个函数式元类 + + ![元类的继承](../imgs/python_34_4.JPG) + +* 元类中的属性并不进入自定义类的命名空间,即元类中声明的一些类属性与被创建类的名字空间无关(他们是两个不同的类) + + ![元类和被创建类的属性](../imgs/python_34_5.JPG) + +* 自定义的类,如果没有显示指定元类,也没有指定父类,则默认使用`type`作为元类(即常规的类创建机制) \ No newline at end of file diff --git a/chapter/35_python_execution.md b/chapter/35_python_execution.md new file mode 100644 index 0000000..b95ebed --- /dev/null +++ b/chapter/35_python_execution.md @@ -0,0 +1,16 @@ + +# Python 执行细节 + +1.Python脚本执行时,Python内部会首先将源代码编译成字节码的形式。字节码是平台无关的。 + +- 字节码是平台无关的 +- 如果Python进程拥有写入权限,则它会将脚本的字节码以一个`.pyc`为扩展名的文件。当脚本运行后你可以在源代码所在的目录附近看到`.pyc`文件。 + - 下一次运行脚本时,如果你在上次保存字节码之后没有修改源代码时,Python会自动加载`.pyc`文件并跳过编译步骤 +- 如果Python进程没有写入权限,则字节码会在内存中生成并在脚本执行结束后抛弃。 +- `.pyc`文件也是发布Python程序的方法之一。此时并不需要提供`.py`源代码。 + +2.字节码由Python虚拟机(简称`PVM`)来解释执行。实际上`PVM`不是一个独立的程序,它只是迭代运行字节码指令的一个大循环而已,它是Python系统的一部分。 \ No newline at end of file diff --git a/chapter/3_python_set_type.md b/chapter/3_python_set_type.md index 3563575..2e49def 100644 --- a/chapter/3_python_set_type.md +++ b/chapter/3_python_set_type.md @@ -1,3 +1,8 @@ + # Set类型 1.Python的`set`类型是集合内元素值唯一、元素值不可变的无序集。 `set`类型并不要求其集合内各个元素都是相同类型。 diff --git a/chapter/4_python_string_type.md b/chapter/4_python_string_type.md index a88f3d1..ad41f62 100644 --- a/chapter/4_python_string_type.md +++ b/chapter/4_python_string_type.md @@ -1,3 +1,8 @@ + # 字符串 1.Python的字符串是一种不可变序列,它包含的字符存在从左到右的位置顺序。 不可变是指:字符串创建以后无法修改它的内容。 diff --git a/chapter/5_python_list_type.md b/chapter/5_python_list_type.md index a7a926c..39e6a7d 100644 --- a/chapter/5_python_list_type.md +++ b/chapter/5_python_list_type.md @@ -1,5 +1,9 @@ + # 列表 - 1.列表可以包含任何种类的对象。它是本身是一种可变对象,支持原地修改。 > 不可变对象有元组、字符串、`frozenset` diff --git a/chapter/6_python_tuple_type.md b/chapter/6_python_tuple_type.md index f7a5c5d..68a9430 100644 --- a/chapter/6_python_tuple_type.md +++ b/chapter/6_python_tuple_type.md @@ -1,3 +1,8 @@ + # 元组 1.元组是由圆括号包围的一系列项,它由任意对象元素组成。它本身是不可变的, 即不可以原地修改。 diff --git a/chapter/7_python_collections.md b/chapter/7_python_collections.md index 2bf89d1..4a2b3d7 100644 --- a/chapter/7_python_collections.md +++ b/chapter/7_python_collections.md @@ -1,5 +1,9 @@ + #通用序列 - 1.Python的通用序列包括:字符串、列表、元组。 * 字符串:不可变对象,元素只能是字符 diff --git a/chapter/8_python_dictionary.md b/chapter/8_python_dictionary.md index a5310a9..8d2c69d 100644 --- a/chapter/8_python_dictionary.md +++ b/chapter/8_python_dictionary.md @@ -1,3 +1,8 @@ + # 字典 1.字典是一些 "键 --- 值" 对的无序集和。它通过键来索引。 diff --git a/chapter/9_python_file.md b/chapter/9_python_file.md index f2d8e79..9aab760 100644 --- a/chapter/9_python_file.md +++ b/chapter/9_python_file.md @@ -1,3 +1,8 @@ + # 文件 1.内置的`open()`函数会创建一个Python文件对象,可以作为计算机上的一个文件的引用。 diff --git a/imgs/picture_all.JPG b/imgs/picture_all.JPG new file mode 100644 index 0000000..3f8c078 Binary files /dev/null and b/imgs/picture_all.JPG differ diff --git a/imgs/picture_notes.JPG b/imgs/picture_notes.JPG index a09951d..91d1dbe 100644 Binary files a/imgs/picture_notes.JPG and b/imgs/picture_notes.JPG differ diff --git a/imgs/python_26_1.JPG b/imgs/python_26_1.JPG new file mode 100644 index 0000000..c9cb379 Binary files /dev/null and b/imgs/python_26_1.JPG differ diff --git a/imgs/python_26_10.JPG b/imgs/python_26_10.JPG new file mode 100644 index 0000000..c3c4ce1 Binary files /dev/null and b/imgs/python_26_10.JPG differ diff --git a/imgs/python_26_11.JPG b/imgs/python_26_11.JPG new file mode 100644 index 0000000..ee30d24 Binary files /dev/null and b/imgs/python_26_11.JPG differ diff --git a/imgs/python_26_12.JPG b/imgs/python_26_12.JPG new file mode 100644 index 0000000..f661d78 Binary files /dev/null and b/imgs/python_26_12.JPG differ diff --git a/imgs/python_26_13.JPG b/imgs/python_26_13.JPG new file mode 100644 index 0000000..f922efe Binary files /dev/null and b/imgs/python_26_13.JPG differ diff --git a/imgs/python_26_14.JPG b/imgs/python_26_14.JPG new file mode 100644 index 0000000..9935870 Binary files /dev/null and b/imgs/python_26_14.JPG differ diff --git a/imgs/python_26_15.JPG b/imgs/python_26_15.JPG new file mode 100644 index 0000000..de54623 Binary files /dev/null and b/imgs/python_26_15.JPG differ diff --git a/imgs/python_26_16.JPG b/imgs/python_26_16.JPG new file mode 100644 index 0000000..e6a8c03 Binary files /dev/null and b/imgs/python_26_16.JPG differ diff --git a/imgs/python_26_17.JPG b/imgs/python_26_17.JPG new file mode 100644 index 0000000..38d681f Binary files /dev/null and b/imgs/python_26_17.JPG differ diff --git a/imgs/python_26_18.JPG b/imgs/python_26_18.JPG new file mode 100644 index 0000000..bef4fd0 Binary files /dev/null and b/imgs/python_26_18.JPG differ diff --git a/imgs/python_26_19.JPG b/imgs/python_26_19.JPG new file mode 100644 index 0000000..c6d5991 Binary files /dev/null and b/imgs/python_26_19.JPG differ diff --git a/imgs/python_26_2.JPG b/imgs/python_26_2.JPG new file mode 100644 index 0000000..4cefae6 Binary files /dev/null and b/imgs/python_26_2.JPG differ diff --git a/imgs/python_26_20.JPG b/imgs/python_26_20.JPG new file mode 100644 index 0000000..202f75f Binary files /dev/null and b/imgs/python_26_20.JPG differ diff --git a/imgs/python_26_3.JPG b/imgs/python_26_3.JPG new file mode 100644 index 0000000..2258b56 Binary files /dev/null and b/imgs/python_26_3.JPG differ diff --git a/imgs/python_26_4.JPG b/imgs/python_26_4.JPG new file mode 100644 index 0000000..c009611 Binary files /dev/null and b/imgs/python_26_4.JPG differ diff --git a/imgs/python_26_5.JPG b/imgs/python_26_5.JPG new file mode 100644 index 0000000..8ac1cb9 Binary files /dev/null and b/imgs/python_26_5.JPG differ diff --git a/imgs/python_26_6.JPG b/imgs/python_26_6.JPG new file mode 100644 index 0000000..ab48c1b Binary files /dev/null and b/imgs/python_26_6.JPG differ diff --git a/imgs/python_26_7.JPG b/imgs/python_26_7.JPG new file mode 100644 index 0000000..be5e914 Binary files /dev/null and b/imgs/python_26_7.JPG differ diff --git a/imgs/python_26_8.JPG b/imgs/python_26_8.JPG new file mode 100644 index 0000000..73168b9 Binary files /dev/null and b/imgs/python_26_8.JPG differ diff --git a/imgs/python_26_9.JPG b/imgs/python_26_9.JPG new file mode 100644 index 0000000..5821594 Binary files /dev/null and b/imgs/python_26_9.JPG differ diff --git a/imgs/python_27_1.JPG b/imgs/python_27_1.JPG new file mode 100644 index 0000000..7c2641e Binary files /dev/null and b/imgs/python_27_1.JPG differ diff --git a/imgs/python_27_2.JPG b/imgs/python_27_2.JPG new file mode 100644 index 0000000..e0fe26f Binary files /dev/null and b/imgs/python_27_2.JPG differ diff --git a/imgs/python_27_3.JPG b/imgs/python_27_3.JPG new file mode 100644 index 0000000..0162c43 Binary files /dev/null and b/imgs/python_27_3.JPG differ diff --git a/imgs/python_27_4.JPG b/imgs/python_27_4.JPG new file mode 100644 index 0000000..d2a8abf Binary files /dev/null and b/imgs/python_27_4.JPG differ diff --git a/imgs/python_27_5.JPG b/imgs/python_27_5.JPG new file mode 100644 index 0000000..962c1d7 Binary files /dev/null and b/imgs/python_27_5.JPG differ diff --git a/imgs/python_27_6.JPG b/imgs/python_27_6.JPG new file mode 100644 index 0000000..2d3a1f3 Binary files /dev/null and b/imgs/python_27_6.JPG differ diff --git a/imgs/python_27_7.JPG b/imgs/python_27_7.JPG new file mode 100644 index 0000000..e9251e7 Binary files /dev/null and b/imgs/python_27_7.JPG differ diff --git a/imgs/python_28_1.JPG b/imgs/python_28_1.JPG new file mode 100644 index 0000000..3102b29 Binary files /dev/null and b/imgs/python_28_1.JPG differ diff --git a/imgs/python_28_10.JPG b/imgs/python_28_10.JPG new file mode 100644 index 0000000..ceed134 Binary files /dev/null and b/imgs/python_28_10.JPG differ diff --git a/imgs/python_28_11.JPG b/imgs/python_28_11.JPG new file mode 100644 index 0000000..c6acee1 Binary files /dev/null and b/imgs/python_28_11.JPG differ diff --git a/imgs/python_28_12.JPG b/imgs/python_28_12.JPG new file mode 100644 index 0000000..fc2359b Binary files /dev/null and b/imgs/python_28_12.JPG differ diff --git a/imgs/python_28_13.JPG b/imgs/python_28_13.JPG new file mode 100644 index 0000000..29c4695 Binary files /dev/null and b/imgs/python_28_13.JPG differ diff --git a/imgs/python_28_14.JPG b/imgs/python_28_14.JPG new file mode 100644 index 0000000..2d8d7a3 Binary files /dev/null and b/imgs/python_28_14.JPG differ diff --git a/imgs/python_28_2.JPG b/imgs/python_28_2.JPG new file mode 100644 index 0000000..0a73991 Binary files /dev/null and b/imgs/python_28_2.JPG differ diff --git a/imgs/python_28_3.JPG b/imgs/python_28_3.JPG new file mode 100644 index 0000000..6fe0e71 Binary files /dev/null and b/imgs/python_28_3.JPG differ diff --git a/imgs/python_28_4.JPG b/imgs/python_28_4.JPG new file mode 100644 index 0000000..0bd611d Binary files /dev/null and b/imgs/python_28_4.JPG differ diff --git a/imgs/python_28_5.JPG b/imgs/python_28_5.JPG new file mode 100644 index 0000000..9e8dacb Binary files /dev/null and b/imgs/python_28_5.JPG differ diff --git a/imgs/python_28_6.JPG b/imgs/python_28_6.JPG new file mode 100644 index 0000000..7a1a7dc Binary files /dev/null and b/imgs/python_28_6.JPG differ diff --git a/imgs/python_28_7.JPG b/imgs/python_28_7.JPG new file mode 100644 index 0000000..a891ab7 Binary files /dev/null and b/imgs/python_28_7.JPG differ diff --git a/imgs/python_28_8.JPG b/imgs/python_28_8.JPG new file mode 100644 index 0000000..c45160f Binary files /dev/null and b/imgs/python_28_8.JPG differ diff --git a/imgs/python_28_9.JPG b/imgs/python_28_9.JPG new file mode 100644 index 0000000..b58682c Binary files /dev/null and b/imgs/python_28_9.JPG differ diff --git a/imgs/python_29_1.JPG b/imgs/python_29_1.JPG new file mode 100644 index 0000000..f50266e Binary files /dev/null and b/imgs/python_29_1.JPG differ diff --git a/imgs/python_29_10.JPG b/imgs/python_29_10.JPG new file mode 100644 index 0000000..a7166f7 Binary files /dev/null and b/imgs/python_29_10.JPG differ diff --git a/imgs/python_29_2.JPG b/imgs/python_29_2.JPG new file mode 100644 index 0000000..0f69ab6 Binary files /dev/null and b/imgs/python_29_2.JPG differ diff --git a/imgs/python_29_3.JPG b/imgs/python_29_3.JPG new file mode 100644 index 0000000..7de8028 Binary files /dev/null and b/imgs/python_29_3.JPG differ diff --git a/imgs/python_29_4.JPG b/imgs/python_29_4.JPG new file mode 100644 index 0000000..5fcd2c4 Binary files /dev/null and b/imgs/python_29_4.JPG differ diff --git a/imgs/python_29_5.JPG b/imgs/python_29_5.JPG new file mode 100644 index 0000000..de29cc2 Binary files /dev/null and b/imgs/python_29_5.JPG differ diff --git a/imgs/python_29_6.JPG b/imgs/python_29_6.JPG new file mode 100644 index 0000000..5019e80 Binary files /dev/null and b/imgs/python_29_6.JPG differ diff --git a/imgs/python_29_7.JPG b/imgs/python_29_7.JPG new file mode 100644 index 0000000..8ae83f3 Binary files /dev/null and b/imgs/python_29_7.JPG differ diff --git a/imgs/python_29_8.JPG b/imgs/python_29_8.JPG new file mode 100644 index 0000000..d37a1cb Binary files /dev/null and b/imgs/python_29_8.JPG differ diff --git a/imgs/python_29_9.JPG b/imgs/python_29_9.JPG new file mode 100644 index 0000000..136706e Binary files /dev/null and b/imgs/python_29_9.JPG differ diff --git a/imgs/python_30_1.JPG b/imgs/python_30_1.JPG new file mode 100644 index 0000000..e6362b4 Binary files /dev/null and b/imgs/python_30_1.JPG differ diff --git a/imgs/python_30_2.JPG b/imgs/python_30_2.JPG new file mode 100644 index 0000000..1ff16c5 Binary files /dev/null and b/imgs/python_30_2.JPG differ diff --git a/imgs/python_30_3.JPG b/imgs/python_30_3.JPG new file mode 100644 index 0000000..3d987f8 Binary files /dev/null and b/imgs/python_30_3.JPG differ diff --git a/imgs/python_30_4.JPG b/imgs/python_30_4.JPG new file mode 100644 index 0000000..2276133 Binary files /dev/null and b/imgs/python_30_4.JPG differ diff --git a/imgs/python_31_1.JPG b/imgs/python_31_1.JPG new file mode 100644 index 0000000..ac7919e Binary files /dev/null and b/imgs/python_31_1.JPG differ diff --git a/imgs/python_31_10.JPG b/imgs/python_31_10.JPG new file mode 100644 index 0000000..0db4f5c Binary files /dev/null and b/imgs/python_31_10.JPG differ diff --git a/imgs/python_31_11.JPG b/imgs/python_31_11.JPG new file mode 100644 index 0000000..05368fe Binary files /dev/null and b/imgs/python_31_11.JPG differ diff --git a/imgs/python_31_12.JPG b/imgs/python_31_12.JPG new file mode 100644 index 0000000..78097fa Binary files /dev/null and b/imgs/python_31_12.JPG differ diff --git a/imgs/python_31_2.JPG b/imgs/python_31_2.JPG new file mode 100644 index 0000000..7325d30 Binary files /dev/null and b/imgs/python_31_2.JPG differ diff --git a/imgs/python_31_3.JPG b/imgs/python_31_3.JPG new file mode 100644 index 0000000..3f58aca Binary files /dev/null and b/imgs/python_31_3.JPG differ diff --git a/imgs/python_31_4.JPG b/imgs/python_31_4.JPG new file mode 100644 index 0000000..aaac449 Binary files /dev/null and b/imgs/python_31_4.JPG differ diff --git a/imgs/python_31_5.JPG b/imgs/python_31_5.JPG new file mode 100644 index 0000000..84bc01c Binary files /dev/null and b/imgs/python_31_5.JPG differ diff --git a/imgs/python_31_6.JPG b/imgs/python_31_6.JPG new file mode 100644 index 0000000..62124e9 Binary files /dev/null and b/imgs/python_31_6.JPG differ diff --git a/imgs/python_31_7.JPG b/imgs/python_31_7.JPG new file mode 100644 index 0000000..c7ae52a Binary files /dev/null and b/imgs/python_31_7.JPG differ diff --git a/imgs/python_31_8.JPG b/imgs/python_31_8.JPG new file mode 100644 index 0000000..6f37b07 Binary files /dev/null and b/imgs/python_31_8.JPG differ diff --git a/imgs/python_31_9.JPG b/imgs/python_31_9.JPG new file mode 100644 index 0000000..5126be0 Binary files /dev/null and b/imgs/python_31_9.JPG differ diff --git a/imgs/python_32_1.JPG b/imgs/python_32_1.JPG new file mode 100644 index 0000000..a8809bb Binary files /dev/null and b/imgs/python_32_1.JPG differ diff --git a/imgs/python_32_2.JPG b/imgs/python_32_2.JPG new file mode 100644 index 0000000..e88445f Binary files /dev/null and b/imgs/python_32_2.JPG differ diff --git a/imgs/python_32_3.JPG b/imgs/python_32_3.JPG new file mode 100644 index 0000000..b0c7bf1 Binary files /dev/null and b/imgs/python_32_3.JPG differ diff --git a/imgs/python_32_4.JPG b/imgs/python_32_4.JPG new file mode 100644 index 0000000..2b4c7dd Binary files /dev/null and b/imgs/python_32_4.JPG differ diff --git a/imgs/python_32_5.JPG b/imgs/python_32_5.JPG new file mode 100644 index 0000000..d948ad6 Binary files /dev/null and b/imgs/python_32_5.JPG differ diff --git a/imgs/python_32_6.JPG b/imgs/python_32_6.JPG new file mode 100644 index 0000000..66ba786 Binary files /dev/null and b/imgs/python_32_6.JPG differ diff --git a/imgs/python_32_7.JPG b/imgs/python_32_7.JPG new file mode 100644 index 0000000..c9cd179 Binary files /dev/null and b/imgs/python_32_7.JPG differ diff --git a/imgs/python_33_1.JPG b/imgs/python_33_1.JPG new file mode 100644 index 0000000..0555727 Binary files /dev/null and b/imgs/python_33_1.JPG differ diff --git a/imgs/python_33_10.JPG b/imgs/python_33_10.JPG new file mode 100644 index 0000000..ca28b61 Binary files /dev/null and b/imgs/python_33_10.JPG differ diff --git a/imgs/python_33_2.JPG b/imgs/python_33_2.JPG new file mode 100644 index 0000000..6feea47 Binary files /dev/null and b/imgs/python_33_2.JPG differ diff --git a/imgs/python_33_3.JPG b/imgs/python_33_3.JPG new file mode 100644 index 0000000..3ac0d45 Binary files /dev/null and b/imgs/python_33_3.JPG differ diff --git a/imgs/python_33_4.JPG b/imgs/python_33_4.JPG new file mode 100644 index 0000000..8b57f32 Binary files /dev/null and b/imgs/python_33_4.JPG differ diff --git a/imgs/python_33_5.JPG b/imgs/python_33_5.JPG new file mode 100644 index 0000000..143dd8e Binary files /dev/null and b/imgs/python_33_5.JPG differ diff --git a/imgs/python_33_6.JPG b/imgs/python_33_6.JPG new file mode 100644 index 0000000..19b5f24 Binary files /dev/null and b/imgs/python_33_6.JPG differ diff --git a/imgs/python_33_7.JPG b/imgs/python_33_7.JPG new file mode 100644 index 0000000..467e5ff Binary files /dev/null and b/imgs/python_33_7.JPG differ diff --git a/imgs/python_33_8.JPG b/imgs/python_33_8.JPG new file mode 100644 index 0000000..ed81d00 Binary files /dev/null and b/imgs/python_33_8.JPG differ diff --git a/imgs/python_33_9.JPG b/imgs/python_33_9.JPG new file mode 100644 index 0000000..5354f58 Binary files /dev/null and b/imgs/python_33_9.JPG differ diff --git a/imgs/python_34_1.JPG b/imgs/python_34_1.JPG new file mode 100644 index 0000000..35c28db Binary files /dev/null and b/imgs/python_34_1.JPG differ diff --git a/imgs/python_34_2.JPG b/imgs/python_34_2.JPG new file mode 100644 index 0000000..312f280 Binary files /dev/null and b/imgs/python_34_2.JPG differ diff --git a/imgs/python_34_3.JPG b/imgs/python_34_3.JPG new file mode 100644 index 0000000..6addbdf Binary files /dev/null and b/imgs/python_34_3.JPG differ diff --git a/imgs/python_34_4.JPG b/imgs/python_34_4.JPG new file mode 100644 index 0000000..bf1e888 Binary files /dev/null and b/imgs/python_34_4.JPG differ diff --git a/imgs/python_34_5.JPG b/imgs/python_34_5.JPG new file mode 100644 index 0000000..912602f Binary files /dev/null and b/imgs/python_34_5.JPG differ