commit 81ebee9cf34564a0eb010dc5b9d55c82f907fbb7 Author: aaronxu <3448711340@qq.com> Date: Wed Aug 27 14:39:37 2025 +0800 first commit diff --git a/01.基础语法/01.python基础.md b/01.基础语法/01.python基础.md new file mode 100644 index 0000000..7b861e2 --- /dev/null +++ b/01.基础语法/01.python基础.md @@ -0,0 +1,913 @@ +# Python基础 + +## 安装python + +略 + +## 运行python代码 + +在硬盘创建文件 t1.py,并且使用 PyCharm 打开,输入以下代码 + +```python +print('Hello World!') +``` + +然后右键运行 + +![image](01.python基础/1553917000771-909b5d59-8d4a-4e57-9dfe-95f0ba3a12ee.png) + +运行结果 + +``` +C:\Users\Aaron\AppData\Local\Programs\Python\Python35\python.exe C:/Users/Aaron/Desktop/py/t1.py +Hello World! + +Process finished with exit code 0 +``` + +## 注释 + +当行注释:# 被注释内容 + +多行注释:''' 被注释内容 ''',或者 """ 被注释内容 """ + +## 变量 + +变量是什么? 变量:把程序运行的中间结果临时的存在内存里,以便后续的代码调用。 + +## 声明变量 + +```python +a = "Hello World!" +print(a) +``` + +## 变量定义的规则 + +- 变量名只能是 字母、数字或下划线的任意组合 +- 变量名的第一个字符不能是数字 +- 以下关键字不能声明为变量名 +- ['and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'exec', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'not', 'or', 'pass', 'print', 'raise', 'return', 'try', 'while', 'with', 'yield'] +- 变量的定义要具有可描述性。 + +## 变量的赋值 + +```python +a = "变量1" +b = "变量2" +``` + + + +![image](01.python基础/1553917013597-9d6b5e70-3c79-4042-81a1-2459eca7cae8.png) + + + +```python +a = "变量1" +b = a +``` + + + +![image](01.python基础/1553917020154-5c92c78b-e289-42a7-8b42-d6f563ed4dad.png) + + + +## 常量 + +常量即指不变的量,如 pi 3.141592653..., 或在程序运行过程中不会改变的量。 + +## 程序交互 + +```python +name = input("请输入姓名:") +print(name) +``` + +执行脚本就会发现,程序会等待你输入姓名后再往下继续走。 + +```python +请输入姓名:Aaron +Aaron +``` + +## 基础数据类型 + +### 整数型(int) + +在 32 位机器上,整数的位数为 32 位,取值范围为 -2**31~2**31-1,即 -2147483648~2147483647 + +在 64 位系统上,整数的位数为 64 位,取值范围为 -2**63~2**63-1,即 -9223372036854775808~9223372036854775807 + +注意:在 Python3 里不再有 long 类型了,全都是 int + +```python +a = 2**64 +print(type(a)) #type()是查看数据类型的方法 + +b = 2**60 +print(type(b)) +``` + +运行结果 + +```python + + +``` + +## 字符串类型(str) + +在 Python 中, 加了引号的字符都被认为是字符串! + +```python +a = "Eagle's Lab" +b = ''' +欢迎大家来到英格科技! +今天我们学习python!''' + +print(a,b) +``` + +运行结果 + +```python +Eagle's Lab +欢迎大家来到英格科技! +今天我们学习python! +``` + +字符串拼接 + +```python +a = 'eagle ' +b = 'welcome ' +print(b + a,'*' * 3,a * 3) +``` + +运行结果 + +```python +welcome eagle *** eagle eagle eagle +``` + +## 布尔值(True, False) + +布尔类型很简单,就两个值 ,一个 True(真),一个 False(假), 主要用记逻辑判断 + +```python +a = 3 +b = 5 +print(a < b, a > b , a != b) +``` + +运行结果 + +``` +True False True +``` + +## 格式化输出 + +```python +name = input("姓名:") +age = input("年龄:") +job = input("工作:") +info = ''' +----------- info of %s ----------- +姓名:%s +年龄:%s +工作:%s +''' % (name,name,age,job) +print(info) +``` + +运行结果 + +``` +姓名:Aaron +年龄:18 +工作:Teacher +----------- info of Aaron ----------- +姓名:Aaron +年龄:18 +工作:Teacher +``` + +## 基本运算符 + +算数运算 + +| 运算符 | 描述 | 实例 | +| ------ | -------------- | ----------------- | +| + | 加 | a+b 输出结果30 | +| - | 减 | a-b 输出结果-10 | +| * | 乘 | a*b 输出结果200 | +| / | 除 | b/a 输出结果2 | +| % | 取模 得到余数 | b%a 输出结果0 | +| ** | 幂 | a**2 输出结果100 | +| // | 取整 | 9//2 输出结果4 | + +比较运算 + +| 运算符 | 描述 | 实例 | +| ------ | -------- | ----------------- | +| == | 等于 | a == b 返回False | +| != | 不等于 | a != b 返回True | +| <> | 不等于 | a <> b 返回True | +| > | 大于 | a > b 返回False | +| < | 小于 | a < b 返回True | +| >= | 大于等于 | a >= b 返回False | +| <= | 小于等于 | a <= b 返回True | + +赋值运算 + +| 运算符 | 描述 | 实例 | +| ------ | ---------------- | --------- | +| = | 赋值运算符 | c = a + b | +| += | 加法赋值运算符 | c += a | +| -= | 加法赋值运算符 | c -= a | +| *= | 乘法赋值运算符 | c *= a | +| /= | 除法赋值运算符 | c /= a | +| %= | 取模赋值运算符 | c %= a | +| **= | 幂赋值运算符 | c **= a | +| //= | 取整除赋值运算符 | c //= a | + +逻辑运算 + +| 运算符 | 描述 | 实例 | +| ------ | ---- | ------------ | +| and | 与 | a and b | +| or | 或 | a or b | +| not | 非 | not(a and b) | + +在没有 () 的情况下 not 优先级高于 and,and 优先级高于 or,即优先级关系为()>not>and>or,同一优先级从左往右计算。 + +x or y , x 为真,值就是 x,x 为假,值是 y; x and y, x 为真,值是 y,x 为假,值是 x。 + +成员运算 + +| 运算符 | 描述 | 实例 | +| ------ | ------------------------------------------------- | ---------- | +| in | 如果在指定的序列中找到值返回True,否则返回False | x in y | +| not in | 如果在指定的序列中没有找到返回True,否则返回False | x not in y | + +```python +print('a' in 'abcd') +print('y' not in 'xyzasd') +``` + +运行结果 + +``` +True +False +``` + +**Python 运算符优先级** + +以下表格列出了从最高到最低优先级的所有运算符: + +| 运算符 | 描述 | +| ------------------------ | ------------------------------------------------------ | +| ** | 指数 (最高优先级) | +| ~ + - | 按位翻转, 一元加号和减号 (最后两个的方法名为 +@ 和 -@) | +| * / % // | 乘,除,取模和取整除 | +| + - | 加法减法 | +| >> << | 右移,左移运算符 | +| & | 位 'AND' | +| ^ | 位运算符 | +| <= < > >= | 比较运算符 | +| <> == != | 等于运算符 | +| = %= /= //= -= += *= **= | 赋值运算符 | +| is is not | 身份运算符 | +| in not in | 成员运算符 | +| not and or | 逻辑运算符 | + +## 流程控制之 --if + +单分支 + +```python +if 条件: + 满足条件后要执行的代码 +``` + +双分支 + +```python +""" +if 条件: + 满足条件执行代码 +else: + if条件不满足就走这段 +""" +age = 48 + +if age > 50 : + print("尚能饭否") +else: + print("廉颇老矣") +``` + +运行结果 + +``` +廉颇老矣 +``` + +if...else ... 可以有多个分支条件 + +```python +if 条件: + 满足条件执行代码 +elif 条件: + 上面的条件不满足就走这个 +elif 条件: + 上面的条件不满足就走这个 +elif 条件: + 上面的条件不满足就走这个 +else: + 上面所有的条件不满足就走这段 +``` + +## 流程控制之 --while + +基本循环 + +```python +while 条件: + 循环体 +``` + +如果条件为真,那么循环体则执行 + +如果条件为假,那么循环体不执行 + +循环中止语句 + +break 用于完全结束一个循环,跳出循环体执行循环后面的语句 + +continue 和 break 有点类似,区别在于 continue 只是终止本次循环,接着还执行后面的循环,break 则完全终止循环 + +```python +print('猜数字游戏开始') +num = 54 +while True: + guess = int(input("您猜数字是什么?(输入0-100的数字)")) + if guess < num: + print("您猜小了") + continue + elif guess > num: + print("您猜大了") + continue + break + +print("您猜对了!") +``` + +运行结果 + +``` +猜数字游戏开始 +您猜数字是什么?(输入0-100的数字)50 +您猜小了 +您猜数字是什么?(输入0-100的数字)60 +您猜大了 +您猜数字是什么?(输入0-100的数字)54 +您猜对了! +``` + +while ... else .. + +while 后面的 else 作用是指,当 while 循环正常执行完,中间没有被 break 中止的话,就会执行 else 后面的语句 + +## 基础数据类型 + +### 数字 (int) + +```python +v = 11 +data = v.bit_length() #当十进制用二进制表示时,最少使用的位数 +print(data) +``` + +运行结果 + +``` +4 +``` + +### 布尔值 ()bool + +布尔值就两种:True,False。就是反应条件的正确与否。 + +真 1 True。 + +假 0 False。 + +### 字符串 str + +#### 字符串的索引与切片 + +```python +a = 'ABCDEFGHIJK' +print(a[0]) +print(a[3]) +print(a[5]) +print(a[7]) + +a = 'ABCDEFGHIJK' +print(a[0:3]) +print(a[2:5]) +print(a[0:]) #默认到最后 +print(a[0:-1]) # -1 是列表中最后一个元素的索引,但是要满足顾头不顾腚的原则,所以取不到K元素 +print(a[0:5:2]) #加步长 +print(a[5:0:-2]) #反向加步长 +``` + +运行结果 + +``` +A +D +F +H +ABC +CDE +ABCDEFGHIJK +ABCDEFGHIJ +ACE +FDB +``` + +#### 字符串常用方法 + +```python +words = "beautiful is better than ugly." +print(words.capitalize()) #首字母大写 +print(words.swapcase()) #大小写翻转 +print(words.title()) #每个单词的首字母大写 + + + +## 内容居中,总长度,空白处填充 +a = "test" +ret = a.center(20,"*") +print(ret) + + +## 数字符串中的元素出现的个数 +ret = words.count("e",0,30) +print(ret) +a = "aisdjioadoiqwd12313assdj" + + + +## startswith 判断是否以...开头 +## endswith 判断是否以...结尾 +print(a.startswith("a")) +print(a.endswith("j")) +print(a.startswith('sdj',2,5)) +print(a.endswith('ado',7,10)) + + +## 寻找字符串中的元素是否存在 +print(a.find('sdj',1,10)) # 返回的找到的元素的索引,如果找不到返回-1 +print(a.index('sdj',1,10)) # 返回的找到的元素的索引,找不到报错。 + + +## split 以什么分割,最终形成一个列表此列表不含有这个分割的元素。 +ret = words.split(' ') +print(ret) +ret = words.rsplit(' ',2) +print(ret) + + +## format的三种玩法 格式化输出 +print('{} {} {}'.format('aaron',18,'teacher')) +print('{1} {0} {1}'.format('aaron',18,'teacher')) +print('{name} {age} {job}'.format(job='teacher',name='aaron',age=18)) + + +## strip +a = '****asdasdasd********' +print(a.strip('*')) +print(a.lstrip('*')) +print(a.rstrip('*')) + + +## replace +print(words.replace('e','a',2)) +print(words.isalnum()) #字符串由字母或数字组成 +print(words.isalpha()) #字符串只由字母组成 +print(words.isdigit()) #字符串只由数字组成 +``` + +### 元祖 tuple + +元组被称为只读列表,即数据可以被查询,但不能被修改。 + +### 列表 list + +列表相比于字符串,不仅可以储存不同的数据类型,而且可以储存大量数据,32 位 python 的限制是 536870912 个元素,64 位 python 的限制是 1152921504606846975 个元素。而且列表是有序的,有索引值,可切片,方便取值。 + +#### 增 + +```python +li = [1,'a',2,'d',4] +li.insert(0,22) # 按照索引去增加 +print(li) +li.append('ddd') # 增加到最后 +print(li) +li.extend(['q,a,w']) # 迭代的去增 +print(li) +li.extend(['q,a,w','das']) # 迭代的去增 +print(li) +``` + +运行结果 + +``` +[22, 1, 'a', 2, 'd', 4] +[22, 1, 'a', 2, 'd', 4, 'ddd'] +[22, 1, 'a', 2, 'd', 4, 'ddd', 'q,a,w'] +[22, 1, 'a', 2, 'd', 4, 'ddd', 'q,a,w', 'q,a,w', 'das'] +``` + +#### 删 + +```python +li = [1,'a',2,'d',4,5,'f'] +a = li.pop(1) # 按照位置去删除,有返回值 +print(a) +del li[1:3] # 按照位置去删除,也可切片删除没有返回值。 +print(li) +li.remove('f') +print(li) +li.clear() +print(li) +``` + +运行结果 + +``` +a +[1, 4, 5, 'f'] +[1, 4, 5] +[] +``` + +#### 改 + +```python +li = [1,'a',2,'d',4,5,'f'] +li[1] = 'aaa' +print(li) +li[2:3] = [3,'e'] +print (li) +``` + +运行结果 + +``` +[1, 'aaa', 2, 'd', 4, 5, 'f'] +[1, 'aaa', 3, 'e', 'd', 4, 5, 'f'] +``` + +#### 查 + +切片去查,或者循环去查。 + +#### 其他操作 + +```python +li = [1,2,4,5,4,2,4] +print (li.count(4)) # 统计某个元素在列表中出现的次数 +print (li.index(2)) # 用于从列表中找出某个值第一个匹配项的索引位置 +li.sort() # 用于在原位置对列表进行排序 +print (li) +li.reverse() # 将列表中的元素反向存放 +print (li) +``` + +运行结果 + +``` +3 +1 +[1, 2, 2, 4, 4, 4, 5] +[5, 4, 4, 4, 2, 2, 1] +``` + +### 字典dict + +字典是python中唯一的映射类型,采用键值对(key-value)的形式存储数据。python对key进行哈希函数运算,根据计算的结果决定value的存储地址,所以字典是无序存储的,且key必须是可哈希的。可哈希表示key必须是不可变类型,如:数字、字符串、元组。 + +#### 增 + +```python +dic = {"age":18, "name":"aaron"} + +dic['li'] = ["a","b","c"] +print(dic) + +dic.setdefault('k','v') +## 在字典中添加键值对,如果只有键那对应的值是none,但是如果原字典中存在设置的键值对,则他不会更改或者覆盖。 +print(dic) + +dic.setdefault('k','v1') +print(dic) +``` + +#### 删 + +```python +dic = {"age":18, "name":"aaron"} + +dic_pop = dic.pop('age') +## pop根据key删除键值对,并返回对应的值,如果没有key则返回默认返回值 +print(dic_pop) + +dic_pop = dic.pop('sex','查无此项') +print(dic_pop) + +dic['age'] = 18 +print(dic) + +del dic['name'] +print(dic) + +dic['name'] = 'demo' +dic_pop = dic.popitem() +## 随机删除字典中的某个键值对,将删除的键值对以元祖的形式返回 +print(dic_pop) + +dic_clear = dic.clear() +## 清空字典 +print(dic,dic_clear) +``` + +#### 改 + +```python +dic = {"age":18, "name":"aaron", 'sex':'male'} +dic2 = {"age":30, "name":'demo'} + +dic2.update(dic) +## 将dic所有的键值对覆盖添加(相同的覆盖,没有的添加)到dic2中 +print(dic2) + +dic2['age'] = 30 +print(dic2) +``` + +#### 查 + +```python +dic = {"age":18, "name":"aaron", 'sex':'male'} + +value = dic['name'] +## 没有会报错 +print(value) + +value = dic.get('abc','查无此项') +print(value) +``` + +#### 其他操作 + +```python +dic = {"age":18, "name":"aaron", 'sex':'male'} + +for i in dic.items(): + # 将键和值作为元祖列出 + print(i) + +for key,value in dic.items(): + print(key,value) + +for i in dic: + # 只是迭代键 + print(i) + +keys = dic.keys() +print(keys,type(keys)) + +value = dic.values() +print(value,type(value)) +``` + +### 集合set + +集合是无序的,不重复的数据集合,它里面的元素是可哈希的(不可变类型),但是集合本身是不可哈希(所以集合做不了字典的键)的。以下是集合最重要的两点: + +- 去重,把一个列表变成集合,就自动去重了。 +- 关系测试,测试两组数据之前的交集、差集、并集等关系。 + +#### 创建集合 + +```python +set1 = set({1,2,'barry'}) +set2 = {1,2,'barry'} + +print(set1,set2) +``` + +#### 集合的增 + +```python +set1 = {'abc','def',123,'asdas'} + +set1.add('qwer') +print(set1) + +set1.update('A') +#update:迭代着增加 +print(set1) + +set1.update('哈哈哈') +print(set1) + +set1.update([1,2,3]) +print(set1) +``` + +#### 集合的删 + +```python +set1 = {'abc','def',123,'asdas'} + +set1.remove('abc') +print(set1) + +set1.pop() +## 随机删除一个数 +print(set1) + +set1.clear() +## 清空合集 +print(set1) + +del set1 +## 删除合集 +print(set1) +``` + +#### 集合的其他操作 + +###### 交集(& 或者 intersection) + +```python +set1 = {1,2,3,4,5} +set2 = {3,4,5,6,7} + +print(set1 & set2) + +print(set1.intersection(set2)) + +## 列出两个集合中共同拥有的项 +``` + +##### 并集(|或者 union) + +```python +set1 = {1,2,3,4,5} +set2 = {3,4,5,6,7} + +print(set1 | set2) + +print(set2.union(set1)) + +## 列出两个集合中所有的项 +``` + +##### 差集(- 或者 difference) + +```python +set1 = {1,2,3,4,5} +set2 = {3,4,5,6,7} + +print(set1 - set2) + +print(set1.difference(set2)) + +## 在set1中删除set2中有的项 +``` + +##### 反交集 (^ 或者 symmetric_difference) + +```python +set1 = {1,2,3,4,5} +set2 = {3,4,5,6,7} + +print(set1 ^ set2) + +print(set1.symmetric_difference(set2)) + +## 显示set1和set2不共存的项 +``` + +##### 子集与超集 + +```python +set1 = {1,2,3} +set2 = {1,2,3,4,5,6} + +print(set1 < set2) +print(set1.issubset(set2)) # 这两个相同,都是说明set1是set2子集。 + +print(set2 > set1) +print(set2.issuperset(set1)) # 这两个相同,都是说明set2是set1超集 +``` + +##### frozenset不可变集合,让集合变成不可变类型 + +```python +set1 = {1,2,3,4,5,6} + +s = frozenset(set1) +print(s,type(s)) + +s.add(7) # 不可以修改,会报错 +``` + +## 基础数据类型的总结 + +### 按存储空间的占用分(从低到高) + +1. 数字 +2. 字符串 +3. 集合:无序,即无序存索引相关信息 +4. 元组:有序,需要存索引相关信息,不可变 +5. 列表:有序,需要存索引相关信息,可变,需要处理数据的增删改 +6. 字典:无序,需要存key与value映射的相关信息,可变,需要处理数据的增删改 + +### 按存值个数区分 + +| 标量/原子类型 | 数字,字符串 | +| -------------- | ---------------- | +| 容器类型 | 列表,元组,字典 | + +### 按可变不可变区分 + +| 可变 | 列表,字典 | +| ------ | -------------------------- | +| 不可变 | 数字,字符串,元组,布尔值 | + +### 按访问顺序区分 + +| 直接访问 | 数字 | +| --------------------- | ------------------ | +| 顺序访问(序列类型) | 字符串,列表,元组 | +| key值访问(映射类型) | 字典 | + +## 其他(for,enumerate,range) + +for循环:用户按照顺序循环可迭代对象的内容。 + +```python +s = '先帝创业未半而中道崩殂,今天下三分,益州疲弊,此诚危急存亡之秋也。' + +for i in s: + print(i) + +li = ['甲','乙','丙','丁'] +for i in li: + print(i) + +dic = {'a':1,'b':2,'c':3} +for k,v in dic.items(): + print(k,v) +``` + +enumerate:枚举,对于一个可迭代的(iterable)/可遍历的对象(如列表、字符串),enumerate将其组成一个索引序列,利用它可以同时获得索引和值。 + +```python +li = ['甲','乙','丙','丁'] +for i in li: + print(i) + +for i in enumerate(li): + print(i) + +for index,value in enumerate(li): + print(index,value) + +for index,value in enumerate(li,100): #从哪个数字开始索引 + print(index,value) +``` + +range:指定范围,生成指定数字。 + +```python +for i in range(1,10): + print(i) + +for i in range(1,10,2): # 步长 + print(i) + +for i in range(10,1,-2): # 反向步长 + print(i) +``` \ No newline at end of file diff --git a/01.基础语法/01.python基础/1553917000771-909b5d59-8d4a-4e57-9dfe-95f0ba3a12ee.png b/01.基础语法/01.python基础/1553917000771-909b5d59-8d4a-4e57-9dfe-95f0ba3a12ee.png new file mode 100644 index 0000000..71c066b Binary files /dev/null and b/01.基础语法/01.python基础/1553917000771-909b5d59-8d4a-4e57-9dfe-95f0ba3a12ee.png differ diff --git a/01.基础语法/01.python基础/1553917013597-9d6b5e70-3c79-4042-81a1-2459eca7cae8.png b/01.基础语法/01.python基础/1553917013597-9d6b5e70-3c79-4042-81a1-2459eca7cae8.png new file mode 100644 index 0000000..8d23449 Binary files /dev/null and b/01.基础语法/01.python基础/1553917013597-9d6b5e70-3c79-4042-81a1-2459eca7cae8.png differ diff --git a/01.基础语法/01.python基础/1553917020154-5c92c78b-e289-42a7-8b42-d6f563ed4dad.png b/01.基础语法/01.python基础/1553917020154-5c92c78b-e289-42a7-8b42-d6f563ed4dad.png new file mode 100644 index 0000000..f809fee Binary files /dev/null and b/01.基础语法/01.python基础/1553917020154-5c92c78b-e289-42a7-8b42-d6f563ed4dad.png differ diff --git a/01.基础语法/01.python基础/1553917053256-ad06118c-368c-44d0-9ecc-23892b2067a2.png b/01.基础语法/01.python基础/1553917053256-ad06118c-368c-44d0-9ecc-23892b2067a2.png new file mode 100644 index 0000000..6238d01 Binary files /dev/null and b/01.基础语法/01.python基础/1553917053256-ad06118c-368c-44d0-9ecc-23892b2067a2.png differ diff --git a/01.基础语法/01.python基础/1553917057847-bf765831-83cb-4d40-8c5c-fcf53e74fb1c.png b/01.基础语法/01.python基础/1553917057847-bf765831-83cb-4d40-8c5c-fcf53e74fb1c.png new file mode 100644 index 0000000..2dd7ca7 Binary files /dev/null and b/01.基础语法/01.python基础/1553917057847-bf765831-83cb-4d40-8c5c-fcf53e74fb1c.png differ diff --git a/01.基础语法/01.python基础/1553917063983-03022732-9ed6-4caa-a44b-8382ed823db5.png b/01.基础语法/01.python基础/1553917063983-03022732-9ed6-4caa-a44b-8382ed823db5.png new file mode 100644 index 0000000..8fd6a07 Binary files /dev/null and b/01.基础语法/01.python基础/1553917063983-03022732-9ed6-4caa-a44b-8382ed823db5.png differ diff --git a/01.基础语法/01.python基础/1553917069436-348739b7-22b4-4758-958c-821027d56553.png b/01.基础语法/01.python基础/1553917069436-348739b7-22b4-4758-958c-821027d56553.png new file mode 100644 index 0000000..46b67db Binary files /dev/null and b/01.基础语法/01.python基础/1553917069436-348739b7-22b4-4758-958c-821027d56553.png differ diff --git a/01.基础语法/01.python基础/1553917075110-f7a4b9d5-85df-45a4-b44b-935df9e88231.png b/01.基础语法/01.python基础/1553917075110-f7a4b9d5-85df-45a4-b44b-935df9e88231.png new file mode 100644 index 0000000..52b2ca0 Binary files /dev/null and b/01.基础语法/01.python基础/1553917075110-f7a4b9d5-85df-45a4-b44b-935df9e88231.png differ diff --git a/01.基础语法/02.python文件操作.md b/01.基础语法/02.python文件操作.md new file mode 100644 index 0000000..e5f36ce --- /dev/null +++ b/01.基础语法/02.python文件操作.md @@ -0,0 +1,321 @@ +# Python文件操作 + +## 文件操作基本流程 + + + +```python +#1. 打开文件,得到文件句柄并赋值给一个变量 +f=open('a.txt','r',encoding='utf-8') #默认打开模式就为r + +#2. 通过句柄对文件进行操作 +data=f.read() + +#3. 关闭文件 +f.close() +``` + + + +打开一个文件包含两部分资源:操作系统级打开的文件+应用程序的变量。在操作完毕一个文件时,必须把与该文件的这两部分资源一个不落地回收,回收方法为: + + + +```python +f.close() +# 回收操作系统级打开的文件 +def f +# 回收应用程序级的变量 +``` + + + +在操作完毕文件后,一定要记住f.close(),推荐操作方式:使用with关键字来帮我们管理上下文 + + + +```python +with open('a.txt','r') as read_f,open('b.txt','w') as write_f: + data=read_f.read() + write_f.write(data) +``` + + + +## 文件编码 + + + +f=open(...)是由操作系统打开文件,那么如果我们没有为open指定编码,那么打开文件的默认编码很明显是操作系统说了算了,操作系统会用自己的默认编码去打开文件,在windows下是gbk,在linux下是utf-8。 + + + +```python +f=open('a.txt','r',encoding='utf-8') +``` + + + +## 文件的打开模式 + + + +### 打开文件的模式 + + + +| r | 只读模式【默认模式,文件必须存在,不存在则抛出异常】 | +| ---- | ------------------------------------------------------ | +| w | 只写模式【不可读;不存在则创建;存在则清空内容】 | +| a | 只追加写模式【不可读;不存在则创建;存在则只追加内容】 | + + + +对于非文本文件,我们只能使用b模式,"b"表示以字节的方式操作(而所有文件也都是以字节的形式存储的,使用这种模式无需考虑文本文件的字符编码、图片文件的jgp格式、视频文件的avi格式) + + + +rb + +wb + +ab + + + +注:以b方式打开时,读取到的内容是字节类型,写入时也需要提供字节类型,不能指定编码 + + + +### ‘+’模式(就是增加了一个功能) + + + +| r+ | 读写【可读,可写】 | +| ---- | ------------------ | +| w+ | 写读【可写,可读】 | +| a+ | 写读【可写,可读】 | + +| 模式 | 可做操作 | 若文件不存在 | 是否覆盖 | +| ---- | -------- | ------------ | ---------- | +| r | 只能读 | 报错 | - | +| r+ | 可读可写 | 报错 | 是 | +| w | 只能写 | 创建 | 是 | +| w+ | 可读可写 | 创建 | 是 | +| a | 只能写 | 创建 | 否,追加写 | +| a+ | 可读可写 | 创建 | 否,追加写 | + +### 以bytes类型操作的读写,写读,写读模式 + + + +| r+b | 读写【可读,可写】 | +| ---- | ------------------ | +| w+b | 写读【可写,可读】 | +| a+b | 写读【可写,可读】 | + + + +## 文件操作方法 + + + +### 常用操作方法 + + + +read(3): + + + +1. 文件打开方式为文本模式时,代表读取3个字符 +2. 文件打开方式为b模式时,代表读取3个字节 + + + +其余的文件内光标移动都是以字节为单位的如:seek,tell,truncate + + + +注意: + + + +1. seek有三种移动方式0,1,2,其中1和2必须在b模式下进行,但无论哪种模式,都是以bytes为单位移动的 +2. truncate是截断文件,所以文件的打开方式必须可写,但是不能用w或w+等方式打开,因为那样直接清空文件了,所以truncate要在r+或a或a+等模式下测试效果。 + + + +### 所有的操作方法 + + + +```python +def close(self, *args, **kwargs): # real signature unknown + 关闭文件 + pass + +def fileno(self, *args, **kwargs): # real signature unknown + 文件描述符 + pass + +def flush(self, *args, **kwargs): # real signature unknown + 刷新文件内部缓冲区 + pass + +def isatty(self, *args, **kwargs): # real signature unknown + 判断文件是否是同意tty设备 + pass + +def read(self, *args, **kwargs): # real signature unknown + 读取指定字节数据 + pass + +def readable(self, *args, **kwargs): # real signature unknown + 是否可读 + pass + +def readline(self, *args, **kwargs): # real signature unknown + 仅读取一行数据 + pass + +def seek(self, *args, **kwargs): # real signature unknown + 指定文件中指针位置 + pass + +def seekable(self, *args, **kwargs): # real signature unknown + 指针是否可操作 + pass + +def tell(self, *args, **kwargs): # real signature unknown + 获取指针位置 + pass + +def truncate(self, *args, **kwargs): # real signature unknown + 截断数据,仅保留指定之前数据 + pass + +def writable(self, *args, **kwargs): # real signature unknown + 是否可写 + pass + +def write(self, *args, **kwargs): # real signature unknown + 写内容 + pass + +def __getstate__(self, *args, **kwargs): # real signature unknown + pass + +def __init__(self, *args, **kwargs): # real signature unknown + pass + +@staticmethod # known case of __new__ +def __new__(*args, **kwargs): # real signature unknown + """ Create and return a new object. See help(type) for accurate signature. """ + pass + +def __next__(self, *args, **kwargs): # real signature unknown + """ Implement next(self). """ + pass + +def __repr__(self, *args, **kwargs): # real signature unknown + """ Return repr(self). """ + pass +``` + + + +## 文件的修改 + + + +文件的数据是存放于硬盘上的,因而只存在覆盖、不存在修改这么一说,我们平时看到的修改文件,都是模拟出来的效果,具体的说有两种实现方式: + + + +方式一:将硬盘存放的该文件的内容全部加载到内存,在内存中是可以修改的,修改完毕后,再由内存覆盖到硬盘(word,vim,nodpad++等编辑器) + + + +```python +import os + +with open('a.txt') as read_f,open('a.txt.new','w') as write_f: + data = read_f.read() + data = data.replace('Hello','nihao') + + write_f.write(data) + +os.remove('a.txt') +os.rename('a.txt.new','a.txt') +``` + + + +方式二:将硬盘存放的该文件的内容一行一行地读入内存,修改完毕就写入新文件,最后用新文件覆盖源文件 + + + +```python +import os + +with open('a.txt') as read_f,open('a.txt.new','w') as write_f: + for line in read_f: + line = line.replace('nihao','Hello') + write_f.write(line) + +os.remove('a.txt') +os.rename('a.txt.new','a.txt') +``` + + + +## 小测验 + + + +文件a.txt内容:每一行内容分别为商品名字,价钱,个数。 + + + +apple 10 3 + + + +tesla 100000 1 + + + +mac 3000 2 + + + +lenovo 30000 3 + + + +chicken 10 3 + + + +通过代码,将其构建成这种数据类型:[{'name':'apple','price':10,'amount':3},{'name':'tesla','price':1000000,'amount':1}......] 并计算出总价钱。 + + + +```python +list = [] +with open('a.txt','r',encoding='utf-8') as file: + for line in file: + list2 = line.strip().split() + if list2: + dic = {'name':list2[0],'price':list2[1],'amount':list2[2]} + list.append(dic) + continue + +print(list) +price = 0 +for i in list: + price += int(i['price']) * int(i['amount']) + +print(price) +``` \ No newline at end of file diff --git a/01.基础语法/03.python认识函数.md b/01.基础语法/03.python认识函数.md new file mode 100644 index 0000000..69c7fb4 --- /dev/null +++ b/01.基础语法/03.python认识函数.md @@ -0,0 +1,410 @@ +# 认识函数 + +## 什么是函数 + +函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。 + +## 函数的定义与调用 + +```python +def my_len(): + s = 'hello world' + length = 0 + for i in s: + length = length + 1 + print(length) + +my_len() +``` + +```python +定义:def 关键词开头,空格之后接函数名称和圆括号(),最后还有一个":"。 + +   def 是固定的,不能变,他就是定义函数的关键字。 + +   空格 为了将def关键字和函数名分开,必须空(四声),当然你可以空2格、3格或者你想空多少都行,但正常人还是空1格。 + +   函数名:函数名只能包含字符串、下划线和数字且不能以数字开头。虽然函数名可以随便起,但我们给函数起名字还是要尽量简短,并能表达函数功能 + +   括号:是必须加的,先别问为啥要有括号,总之加上括号就对了! + +注释:每一个函数都应该对功能和参数进行相应的说明,应该写在函数下面第一行。以增强代码的可读性。 + +调用:就是 函数名() 要记得加上括号。 +``` + +## 函数的返回值 + +```python +def my_len(): + s = 'hello world' + length = 0 + for i in s: + length = length + 1 + return length + +str_len = my_len() +print(str_len) +``` + +**return关键字的作用** + +- return 是一个关键字,这个词翻译过来就是“返回”,所以我们管写在return后面的值叫“返回值”。 +- 不写return的情况下,会默认返回一个None +- 一旦遇到return,结束整个函数。 +- 返回的多个值会被组织成元组被返回,也可以用多个值来接收 + +```python +def ret_demo(): + return 1,2,'a',['hello','world'] + +ret = ret_demo() +print(ret) +``` + +## 函数的参数 + +带参数的函数 + +```python +def my_len(s): + length = 0 + for i in s: + length += 1 + return length + +ret = my_len('hello world!') +print(ret) +``` + +实际的要交给函数的内容,简称实参。 + +在定义函数的时候它只是一个形式,表示这里有一个参数,简称形参。 + +1. 按照位置传值:位置参数 + +```python +def maxnumber(x,y): + the_max = x if x > y else y + return the_max + +ret = maxnumber(10,20) +print(ret) +``` + +1. 按照关键字传值:关键字参数。 + +```python +def maxnumber(x,y): + the_max = x if x > y else y + return the_max + +ret = maxnumber(y = 10,x = 20) +print(ret) +``` + +1. 位置、关键字形式混着用:混合传参。 + +```python +def maxnumber(x,y): + the_max = x if x > y else y + return the_max + +ret = maxnumber(10,y = 20) +print(ret) +``` + +位置参数必须在关键字参数的前面 + +对于一个形参只能赋值一次 + +1. 默认参数。 + +```python +def stu_info(name,age = 18): + print(name,age) + +stu_info('aaron') +stu_info('song',50) +``` + +1. 默认参数是一个可变数据类型 + +```python +def demo(a,l = []): + l.append(a) + print(l) + +demo('abc') +demo('123') +``` + +1. 动态参数 + +```python +def demo(*args,**kwargs): + print(args,type(args)) + print(kwargs,type(kwargs)) + +demo('aaron',1,3,[1,3,2,2],{'a':123,'b':321},country='china',b=1) + +##动态参数,也叫不定长传参,就是你需要传给函数的参数很多,不定个数,那这种情况下,你就用*args,**kwargs接收,args是元祖形式,接收除去键值对以外的所有参数,kwargs接收的只是键值对的参数,并保存在字典中。 +``` + +## 命名空间和作用域 + +代码在运行伊始,创建的存储“变量名与值的关系”的空间叫做全局命名空间; + +在函数的运行中开辟的临时的空间叫做局部命名空间。 + +命名空间一共分为三种: + +- 全局命名空间 +- 局部命名空间 +- 内置命名空间 + +取值顺序: + +- 在局部调用:局部命名空间->全局命名空间->内置命名空间 +- 在全局调用:全局命名空间->内置命名空间 + +作用域 + +- 全局作用域:包含内置名称空间、全局名称空间,在整个文件的任意位置都能被引用、全局有效 +- 局部作用域:局部名称空间,只能在局部范围内生效 + +### globals和locals方法 + +```python +print(globals()) +print(locals()) + +def func(): + a = 12 + b = 20 + print(globals()) + print(locals()) + +func() +``` + +**global** + +1. 声明一个全局变量。 +2. 在局部作用域想要对全局作用域的全局变量进行修改时,需要用到 global(限于字符串,数字)。 + +```python +def func(): + global a + a = 3 + +func() +print(a) + +count = 1 +def search(): + global count + count = 2 + +search() +print(count) +``` + +对可变数据类型(list,dict,set)可以直接引用不用通过global + +```python +li = [1,2,3] +dic = {'name':'aaron'} + +def change(): + li.append(4) + dic['age'] = 18 + print(dic) + print(li) + +change() +print(dic) +print(li) +``` + +**nonlocal** + +1. 不能修改全局变量。 +2. 在局部作用域中,对父级作用域(或者更外层作用域非全局作用域)的变量进行引用和修改,并且引用的哪层,从那层及以下此变量全部发生改变。 + +```python +def add_b(): + b = 1 + def do_global(): + b = 10 + print(b) + def dd_nolocal(): + nonlocal b # 应用了上一层的变量b + b = b + 20 + print(b) # 发生了改变 + dd_nolocal() # 调用函数,导致do_global的命名空间b也改变了 + print(b) + do_global() + print(b) +add_b() # 最上面一层没有变化 +``` + +## 函数的嵌套和作用域链 + +```python +def mymax(x,y): + m = x if x > y else y + return m + +def maxx(a,b,c,d): + res1 = mymax(a,b) + res2 = mymax(res1,c) + res3 = mymax(res2,d) + return res3 + +ret = maxx(23,453,12,-13) +print(ret) +``` + +```python +def f1(): + print("in f1") + def f2(): + print("in f2") + f2() + +f1() +``` + +## 函数名的本质 + +函数名本质上就是函数的内存地址 + +1. 可以被引用 + +```python +def func(): + print('in func') + +f = func + +print(f) +f() +``` + +1. 可以被当作容器类型的元素 + +```python +def f1(): + print('f1') + +def f2(): + print('f2') + +def f3(): + print('f3') + +l = [f1,f2,f3] +d = {'f1':f1,'f2':f2,'f3':f3} + +#调用 +l[0]() +d['f2']() +``` + +1. 可以当作函数的参数和返回值 + +```python +def f1(): + print('f1') + +def func(argv): + argv() + return argv + +f = func(f1) +f() +``` + +## 闭包 + +```python +def func(): + name = 'aaron' + def inner(): + print(name) + return inner + +f = func() +f() +``` + +内部函数包含对外部作用域而非全剧作用域变量的引用,该内部函数称为闭包函数 + +判断闭包函数的方法**closure** + +```python +def func(): + name = 'aaron' + def inner(): + print(name) + print(inner.__closure__) + return inner + +f = func() +f() +# 最后运行的结果里面有cell就是闭包 + +name = 'aaron' +def func(): + def inner(): + print(name) + print(inner.__closure__) + return inner + +f = func() +f() +# 输出结果为None,说明不是闭包 +``` + +```python +def wrapper(): + money = 1000 + def func(): + name = 'apple' + def inner(): + print(name,money) + return inner + return func + +f = wrapper() +i = f() +i() +``` + +```python +def func(a,b): + def inner(x): + return a*x + b + return inner + +func1 = func(4,5) +func2 = func(7,8) +print(func1(5),func2(6)) +``` + +```python +from urllib.request import urlopen +def func(): + content = urlopen('http://myip.ipip.net').read() + def get_content(): + return content + return get_content + +code = func() +content = code() +print(content.decode('utf-8')) + +content2 = code() +print(content2.decode('utf-8')) +``` \ No newline at end of file diff --git a/01.基础语法/04.装饰器.md b/01.基础语法/04.装饰器.md new file mode 100644 index 0000000..a3f7b57 --- /dev/null +++ b/01.基础语法/04.装饰器.md @@ -0,0 +1,175 @@ +# 装饰器 + +## 什么是装饰器 + +让其他函数在不需要做任何代码变动的前提下,增加额外的功能,装饰器的返回值也是一个函数对象。 + +装饰器的应用场景:比如插入日志,性能测试,事务处理,缓存等等场景。 + +## 装饰器的形成过程 + +如果我想测试某个函数的执行时间 + +```python +import time +def func1(): + print('in func1') +def timer(func): + def inner(): + start = time.time() + func() + print(time.time() - start) + return inner +func1 = timer(func1) +func1() +``` + +但是如果有多个函数,我都想让你测试他们的执行时间,你每次是不是都得func1 = timer(func1)?这样还是有点麻烦,因为这些函数的函数名可能是不相同,有func1,func2,graph,等等,所以更简单的方法,python给你提供了,那就是语法糖。 + +```python +import time +def timer(func): + def inner(): + start = time.time() + func() + print(time.time() - start) + return inner +@timer +def func1(): + time.sleep(1) + print('in func1') +func1() +``` + +装饰一个带参数的函数 + +```python +import time +def timer(func): + def inner(a): + start = time.time() + func(a) + print(time.time() - start) + return inner +@timer +def func1(a): + time.sleep(1) + print(a) +func1('hello world') +``` + +装饰一个带各种参数的函数 + +```python +import time +def timer(func): + def inner(*args,**kwargs): + start = time.time() + func(args,kwargs) + print(time.time() - start) + return inner +@timer +def func1(*args,**kwargs): + print(args,kwargs) +func1('hello world','abc',123,432) +``` + +查看函数的相关信息,在加上装饰器后就失效了 + +```python +def index(): + '''这是一条注释信息''' + print('from index') +print(index.__doc__) # 查看函数注释 +print(index.__name__) # 查看函数名称 +``` + +导入wraps装饰器 + +```python +from functools import wraps +def deco(func): + @wraps(func) + def wrapper(*args,**kwargs): + return func(*args,**kwargs) + return wrapper +@deco +def index(): + '''这是一条注释信息''' + print('from index') +print(index.__doc__) # 查看函数注释 +print(index.__name__) # 查看函数名称 +``` + +## 开放封闭原则 + +一句话,软件实体应该是可扩展但是不可修改的。 + +* 对于扩展是开放的 +* 对于修改是封闭的 + +装饰器完美的遵循了这个开放封闭原则 + +## 装饰器的主要功能和固定结构 + +```python +def timer(func): + def inner(*args,**kwargs): + '''执行函数之前要做的''' + re = func(*args,**kwargs) + '''执行函数之后要做的''' + return re + return inner +# 下面是加上wraps的固定结构 +from functools import wraps +def timer(func): + @wraps(func) + def wrapper(*args,**kwargs) + return func(*args,**kwargs) + return wrapper +``` + +## 带参数的装饰器 + +加上一个outer函数,可以携带一个flag的值,然后控制装饰器是否生效 + +```python +def outer(flag): + def timer(func): + def inner(*args,**kwargs): + if flag: + print('函数开始执行') + re = func(*args,**kwargs) + if flag: + print('函数执行完毕') + return re + return inner + return timer +@outer(True) +def func(): + print('test') +func() +``` + +## 多个装饰器装饰一个函数 + +```python +def wrapper1(func): + def inner(): + print('第一个装饰器,在程序运行之前') + func() + print('第一个装饰器,在程序运行之后') + return inner +def wrapper2(func): + def inner(): + print('第二个装饰器,在程序运行之前') + func() + print('第二个装饰器,在程序运行之后') + return inner +@wrapper1 +@wrapper2 +def f(): + print('Hello') +f() +``` + diff --git a/01.基础语法/05.迭代器与生成器.md b/01.基础语法/05.迭代器与生成器.md new file mode 100644 index 0000000..f21f2d9 --- /dev/null +++ b/01.基础语法/05.迭代器与生成器.md @@ -0,0 +1,177 @@ +# 迭代器与生成器 + +## 迭代器 + +字符串、列表、元组、字典、集合都可以被for循环,说明他们都是可迭代的 + +```python +from collections import Iterable +l = [1, 2, 3, 4] +t = (1, 2, 3, 4) +d = {1: 2, 3: 4} +s = {1, 2, 3, 4} +print(isinstance(l, Iterable)) +print(isinstance(t, Iterable)) +print(isinstance(d, Iterable)) +print(isinstance(s, Iterable)) +``` + +### 可迭代协议 + +可以被迭代要满足的要求就叫做可迭代协议。可迭代协议的定义非常简单,就是内部实现了iter方法。 + +```python +l = [1, 2, 3, 4] +t = (1, 2, 3, 4) +d = {1: 2, 3: 4} +s = {1, 2, 3, 4} +print(dir(l)) +print(dir(t)) +print(dir(d)) +print(dir(s)) +``` + +可迭代的:内部必须含有一个iter方法。 + +### 迭代器 + +```python +l = [1, 2, 3, 4] +l_iter = l.__iter__() +item = l_iter.__next__() +print(item) +item = l_iter.__next__() +print(item) +item = l_iter.__next__() +print(item) +item = l_iter.__next__() +print(item) +item = l_iter.__next__() +print(item) +``` + +迭代器遵循迭代器协议:必须拥有iter方法和next方法。 +for循环,能遍历一个可迭代对象,他的内部到底进行了什么? + +将可迭代对象转化成迭代器。(可迭代对象.iter()) + +内部使用next方法,一个一个取值。 + +加了异常处理功能,取值到底后自动停止。 + +```python +l = [1, 2, 3, 4] +l_iter = l.__iter__() +while True: + try: + item = l_iter.__next__() + print(item) + except StopIteration: + break +``` + +### 为什么要有for循环 + +for循环就是基于迭代器协议提供了一个统一的可以遍历所有对象的方法,即在遍历之前,先调用对象的iter方法将其转换成一个迭代器,然后使用迭代器协议去实现循环访问,这样所有的对象就都可以通过for循环来遍历了 + +最重要的一点,转化成迭代器,在循环时,同一时刻在内存中只出现一条数据,极大限度的节省了内存 + +## 生成器 + +### 初识生成器 + +**Python中提供的生成器** + +1. 生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行 +2. 生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表 + +**生成器Generator** + +* 本质:迭代器(所以自带了iter方法和next方法,不需要我们去实现) +* 特点:惰性运算,开发者自定义 + +### 生成器函数 + +一个包含yield关键字的函数就是一个生成器函数。yield可以为我们从函数中返回值,但是yield又不同于return,return的执行意味着程序的结束,调用生成器函数不会得到返回的具体的值,而是得到一个可迭代的对象。每一次获取这个可迭代对象的值,就能推动函数的执行,获取新的返回值。直到函数执行结束。 + +```python +import time +def genrator_func1(): + a = 1 + print('将a赋值') + yield a + b = 2 + print('将b赋值') + yield b +g1 = genrator_func1() +print(g1,next(g1)) +print(next(g1)) +``` + +生成器不会一下子在内存中生成太多数据 +比如我想卖包子,让包子工厂开始加工10000个包子,但是如果一下子全部生产好,没地方放,而且容易坏。 + +那么可以让包子工厂在我需要的时候再生产 + +```python +def produce(): + '''生产包子''' + for i in range(10000): + yield '生产了第%s个包子'%i +produce_g = produce() +print(produce_g.__next__()) +print(produce_g.__next__()) +print(produce_g.__next__()) + +# 需要一批包子 +num = 0 +for i in produce_g: + print(i) + num += 1 + if num == 5: + break +``` + +### send + +send 获取下一个值的效果和next基本一致 + +只是在获取下一个值的时候,给上一yield的位置传递一个数据 + +使用send的注意事项 + +* 第一次使用生成器的时候 是用next获取下一个值 +* 最后一个yield不能接受外部的值 + +```python +def generator(): + print(123) + content = yield 1 + print('=========',content) + print(456) + yield 2 +g = generator() +ret = g.__next__() +print('***',ret) +ret = g.send('hello') +print('***',ret) +``` + +## 列表推导式和生成器表达式 + +```python +l = [i for i in range(10)] +print(l) +l1 = ['项目%s'%i for i in range(10)] +print(l1) +``` + +1. 把列表解析的[]换成()得到的就是生成器表达式 +2. 列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存 +3. Python不但使用迭代器协议,让for循环变得更加通用。大部分内置函数,也是使用迭代器协议访问对象的。例如, sum函数是Python的内置函数,该函数使用迭代器协议访问对象,而生成器实现了迭代器协议,所以,我们可以直接这样计算一系列值的和: + +```python +ret = sum(x for x in range(101)) +print(ret) +``` + diff --git a/01.基础语法/06.推导式.md b/01.基础语法/06.推导式.md new file mode 100644 index 0000000..1218c41 --- /dev/null +++ b/01.基础语法/06.推导式.md @@ -0,0 +1,73 @@ +# 推导式 + +## 推导式详细格式 + +```plain +variable = [out_exp_res for out_exp in input_list if out_exp == 2] + out_exp_res:  列表生成元素表达式,可以是有返回值的函数。 + for out_exp in input_list:  迭代input_list将out_exp传入out_exp_res表达式中。 + if out_exp == 2:  根据条件过滤哪些值可以。 +``` + +## 列表推导式 + +30以内所有能被3整除的数 + +```python +multiples = [i for i in range(30) if i % 3 is 0] +print(multiples) +``` + +30以内所有能被3整除的数的平方 + +```python +def squared(x): + return x*x +multiples = [squared(i) for i in range(30) if i % 3 is 0] +print(multiples) +``` + +找到嵌套列表中名字含有两个及以上‘a’的所有名字 + +```python +fruits = [['peach','Lemon','Pear','avocado','cantaloupe','Banana','Grape'], + ['raisins','plum','apricot','nectarine','orange','papaya']] +print([name for lst in fruits for name in lst if name.count('a') >= 2]) +``` + +## 字典推导式 + +将一个字典的key和value对调 + +```python +dic1 = {'a':1,'b':2} +dic2 = {dic1[k]: k for k in dic1} +print(dic2) +``` + +合并大小写对应的value值,将k统一成小写 + +```python +dic1 = {'a':1,'b':2,'A':4,'Y':9} +dic2 = {k.lower():dic1.get(k.lower(),0) + dic1.get(k.upper(),0) for k in dic1.keys()} +print(dic2) +``` + +## 集合推导式 + +计算列表中每个值的平方,自带去重功能 + +```python +l = [1,2,3,4,1,-1,-2,3] +squared = {x**2 for x in l} +print(squared) +``` + +## 练习题 + +1. 过滤掉长度小于3的字符串列表,并将剩下的转换成大写字母 +2. 求(x,y)其中x是0-5之间的偶数,y是0-5之间的奇数组成的元祖列表 +3. 将1000以内的素数放入一个列表中 + + + diff --git a/01.基础语法/07.内置函数与匿名函数.md b/01.基础语法/07.内置函数与匿名函数.md new file mode 100644 index 0000000..fff6a16 --- /dev/null +++ b/01.基础语法/07.内置函数与匿名函数.md @@ -0,0 +1,535 @@ +# 内置函数与匿名函数 + +## 内置函数 + +截止到python版本3.6.2,现在python一共为我们提供了**68个内置函数。** + +| 内置函数 | | | | | +| :------------ | :---------- | :----------- | :--------- | :------------- | +| abs() | dict() | help() | min() | setattr() | +| all() | dir() | hex() | next() | slice() | +| any() | divmod() | id() | object() | sorted() | +| ascii() | enumerate() | input() | oct() | staticmethod() | +| bin() | eval() | int() | open() | str() | +| bool() | exec() | isinstance() | ord() | sum() | +| bytearray() | filter() | issubclass() | pow() | super() | +| bytes() | float() | iter() | print() | tuple() | +| callable() | format() | len() | property() | type() | +| chr() | frozenset() | list() | range() | vars() | +| classmethod() | getattr() | locals() | repr() | zip() | +| compile() | globals() | map() | reversed() | __import__() | +| complex() | hasattr() | max() | round() | | +| delattr() | hash() | memoryview() | set() | | + +### 作用域相关 + +* locals :函数会以字典的类型返回当前位置的全部局部变量。 +* globals:函数以字典的类型返回全部全局变量。 + +```python +a = 1 +b = 2 +print(locals()) +print(globals()) +# 这两个一样,因为是在全局执行的 +def func(argv): + c = 2 + print(locals()) + print(globals()) +func(3) +``` + +### 其他相关 + +#### 字符串类型代码的执行 eval,exec,complie + +* eval:执行字符串类型的代码,并返回最终结果。 + +```python +ret = eval('2 + 2') +print(ret) +n = 20 +ret = eval('n + 23') +print(ret) +eval('print("Hello world")') +``` + +* exec:执行字符串类型的代码。 + +```python +s = ''' +for i in range(5): + print(i) +''' +exec(s) +``` + +compile:将字符串类型的代码编译。代码对象能够通过exec语句来执行或者eval()进行求值。 + +1. 参数source:字符串。即需要动态执行的代码段。 +2. 参数 filename:代码文件名称,如果不是从文件读取代码则传递一些可辨认的值。当传入了source参数时,filename参数传入空字符即可。 +3. 参数model:指定编译代码的种类,可以指定为 ‘exec’,’eval’,’single’。当source中包含流程语句时,model应指定为‘exec’;当source中只包含一个简单的求值表达式,model应指定为‘eval’;当source中包含了交互式命令语句,model应指定为'single'。 + +```python +# 流程语句使用exec +code1 = 'for i in range(5): print(i)' +compile1 = compile(code1,'','exec') +exec(compile1) +# 简单求值表达式用eval +code2 = '1 + 2 + 3' +compile2 = compile(code2,'','eval') +eval(compile2) +# 交互语句用single +code3 = 'name = input("please input you name: ")' +compile3 = compile(code3,'','single') +exec(compile3) +print(name) +``` + +有返回值的字符串形式的代码用eval,没有返回值的字符串形式的代码用exec,一般不用compile。 + +#### 输入输出相关 input,print + +* input:函数接受一个标准输入数据,返回为 string 类型。 +* print:打印输出。 + +```python +''' 源码分析 +def print(self, *args, sep=' ', end='\n', file=None): # known special case of print + """ + print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False) + file: 默认是输出到屏幕,如果设置为文件句柄,输出到文件 + sep: 打印多个值之间的分隔符,默认为空格 + end: 每一次打印的结尾,默认为换行符 + flush: 立即把内容输出到流文件,不作缓存 + """ +''' +print(11,22,33,sep='*') +print(11,22,33,end='') +print(44,55) +with open('log','w',encoding='utf-8') as f: + print('写入文件',file=f,flush=True) +``` + +#### 内存相关 hash id + +* hash:获取一个对象(可哈希对象:int,str,Bool,tuple)的哈希值。 + +```python +print(hash(12322)) +print(hash('123')) +print(hash('arg')) +print(hash('aaron')) +print(hash(True)) +print(hash(False)) +print(hash((1,2,3))) +``` + +* id:用于获取对象的内存地址。 + +```python +print(id('abc')) +print(id('123')) +``` + +#### 文件操作相关 + +* open:函数用于打开一个文件,创建一个 file 对象,相关的方法才可以调用它进行读写。 + +#### 模块相关`__import__` + +* `__import__`:函数用于动态加载类和函数 。 + +#### 帮助 + +* help:函数用于查看函数或模块用途的详细说明。 + +```python +print(help(print)) +``` + +#### 调用相关 + +* callable:函数用于检查一个对象是否是可调用的。如果返回True,object仍然可能调用失败;但如果返回- False,调用对象ojbect绝对不会成功。 + +```python +print(callable(0)) +print(callable('hello')) +def demo1(a, b): + return a + b +print(callable(demo1)) +class Demo2: + def test1(self): + return 0 +print(callable(Demo2)) +a = Demo2() +print(callable(a)) +# 没有实现 __call__, 返回 False +``` + +#### 查看内置属性 + +* dir:函数不带参数时,返回当前范围内的变量、方法和定义的类型列表;带参数时,返回参数的属性、方法列表。如果参数包含方法`__dir__()`,该方法将被调用。如果参数不包含`__dir__()`,该方法将最大限度地收集参数信息。 + +```python +print(dir()) # 获得当前模块的属性列表 +print(dir([ ])) # 查看列表的方法 +``` + +### 迭代器生成器相关 + +* range:函数可创建一个整数对象,一般用在 for 循环中。 +* next:内部实际使用了`__next__`方法,返回迭代器的下一个项目。 + +```python +# 首先获得Iterator对象: +it = iter([1,2,3,4,5,6]) +# 循环 +while True: + try: + # 获得下一个值 + x = next(it) + print(x) + except StopIteration: # 遇到StopIteration就退出循环 + break +``` + +* iter:函数用来生成迭代器(讲一个可迭代对象,生成迭代器)。 + +```python +from collections import Iterable +from collections import Iterator +l = [1,2,3,4] # 可迭代对象,但不是迭代器 +print(isinstance(l,Iterable)) +print(isinstance(l,Iterator)) +l1 = iter(l) # 从一个可迭代对象生成迭代器 +print(isinstance(l1,Iterable)) +print(isinstance(l1,Iterator)) +``` + +### 基础数据类型相关 + +#### 数字相关(14个) + +数据类型(4个): + +* bool :用于将给定参数转换为布尔类型,如果没有参数,返回 False。 +* int:函数用于将一个字符串或数字转换为整型。 + +```python +print(int()) +print(int('12')) +print(int(3.6)) +print(int('0100',base=2)) # 将2进制的 0100 转化成十进制。结果为 4 +``` + +* float:函数用于将整数和字符串转换成浮点数。 +* complex:函数用于创建一个值为 real + imag * j 的复数或者转化一个字符串或数为复数。如果第一个参数为字符串,则不需要指定第二个参数。。 + +```python +print(complex(1,2)) +print(complex(1)) +print(complex("1")) +print(complex("1+2j")) +``` + +进制转换(3个): + +* bin:将十进制转换成二进制并返回。 +* oct:将十进制转化成八进制字符串并返回。 +* hex:将十进制转化成十六进制字符串并返回。 + +```python +print(bin(10),type(bin(10))) +print(oct(10),type(oct(10))) +print(hex(10),type(hex(10))) +``` + +数学运算(7): + +* abs:函数返回数字的绝对值。 +* divmod:计算除数与被除数的结果,返回一个包含商和余数的元组(a // b, a % b)。 +* round:保留浮点数的小数位数,默认保留整数。 -pow:函数是计算x的y次方,如果z在存在,则再对结果进行取模,其结果等效于pow(x,y) %z) + +```python +print(abs(-5)) # 5 +print(divmod(7,2)) # (3, 1) +print(round(7/3,2)) # 2.33 +print(round(7/3)) # 2 +print(round(3.32567,3)) # 3.326 +print(pow(2,3)) # 8 +print(pow(2,3,3)) # 2 +``` + +* sum:对可迭代对象进行求和计算(可设置初始值)。 +* min:返回可迭代对象的最小值(可加key,key为函数名,通过函数的规则,返回最小值)。 +* max:返回可迭代对象的最大值(可加key,key为函数名,通过函数的规则,返回最大值)。 + +```python +print(sum([1,2,3])) +print(sum([1,2,3],100)) +print(min([1,2,3])) +ret = min([1,2,3,-10],key=abs) +print(ret) +dic = {'a':3,'b':2,'c':1} +print(min(dic,key=lambda x:dic[x])) +# x为dic的key,lambda的返回值(即dic的值进行比较)返回最小的值对应的键 +print(max([1,2,3])) +ret = max([1,2,3,-10],key=abs) +print(ret) +dic = {'a':3,'b':2,'c':1} +print(max(dic,key=lambda x:dic[x])) +``` + +#### 数据结构相关(24个) + +列表和元祖(2个) + +* list:将一个可迭代对象转化成列表(如果是字典,默认将key作为列表的元素)。 +* tuple:将一个可迭代对象转化成元祖(如果是字典,默认将key作为元祖的元素)。 + +```python +l = list((1,2,3)) +print(l) +l = list({1,2,3}) +print(l) +l = list({'k1':1,'k2':2}) +print(l) +tu = tuple((1,2,3)) +print(tu) +tu = tuple([1,2,3]) +print(tu) +tu = tuple({'k1':1,'k2':2}) +print(tu) +``` + +相关内置函数(2个) + +* reversed:将一个序列翻转,并返回此翻转序列的迭代器。 +* slice:构造一个切片对象,用于列表的切片。 + +```python +ite = reversed(['a',2,4,'f',12,6]) +for i in ite: + print(i) +l = ['a','b','c','d','e','f','g'] +sli = slice(3) +print(l[sli]) +sli = slice(0,7,2) +print(l[sli]) +``` + +字符串相关(9) + +* str:将数据转化成字符串。 +* format:与具体数据相关,用于计算各种小数,精算等。 + +```python +# 字符串可以提供的参数,指定对齐方式,<是左对齐, >是右对齐,^是居中对齐 +print(format('test','<20')) +print(format('test','>20')) +print(format('test','^20')) +# 整形数值可以提供的参数有 'b' 'c' 'd' 'o' 'x' 'X' 'n' None +print(format(192,'b')) # 转换为二进制 +print(format(97,'c')) # 转换unicode成字符 +print(format(11,'d')) # 转换成10进制 +print(format(11,'o')) # 转换为8进制 +print(format(11,'x')) # 转换为16进制,小写字母表示 +print(format(11,'X')) # 转换为16进制,大写字母表示 +print(format(11,'n')) # 和d一样 +print(format(11)) # 和d一样 +# 浮点数可以提供的参数有 'e' 'E' 'f' 'F' 'g' 'G' 'n' '%' None +print(format(314159265,'e')) # 科学计数法,默认保留6位小数 +print(format(314159265,'0.2e')) # 科学计数法,保留2位小数 +print(format(314159265,'0.2E')) # 科学计数法,保留2位小数,大写E +print(format(3.14159265,'f')) # 小数点计数法,默认保留6位小数 +print(format(3.14159265,'0.10f')) # 小数点计数法,保留10位小数 +print(format(3.14e+10000,'F')) # 小数点计数法,无穷大转换成大小字母 +# g的格式化比较特殊,假设p为格式中指定的保留小数位数,先尝试采用科学计数法格式化,得到幂指数exp,如果-4<=exp匿名函数格式的说明 + +**函数名 = lambda 参数 :返回值** + +1. 参数可以有多个,用逗号隔开 +2. 匿名函数不管逻辑多复杂,只能写一行,且逻辑执行结束后的内容就是返回值 +3. 返回值和正常的函数一样可以是任意数据类型 + +```python +l=[3,2,100,999,213,1111,31121,333] +print(max(l)) +dic={'k1':10,'k2':100,'k3':30} + +print(max(dic)) +print(dic[max(dic,key=lambda k:dic[k])]) +res = map(lambda x:x**2,[1,5,7,4,8]) +for i in res: + print(i) +res = filter(lambda x:x>10,[5,8,11,9,15]) +for i in res: + print(i) +``` diff --git a/01.基础语法/08.递归函数.md b/01.基础语法/08.递归函数.md new file mode 100644 index 0000000..6119912 --- /dev/null +++ b/01.基础语法/08.递归函数.md @@ -0,0 +1,139 @@ +# 递归函数 + +## 初识递归 + +* 递归的定义——在一个函数里再调用这个函数本身 +* 递归的最大深度——997 + +```python +def foo(n): + print(n) + n += 1 + foo(n) +foo(1) +``` + +997是python为了我们程序的内存优化所设定的一个默认值,我们当然还可以通过一些手段去修改它。 + +```python +import sys +print(sys.setrecursionlimit(10000)) +def foo(n): + print(n) + n += 1 + foo(n) +foo(1) +``` + +将python允许的递归深度设置为了1w,至于实际可以达到的深度就取决于计算机的性能了。 +不推荐修改这个默认的递归深度,因为如果用997层递归都没有解决的问题是不适合使用递归来解决。 + +## 汉诺塔问题 + +从左到右 A B C 柱 大盘子在下, 小盘子在上, 借助B柱将所有盘子从A柱移动到C柱, 期间只有一个原则: 大盘子只能在小盘子的下面. + +我们只需要考虑如果有64层,先将A柱上的63层移动到B柱上,然后将A柱的第64个移动到C柱上,然后将B柱上的63层移动到C柱上即可。 + +那怎么把63层都移到B柱上,这个问题可以用上面相同的方法解决。 + +```python +def move(n,a,b,c): + if n == 1: + print(a,'->',c) + else: + # 将n-1个盘子从a --> b + move(n-1,a,c,b) + # 将剩余的最后一个盘子从a --> c + print(a,'->',c) + # 将剩余的n-1个盘子从 b --> c + move(n-1,b,a,c) +n = int(input('请输入汉诺塔的层数:')) +move(n,'A','B','C') +``` + +递归实现三级菜单 + +```python +menu = { + '山东': { + '青岛': ['四方', '黄岛', '崂山', '李沧', '城阳'], + '济南': ['历城', '槐荫', '高新', '长青', '章丘'], + '烟台': ['龙口', '莱山', '牟平', '蓬莱', '招远'] + }, + '江苏': { + '苏州': ['沧浪', '相城', '平江', '吴中', '昆山'], + '南京': ['白下', '秦淮', '浦口', '栖霞', '江宁'], + '无锡': ['崇安', '南长', '北塘', '锡山', '江阴'] + }, + '浙江': { + '杭州': ['西湖', '江干', '下城', '上城', '滨江'], + '宁波': ['海曙', '江东', '江北', '镇海', '余姚'], + '温州': ['鹿城', '龙湾', '乐清', '瑞安', '永嘉'] + }, + '安徽': { + '合肥': ['蜀山', '庐阳', '包河', '经开', '新站'], + '芜湖': ['镜湖', '鸠江', '无为', '三山', '南陵'], + '蚌埠': ['蚌山', '龙子湖', '淮上', '怀远', '固镇'] + }, + '广东': { + '深圳': ['罗湖', '福田', '南山', '宝安', '布吉'], + '广州': ['天河', '珠海', '越秀', '白云', '黄埔'], + '东莞': ['莞城', '长安', '虎门', '万江', '大朗'] + }, + '测试': {} +} +def threeLM(dic): + while True: + for k in dic:print(k) + key = input('input>>').strip() + if key == 'b' or key == 'q':return key + elif key in dic.keys() and dic[key]: + ret = threeLM(dic[key]) + if ret == 'q': return 'q' +threeLM(menu) +# l = [menu] +# while l: +# for key in l[-1]:print(key) +# k = input('input>>').strip() # 北京 +# if k in l[-1].keys() and l[-1][k]:l.append(l[-1][k]) +# elif k == 'b':l.pop() +# elif k == 'q':break +``` + +## 二分查找算法 + +如果想在列表中查找某个数字,可以排序后从中间开始查找 + +![图片](data:image/png;base64,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etauW8fChQvJz8+nvLycI0eO0J7SsjLGjh3L5fD7/axdu5YF8+fz7LPPcvDgQaqqqwn1yMMPM3/BAgoKCli0cCHZ3/8+jY2NdEVpaSlpaWm059133+WNHTv4yY9/TFeVlpaSlpZGaw0NDeQ/+yzzf/pTnn32Wd57/30+++wzOqv++HES+/RhkGmS1K8fdXV1tOe9996jePt25s6dy+WoP36cxD59GGSaJPXrR11dHW2Jj4/n1//xH6x+/HE2PP88586do7Pqjx8nsU8fBpkmSf36UVdbS2v1x4+T2KcPg0yTpH79qKutReRaZiDSixQXFxMTE0OR18u2bdsoLy9n//79nDlzhtbeKS/nD5s3s/QXv+ByFBcXExMTQ5HXy7Zt2ygvL2f//v2cOXOGtjidTqZOncqY1FRKS0vpqtszMykpKaEjt2dmUlJSQlfdnplJSUkJoRqbmnhw7lySk5NxOp3k5OTgLSqisxqbmnhw7lySk5NxOp3k5OTgLSoiVGNTEw/OnUtycjJOp5OcnBy8RUV0VmNTEw/OnUtycjJOp5OcnBy8RUW0pbm5meYvv8Rut3M5TjU1MfcnP6F///44HA5+mJNDkddLqMTERF76r//i1ltv5Ze//CX9+/dnwIABXK7mlha+PH8eh8NBW95//31eeuklli9bhsVioSuaW1r48vx5HA4HrTU1NTH3Jz9hwIABOBwOZv/wh3i9Xjrj7NmzbN26laeffpo777yTp556infKy/niiy9o7S9/+Qu/+93vWL5sGRaLhc46e/YsW7du5emnn+bOO+/kqaee4p3ycr744gva4nA4mDRpEpkTJ7J371464+zZs2z50594+umnufPOO3nqqad49733OHbsGEFnz55ly5/+xNNPP82dd97JU089xbvvvcexY8cQuVYZiPQiI2+6icyJE3G5XLhcLpwOB06nE8MwCHXw4EFeeuklVj36KBEREbTnnfJydu3aRWNjI62NvOkmMidOxOVy4XK5cDocOJ1ODMOgI9ddfz1/PXSI1t4pL2fXrl00NjZyKSorK7FYLHSksrISi8VCa++Ul7Nr1y4aGxu5FJWVlVgsFkKlpKRgmiZBffr0oa6ujtbKDx5k165dNDY20paUlBRM0ySoT58+1NXVESolJQXTNAnq06cPdXV1tFZ+8CAdSUlJwTRNgvr06UNdXR1teeed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DcMw6MjRo0fp378/l2vTiy+yefNmtrz2GoZh0JGjR4/Sv39/2nPmzBmqq6sZNGgQTqeT1v7zP/+Tl195hS1bthBhGHTk6NGj9O/fn44cPXqU/v37I/J14S0qwjRNsrOz6QwrInJZDvz5z8yfPx+LxUJXuVwuvvGNb9CeAwcOsGDBAiwWCx2x2+0MHTqUjtjtdoYOHUp7Dhw4wIIFC7BYLHTEbrczdOhQLsblcuFyuWjLgQMHWLhgARaLhYtxuVy4XC464nK5cLlctOXAgQMsXLAA1jzBxbhcLlwuF12xYP58DMPgYlwuFy6Xi7ZERkYyePBgOlJ24AAL5s/HMAyutLKyMubPn49hGHQHl8uFy+WiLWVlZSyYPx/DMLiY/v370xVlZWUsmD8fwzC4mP79+9ORyMhIbrzxRtpTduAA83/6UyIMg4vp378/F9O/f39EegNL4Ct0QWFhIdXV1XiyshDpTU6ePInb7aYnnDx5ErfbTU84efIkbrebnnDy5Encbjc94eTJk7jdbvre5eGC2le9XAl97/JwQe2rXnrCyZMncbvd9ISTJ0/idrvpCSdPnsTtdtMTTp48idvtpiecPHkSt9uNSG/lLSrCNE2ys7PpDAMRuSxut5ue4na76Slut5ue4na76Slut5trkdvtpqe43W56itvtpqe43W56itvtRkQ6z0BEREREJIxZERHphfre5UFERL4eDEREREREwpgVEZFepPZVLyIi8vViICIiIiISxgxERERERMKYgYiIiIhIGDMQEREREQljBiIiIiIiYcxARERERCSMGYiIiIiIhDEr3cRbVISIiIiISHez0g1M00RERERE5EqwBL6CiIiIiEiYMhARERERCWMGIiIiIiJhzEBEREREJIwZiIiIiIiEMQMRERERkTBmICIiIiISxgxERERERMKYgYiIiIhIGDMQEREREQljBiIiIiIiYcxARERERCSMWRER6WXy8/Ppqnnz5iEiIj3DQEREREQkjBmIiIiIiIQxAxERERGRMGYgIiIiIhLGDEREREREwpgVERHpMYWFhfQm2dnZiIh0lRUREelR1dXV9AamaSIi0h2siIhIj/NkZXEt8xYVISLSXQxERERERMKYgYiIiIhIGDMQEREREQljBiIiIiIiYcxARERERCSMGYiIiIiIhDEDEREREZEwZiAiIiIiEsasiIhI2CktK2Pnzp18ef48Y9PSmDJ5Mhfs27ePN3bsoLUfzZ5NUlISl6O0rIydO3fy5fnzjE1LY8rkybRWWlbGzp07+fL8ecampTFl8mRERHqKFRERCSv5+fnYbDYWLVyIzWYjVFV1NbNmzmTgwIEEPfvss5w/f56g1994gwkZGTgcDi4mPz8fm83GooULsdlstCU/Px+bzcaihQux2WyIiPQ0AxERCRtv+nzY7XbmzJmDzWajtX/9l39h4MCBhPrss88wTZOgfn37snjJEt7YsYOOvOnzYbfbmTNnDjabjba86fNht9uZM2cONpsNEZGrwYqIyNdcZWUlf/rTn+hJ+fn5XAq73U52djZxcXFcir179rBkyRIuVV1dHX379iXUqFGjeHrNGv6weTOLHn6YH8+Zwze+8Q1a27tnD0uWLKEje/fsYcmSJYiIXE1WRES+5q6//nrS09PZt28f4Wby5MnExcVxqZpbWqioqGDDhg34/X5mzJjB9OnTac/u3bvJyMigNcMw+P6//it3TJ3Kc889h8Vi4cc//jExMTEENbe0UFFRwYYNG/D7/cyYMYPp06cTqrmlhYqKCjZs2IDf72fGjBlMnz4dEZGeZCAicg1ITU3lhhtuIJykpqYyZMgQOuP48eM8V1DAokWLyM/PZ39pKTU1NbTnz3/+M6NHj6Y9brebJUuWMGTIEO67/35Onz5N0PHjx3muoIBFixaRn5/P/tJSampqCHX8+HGeKyhg0aJF5Ofns7+0lJqaGkREepKBiMg1wGKxMGXKFNxuN+Fg0KBBpKen01mNjY08NG8eSUlJOJ1OZs2cidfrpS3nz5/HYhhYrVba4/f7eXTVKqqqqviv3/2OqKgoghobG3lo3jySkpJwOp3MmjkTr9dLqMbGRh6aN4+kpCScTiezZs7E6/UiItKTrIiIXCMcDgcej4dXXnmF5uZmrpbo6GimTp2KxWKhs4anpGCaJkGJiYnU1tbSlrKyMsakptKWlpYWXn75ZcoOHODBuXMZPHgwrQ1PScE0TYISExOpra0l1PCUFEzTJCgxMZHa2lpERHqSgYjINaRv375kZmZytRiGgcfjITIykssxfvx4tm/fTpDP52NiZiZteeuttxg/fjytvf/++8xfsIA+iYnk5eYyePBg2jJ+/Hi2b99OkM/nY2JmJqHGjx/P9u3bCfL5fEzMzEREpCdZERG5xgwfPpxjx47x/vvv09MmTJhAUlISlys9PZ3169ezbPlyrFYrfr+f3Nxc2nLu/HkSEhJo7bOqKp765S9xOp10JD09nfXr17Ns+XKsVit+v5/c3FxCpaens379epYtX47VasXv95Obm4uISE+yBL6CiMg1prm5mc2bN3Ps2DF6yvDhw/ne975HRwoLC6mursaTlUVHmpqaaGhowDRNrrSmpiYaGhowTZP2NDU10dDQgGmaXApvURGmaZKdnY2ISFcZiIhcgyIiIvB4PDidTnpC3759mThxIt0lOjoa0zTpCdHR0ZimSUeio6MxTRMRkavBQETkGhUdHc0dd9yBxWLhSnI4HHg8HqxWKyIi0v0MRESuYYMGDWLcuHFcSVOnTsXtdiMiIleGgYjINW706NEMHTqUKyEtLY3rr78eERG5cgxERHqB733ve8TFxdGdrr/+esaMGYOIiFxZBiIivYDdbmfatGlYrVa6g9vtZsqUKVgsFkRE5MoyEBHpJRISEpg0aRJdFRERgcfjwel0IiIiV56BiEgv8s1vfpNRo0bRFZmZmfTt2xcREekZBiIivcytt97KgAEDuBzf/va3GT58OCIi0nMMRER6GcMwuOOOO4iKiqIzkpKSyMjIQEREepYVEZFeyOVykZWVxR//+EcCgQAX43Q68Xg8RERE0B28RUWIiMilsSIi0ksNGDCA2267jbfeeouOWCwW7rjjDqKjo+kOpmkiIiKXzhL4CiIivVhxcTGHDh2iPbfccgujR49GRESuDgMRkV5u0qRJJCQk0JYhQ4YwevRoRETk6jEQEenlbDYbHo8Hm81GqLi4OCZPnoyIiFxdBiIiQnx8PJMnTybIarXi8Xiw2+2IiMjVZSAiIv8wdOhQRo8ezQWTJk2iT58+iIjI1WcJfAUREfmHlpYWPv74Y4YPH46IiIQHS+AriIiIiIiEKQMRERERkTBmICIiIiISxgxERERERMKYgYiIiIhIGDMQEREREQljBiIiIiIiYcxARERERCSMGYiIiIiIhDErXVRYWIiIiIiIyKXKzs6mM6x0g+rqakRERERELsY0TTrLSjfxZGUhIiIiItIeb1ERl8NARERERCSMGYiIiIiIhDEDEREREZEwZkVERC6q710eekLtq15EROT/ZiAiIiIiEsasiIjIJat91cuV0PcuDyIi0jYDEREREZEw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) + +```python +l = [2,3,5,10,15,16,18,22,26,30,32,35,41,42,43,55,56,66,67,69,72,76,82,83,88] +# def func(l,aim): +# mid = (len(l)-1)//2 +# if l: +# if aim > l[mid]: +# func(l[mid+1:],aim) +# elif aim < l[mid]: +# func(l[:mid],aim) +# elif aim == l[mid]: +# print("找到了",mid) +# else: +# print('找不到') +# func(l,66) +# func(l,6) +def search(num,l,start=None,end=None): + start = start if start else 0 + end = len(l)-1 if end is None else end + mid = (end - start)//2 + start + if start > end: + return None + elif l[mid] > num : + return search(num,l,start,mid-1) + elif l[mid] < num: + return search(num,l,mid+1,end) + elif l[mid] == num: + return mid +ret = search(18,l) +print(ret) +``` + diff --git a/01.基础语法/09.模块和包.md b/01.基础语法/09.模块和包.md new file mode 100644 index 0000000..9fb3662 --- /dev/null +++ b/01.基础语法/09.模块和包.md @@ -0,0 +1,367 @@ +# 模块和包 + +## 什么是模块 + +1. 使用python编写的代码(.py文件) +2. 已被编译为共享库或DLL的C或C++扩展 +3. 包好一组模块的包 +4. 使用C编写并链接到python解释器的内置模块 + +## 为何要使用模块 + +实现代码和功能的复用 + +### import 自定义模块my_module.py + +文件名my_module.py,模块名my_module + +```python +# my_module.py + +print('from the my_module.py') + +money = 100 + +def read1(): + print('my_module->read1->money',money) + +def read2(): + print('my_module->read2 calling read1') + read1() + +def change(): + global money + money=0 +``` + +模块可以包含可执行的语句和函数的定义,这些语句的目的是初始化模块,它们只在模块名第一次遇到导入import语句时才执行(import语句是可以在程序中的任意位置使用的,且针对同一个模块很import多次,为了防止你重复导入。 +python的优化手段是:第一次导入后就将模块名加载到内存了,后续的import语句仅是对已经加载大内存中的模块对象增加了一次引用,不会重新执行模块内的语句) + +```python +import my_module +import my_module +import my_module +import my_module + +import sys +print(sys.modules) +# sys.modules是一个字典,内部包含模块名与模块对象的映射,该字典决定了导入模块时是否需要重新导入。 +``` + +每个模块都是一个独立的名称空间,定义在这个模块中的函数,把这个模块的名称空间当做全局名称空间,这样我们在编写自己的模块时,就不用担心我们定义在自己模块中全局变量会在被导入时,与使用者的全局变量冲突 + +```python +import my_module +money=10 +print(my_module.money) +``` + +```python +import my_module +def read1(): + print('=========') + +my_module.read1() +``` + +```python +import my_module + +money = 1 +my_module.change() +print(money) +print(my_module.money) +``` + +总结:首次导入模块my_module时会做三件事: + +1. 为源文件(my_module模块)创建新的名称空间,在my_module中定义的函数和方法若是使用到了global时访问的就是这个名称空间。 + +2. 在新创 建的命名空间中执行模块中包含的代码 + +3. 创建名字my_module来引用该命名空间 + +#### 为模块名起别名,相当于m1=1;m2=m1 + +```python +import my_module as mm + +print(mm.money) +``` + +> 示范用法: + +有两中sql模块mysql和oracle,根据用户的输入,选择不同的sql功能 + +```python +# mysql.py +def sqlparse(): + print('from mysql sqlparse') + +# oracle +def sqlparse(): + print('from oracle sqlparse') + +# test.py +db_type=input('>>: ') +if db_type == 'mysql': + import mysql as db +elif db_type == 'oracle': + import oracle as db + +db.sqlparse() +``` + +#### 在一行导入多个模块 + +```python +import sys, os, re +``` + +### from ... import ... + +对比import my_module,会将源文件的名称空间'my_module'带到当前名称空间中,使用时必须是my_module.名字的方式 + +而from 语句相当于import,也会创建新的名称空间,但是将my_module中的名字直接导入到当前的名称空间中,在当前名称空间中,直接使用名字就可以了 + +```python +from my_module import read1,read2 +money = 1000 +read1() +# 导入的函数read1,执行时仍然回到my_module.py中寻找全局变量money +``` + +```python +from my_module import read1,read2 +money = 1000 +def read1(): + print('*'*10) + +read2() +# 导入的函数read2,执行时需要调用read1(),仍然回到my_module.py中找read1() +``` + +```python +from my_module import read1,read2 +money = 1000 +def read1(): + print('*'*10) + +read1() +# 导入的函数read1,被当前位置定义的read1覆盖掉了 +``` + +```python +from my_module import read1 as read + +read() +# 也支持as +``` + +from my_module import * 把my_module中所有的不是以下划线(_)开头的名字都导入到当前位置 +大部分情况下我们的python程序不应该使用这种导入方式,因为*你不知道你导入什么名字,很有可能会覆盖掉你之前已经定义的名字。而且可读性极其的差,在交互式环境中导入时没有问题。 + +在my_module.py中新增一行 + +```python +..... +__all__ = ['money','read1'] +# 这样在另外一个文件中用from my_module import *就这能导入列表中规定的两个名字 + +# test.py +from my_module import * + +print(money) +read1() +read2() +``` + +注意:如果my_module.py中的名字前加_,即_money,则from my_module import *,则_money不能被导入 + +- 编写好的一个python文件可以有两种用途: + +1. 脚本,一个文件就是整个程序,用来被执行 +2. 模块,文件中存放着一堆功能,用来被导入使用 + + +- python为我们内置了全局变量`__name__`, + +1. 当文件被当做脚本执行时:`__name__ 等于'__main__'` +2. 当文件被当做模块导入时:`__name__等于模块名` + +- 作用:用来控制.py文件在不同的应用场景下执行不同的逻辑(或者是在模块文件中测试代码) + +1. `if __name__ == '__main__':` + +```python +def fib(n): + a, b = 0, 1 + while b < n: + print(b, end=',') + a, b = b, a+b + print() + +if __name__ == "__main__": + print(__name__) + num = input('num :') + fib(int(num)) +``` + +## 模块的搜索路径 + +模块的查找顺序是:内存中已经加载的模块->自建模块->sys.path路径中包含的模块 + +1. 在第一次导入某个模块时(比如my_module),会先检查该模块是否已经被加载到内存中(当前执行文件的名称空间对应的内存),如果有则直接引用 + ps:python解释器在启动时会自动加载一些模块到内存中,可以使用sys.modules查看 +2. 如果没有,解释器则会查找同名的内建模块 +3. 如果还没有找到就从sys.path给出的目录列表中依次寻找my_module.py文件。 + +注意:自定义的模块名不应该与系统内置模块重名 + +## 编译python文件 + +为了提高加载模块的速度,python解释器会在`__pycache__`目录中下缓存每个模块编译后的版本,格式为:module.version.pyc。通常会包含python的版本号。例如,在CPython3.3版本下,my_module.py模块会被缓存成`__pycache__/my_module.cpython-33.pyc`。这种命名规范保证了编译后的结果多版本共存。 + + +## 包 + +包就是一个包含有`__init__.py`文件的文件夹,所以其实我们创建包的目的就是为了用文件夹将文件/模块组织起来 + +需要强调的是: + +1. 在python3中,即使包下没有`__init__.py`文件,import 包仍然不会报错,而在python2中,包下一定要有该文件,否则import 包报错 + +2. 创建包的目的不是为了运行,而是被导入使用,记住,包只是模块的一种形式而已,包的本质就是一种模块 + +### 为何要使用包 + +**包的本质就是一个文件夹,那么文件夹唯一的功能就是将文件组织起**来 +随着功能越写越多,我们无法将所以功能都放到一个文件中,于是我们使用模块去组织功能,而随着模块越来越多,我们就需要用文件夹将模块文件组织起来,以此来提高程序的结构性和可维护性 + +### 注意事项 + +1. 关于包相关的导入语句也分为`import`和`from ... import ...`两种,但是无论哪种,无论在什么位置,在导入时都必须遵循一个原则:凡是在导入时带点的,点的左边都必须是一个包,否则非法。可以带有一连串的点,如`item.subitem.subsubitem`,但都必须遵循这个原则。但对于导入后,在使用时就没有这种限制了,点的左边可以是包,模块,函数,类(它们都可以用点的方式调用自己的属性)。 + +2. import导入文件时,产生名称空间中的名字来源于文件,import 包,产生的名称空间的名字同样来源于文件,即包下的`__init__.py`,导入包本质就是在导入该文件 + +3. 包A和包B下有同名模块也不会冲突,如A.a与B.a来自俩个命名空间 + +### 包的使用 + +示例文件 + +```python +glance/ #Top-level package +├── __init__.py #Initialize the glance package +├── api #Subpackage for api +│ ├── __init__.py +│ ├── policy.py +│ └── versions.py +├── cmd #Subpackage for cmd +│ ├── __init__.py +│ └── manage.py +└── db #Subpackage for db + ├── __init__.py + └── models.py +``` + +文件内容 + +```python +#文件内容 + +#policy.py +def get(): + print('from policy.py') + +##versions.py +def create_resource(conf): + print('from version.py: ',conf) + +#manage.py +def main(): + print('from manage.py') + +#models.py +def register_models(engine): + print('from models.py: ',engine) + +``` + +#### 使用import导入包 + +```python +import glance.db.models +# 在导入glance的时候会执行glance下的__init__.py中的代码 + +glance.db.models.register_models('mysql') +``` + +单独导入包名称时不会导入包中所有包含的所有子模块 + +```python +import glance +glance.cmd.manage.main() +``` + +解决方法 + +```python +# glance/__init__.py +from . import cmd + +# glance/cmd/__init__.py +from . import manage +``` + +#### 使用from (具体的路径) import (具体的模块) + +需要注意的是from后import导入的模块,必须是明确的一个不能带点,否则会有语法错误,如:`from a import b.c`是错误语法 + +```python +from glance.db import models +from glance.db.models import register_models + +models.register_models('mysql') +register_models('mysql') +``` + +`from glance.api import *` +想从包api中导入所有,实际上该语句只会导入包api下`__init__.py`文件中定义的名字,我们可以在这个文件中定义`__all__` + +```python +x = 10 + +def func(): + print('from api.__init.py') + +__all__=['x','func','policy'] +``` + +```python +from glance.api import * + +func() +print(x) +policy.get() +``` + +## 绝对导入和相对导入 + +- 绝对导入:以glance作为起始 +- 相对导入:用.或者..的方式最为起始(只能在一个包中使用,不能用于不同目录内) + +绝对导入: 以执行文件的sys.path为起始点开始导入,称之为绝对导入 + +1. 优点: 执行文件与被导入的模块中都可以使用 +2. 缺点: 所有导入都是以sys.path为起始点,导入麻烦 + +相对导入: 参照当前所在文件的文件夹为起始开始查找,称之为相对导入 + +1. 符号: .代表当前所在文件的文件加,..代表上一级文件夹,...代表上一级的上一级文件夹 +2. 优点: 导入更加简单 +3. 缺点: 只能在导入包中的模块时才能使用 + 注意: + +- 相对导入只能用于包内部模块之间的相互导入,导入者与被导入者都必须存在于一个包内 +- 试图在顶级包之外使用相对导入是错误的,言外之意,必须在顶级包内使用相对导入,每增加一个.代表跳到上一级文件夹,而上一级不应该超出顶级包 diff --git a/01.基础语法/10.常用模块.md b/01.基础语法/10.常用模块.md new file mode 100644 index 0000000..879b370 --- /dev/null +++ b/01.基础语法/10.常用模块.md @@ -0,0 +1,1377 @@ +# 常用模块 + +## 序列化模块 + +将原本的字典、列表等内容转换成一个字符串的过程就叫做**序列化** + +**序列化的目的** + +1. 以某种存储形式使自定义对象持久化; +2. 将对象从一个地方传递到另一个地方。 +3. 使程序更具维护性。 + + ![img](10.常用模块/3856406007.png) + +python可序列化的数据类型,序列化出来之后的结果如下 + +| Python | JSON | +| ---------- | ------ | +| dict | object | +| list,tuple | array | +| str | string | +| int,float | number | +| True | true | +| False | false | +| None | null | + +### json模块 + +Json模块提供了四个功能:dumps、dump、loads、load + +```python +import json + +dic = {'k1':'v1','k2':'v2','k3':'v3'} +str_dic = json.dumps(dic) +# 序列化:将一个字典转换成一个字符串 + +print(type(str_dic),str_dic) +dic2 = json.loads(str_dic) +print(type(dic2),dic2) +# 反序列化:将一个字符串格式的字典转换成一个字典 + +list_dic = [1,['a','b','c'],3,{'k1':'v1','k2':'v2'}] +str_dic = json.dumps(list_dic) +print(type(str_dic),str_dic) + +list_dic2 = json.loads(str_dic) +print(type(list_dic2),list_dic2) +``` + +| Skipkeys | 1,默认值是False,如果dict的keys内的数据不是python的基本类型,2,设置为False时,就会报TypeError的错误。此时设置成True,则会跳过这类key,3,当它为True的时候,所有非ASCII码字符显示为\uXXXX序列,只需在dump时将ensure_ascii设置为False即可,此时存入json的中文即可正常显示。 | +| :----------- | :----------------------------------------------------------- | +| indent | 是一个非负的整型,如果是0就是顶格分行显示,如果为空就是一行最紧凑显示,否则会换行且按照indent的数值显示前面的空白分行显示,这样打印出来的json数据也叫pretty-printed json | +| ensure_ascii | 当它为True的时候,所有非ASCII码字符显示为\uXXXX序列,只需在dump时将ensure_ascii设置为False即可,此时存入json的中文即可正常显示。 | +| separators | 分隔符,实际上是(item_separator, dict_separator)的一个元组,默认的就是(‘,’,’:’);这表示dictionary内keys之间用“,”隔开,而KEY和value之间用“:”隔开。 | +| sort_keys | 将数据根据keys的值进行排序 | + +```python +import json + +data = {'name':'陈松','sex':'female','age':88} +json_dic2 = json.dumps(data,sort_keys=True,indent=2,separators=(',',':'),ensure_ascii=False) +print(json_dic2) +``` + +json.dump和json.load不常用,主要是针对文件操作进行序列化和反序列化 + +```python +序列化: +import json +v = {'k1':'yh','k2':'小马过河'} +f = open('xiaoma.txt',mode='w+',encoding='utf-8') #文件不存在就会生成 +val = json.dump(v,f) +print(val) +f.close() +----------------结果: +None +#dump将内容序列化,并写入打开的文件中。 + +反序列化: +import json +f = open('xiaoma.txt',mode='r',encoding='utf-8') +data = json.load(f) +f.close() +print(data,type(data)) +---------------结果: +{'k1': 'yh', 'k2': '小马过河'} +``` + + + +### pickle模块 + +| json | 用于字符串 和 python数据类型间进行转换 | +| ------ | :------------------------------------------------- | +| pickle | 用于python特有的类型 和 python的数据类型间进行转换 | + +pickle模块提供了四个功能:dumps、dump(序列化,存)、loads(反序列化,读)、load +**不仅可以序列化字典,列表...可以把python中任意的数据类型序列化** + + json模块和picle模块都有 dumps、dump、loads、load四种方法,而且用法一样。 + +不同的是json模块序列化出来的是通用格式,其它编程语言都认识,就是普通的字符串, + +而picle模块序列化出来的只有python可以认识,其他编程语言不认识的,表现为乱码 + +不过picle可以序列化函数,但是其他文件想用该函数,在该文件中需要有该文件的定义(定义和参数必须相同,内容可以不同) + +```python +import pickle +dic = {'k1':'v1','k2':'v2','k3':'v3'} +str_dic = pickle.dumps(dic) +print(str_dic) + +dic2 = pickle.loads(str_dic) +print(dic2) + +import time +struct_time = time.localtime(1000000000) +print(struct_time) +f = open('pickle_file','wb') +pickle.dump(struct_time,f) +f.close() + +f = open('pickle_file','rb') +struct_time2 = pickle.load(f) +print(struct_time2.tm_year) +``` + +### shelve模块 + +shelve也是python提供给我们的序列化工具,比pickle用起来更简单一些。 +shelve只提供给我们一个open方法,是用key来访问的,使用起来和字典类似。 + +参考博客 + +https://www.cnblogs.com/sui776265233/p/9225164.html + +```python +import shelve +f = shelve.open('shelve_file') +f['key'] = {'int':10,'str':'hello','float':0.123} +f.close() + +f1 = shelve.open('shelve_file') +ret = f1['key'] +f1.close() +print(ret) +``` + +这个模块有个限制,它不支持多个应用同一时间往同一个DB进行写操作。所以当我们知道我们的应用如果只进行读操作,我们可以让shelve通过只读方式打开DB + +```python +import shelve +f1 = shelve.open('shelve_file',flag='r') +ret = f1['key'] +f1.close() +print(ret) +``` + +由于shelve在默认情况下是不会记录待持久化对象的任何修改的,所以我们在shelve.open()时候需要修改默认参数,否则对象的修改不会保存。 + +```python +import shelve +f1 = shelve.open('shelve_file') +print(f1['key']) +f1['key']['k1'] = 'v1' +f1.close() + +f2 = shelve.open('shelve_file',writeback=True) +print(f2['key']) +f2['key']['k1'] = 'hello' +f2.close() +``` + +**使用shelve模块实现简单的数据库** + +```python +# 简单的数据库 + +import sys,shelve + +def print_help(): + '存储(增加)、查找、更新(修改)、循环打印、删除、退出、帮助' + print('The available commons are: ') + print('store : Stores information about a person') + print('lookup : Looks up a person from ID numbers') + print("update : Update a person's information from ID number") + print('print_all: Print all informations') + print("delete : Delete a person's information from ID number") + print('quit : Save changes and exit') + print('? : Print this message') + + +def store_people(db): + pid = input('Please enter a unique ID number: ') + person = {} + person['name'] = input('Please enter the name: ') + person['age'] = input('Please enter the age: ') + person['phone'] = input('Please enter the phone: ') + db[pid] = person + print("Store information: pid is %s, information is %s" % (pid, person)) + + +def lookup_people(db): + pid = input('Please enter the number: ') + field = input('What would you like to know? (name, age, phone) ') + if pid in db.keys(): + value = db[pid][field] + print("Pid %s's %s is %s" % (pid, field, value)) + else: + print('Not found this number') + + +def update_people(db): + pid = input('Please enter the number: ') + field = input('What would you like to update? (name, age, phone) ') + newvalue = input('Enter the new information: ') + if pid in db.keys(): + value = db[pid] + value[field] = newvalue + print("Pid %s's %s update information is %s" % (pid, field, newvalue)) + else: + print("Not found this number, can't update") + + +def delete_people(db): + pid = input('Please enter the number: ') + if pid in db.keys(): + del db[pid] + print("pid %s's information delete done" % pid) + else: + print( "Not found this number, can't delete") + +def print_all_people(db): + print( 'All information are: ') + for key, value in db.items(): + print(key, value) + +def enter_cmd(): + cmd = input('Please enter the cmd(? for help): ') + cmd = cmd.strip().lower() + return cmd + +def main(): + database = shelve.open('database201803.dat', writeback=True) + try: + while True: + cmd = enter_cmd() + if cmd == 'store': + store_people(database) + elif cmd == 'lookup': + lookup_people(database) + elif cmd == 'update': + update_people(database) + elif cmd == 'print_all': + print_all_people(database) + elif cmd == 'delete': + delete_people(database) + elif cmd == '?': + print_help() + elif cmd == 'quit': + return + finally: + database.close() + +if __name__ == '__main__': + main() +``` + + + +## hashlib模块 + +Python的hashlib提供了常见的摘要算法,如MD5,SHA1等等。 + +什么是摘要算法呢?摘要算法又称哈希算法、散列算法。它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示)。 + +摘要算法就是通过摘要函数f()对任意长度的数据data计算出固定长度的摘要digest,目的是为了发现原始数据是否被人篡改过。 + +摘要算法之所以能指出数据是否被篡改过,就是因为摘要函数是一个单向函数,计算f(data)很容易,但通过digest反推data却非常困难。而且,对原始数据做一个bit的修改,都会导致计算出的摘要完全不同。 + +```python +import hashlib + +md5 = hashlib.md5() +md5.update('how to use md5 in python hashlib?'.encode('utf-8')) +print(md5.hexdigest()) +``` + +如果数据量很大,可以分块多次调用update(),最后计算的结果是一样的 + +```python +import hashlib + +md5 = hashlib.md5() +md5.update('how to use md5 '.encode('utf-8')) +md5.update('in python hashlib?'.encode('utf-8')) +print(md5.hexdigest()) +``` + +MD5是最常见的摘要算法,速度很快,生成结果是固定的128 bit字节,通常用一个32位的16进制字符串表示。另一种常见的摘要算法是SHA1,调用SHA1和调用MD5完全类似 + +```python +import hashlib + +sha1 = hashlib.sha1() +sha1.update('how to use md5 '.encode('utf-8')) +sha1.update('in python hashlib?'.encode('utf-8')) +print(sha1.hexdigest()) +``` + +### 摘要算法应用 + +任何允许用户登录的网站都会存储用户登录的用户名和口令。如何存储用户名和口令呢?方法是存到数据库表中 + +```sql +name | password +--------+---------- +michael | 123456 +bob | abc999 +alice | alice2008 +``` + +如果使用md5来将保护密码那么就是这样 + +```sql +username | password +---------+--------------------------------- +michael | e10adc3949ba59abbe56e057f20f883e +bob | 878ef96e86145580c38c87f0410ad153 +alice | 99b1c2188db85afee403b1536010c2c9 +``` + +有很多md5撞库工具,可以轻松的将简单密码给碰撞出来 + +所以,要确保存储的用户口令不是那些已经被计算出来的常用口令的MD5,这一方法通过对原始口令加一个复杂字符串来实现,俗称“加盐” + +经过Salt处理的MD5口令,只要Salt不被黑客知道,即使用户输入简单口令,也很难通过MD5反推明文口令。 + +但是如果有两个用户都使用了相同的简单口令比如123456,在数据库中,将存储两条相同的MD5值,这说明这两个用户的口令是一样的。 + +如果假定用户无法修改登录名,就可以通过把登录名作为Salt的一部分来计算MD5,从而实现相同口令的用户也存储不同的MD5。 + +显示进度条 + +```python +import time + +for i in range(0,101,2): + time.sleep(0.1) + char_num = i//2 + per_str = '\r%s%% : %s\n' % (i, '*' * char_num) \ + if i == 100 else '\r%s%% : %s' % (i,'*'*char_num) + print(per_str,end='', flush=True) +``` + +## configparser模块 + +该模块适用于配置文件的格式与windows ini文件类似,可以包含一个或多个节(section),每个节可以有多个参数(键=值)。 + +常见的文档格式 + +``` +[DEFAULT] +ServerAliveInterval = 45 +Compression = yes +CompressionLevel = 9 +ForwardX11 = yes + +[bitbucket.org] +User = hg + +[topsecret.server.com] +Port = 50022 +ForwardX11 = no +``` + +使用python生成一个这样的文件 + +```python +import configparser + +conf = configparser.ConfigParser() + +conf['DEFAULT'] = {'ServerAliveInterval':'45', + 'Compression':'yes', + 'CompressionLevel':'9', + 'ForwardX11':'yes' + } +conf['bitbucket.org'] = {'User':'hg'} +conf['topsecret.server.com'] = {'Port':'50022', + 'ForwardX11':'no' + } + +with open('config','w') as config: + conf.write(config) + +``` + +查找 + +```python +import configparser + +conf = configparser.ConfigParser() + +conf['DEFAULT'] = {'ServerAliveInterval':'45', + 'Compression':'yes', + 'CompressionLevel':'9', + 'ForwardX11':'yes' + } +conf['bitbucket.org'] = {'User':'hg'} +conf['topsecret.server.com'] = {'Port':'50022', + 'ForwardX11':'no' + } + +print('bitbucket.org' in conf) +print('bitbucket.com' in conf) + +print(conf['bitbucket.org']['user']) +print(conf['DEFAULT']['Compression']) + +for key in conf['bitbucket.org']: + print(key) # DEFAULT的键也会出现 + +print(conf.options('bitbucket.org')) +# 同for循环,找到'bitbucket.org'下所有键 + +print(conf.items('bitbucket.org')) +# 找到'bitbucket.org'下所有键值对 + +print(conf.get('bitbucket.org','compression')) +``` + +增删改操作 + +```python +import configparser + +conf = configparser.ConfigParser() + +conf.read('config') + +conf.add_section('yuan') # 添加键 + +conf.remove_section('bitbucket.org') # 删除键 +conf.remove_option('topsecret.server.com','forwardx11') # 移除条目 + +conf.set('topsecret.server.com','k1','11111') # 在对应键下加上条目 +conf.set('yuan','k2','22222') + +conf.write(open('config.new','w')) # 写入文件 +``` + +## logging模块 + +参考博客: + +https://blog.csdn.net/pansaky/article/details/90710751 + +### 函数式简单配置 + +```python +import logging +logging.debug('debug message') +logging.info('info message') +logging.warning('warning message') +logging.error('error message') +logging.critical('critical message') +``` + +默认情况下Python的logging模块将日志打印到了标准输出中,且只显示了大于等于WARNING级别的日志,这说明默认的日志级别设置为WARNING(日志级别等级CRITICAL > ERROR > WARNING > INFO > DEBUG),默认的日志格式为日志级别:Logger名称:用户输出消息。 + +```python +import logging + +logging.basicConfig(level=logging.DEBUG, + format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s', + datefmt='%a, %d %b %Y %H:%M:%S', + filename='test.log', + filemode='w') + +logging.debug('debug message') +logging.info('info message') +logging.warning('warning message') +logging.error('error message') +logging.critical('critical message') +``` + +参数解释 + +- logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为,可用参数有: +- filename:用指定的文件名创建FiledHandler,这样日志会被存储在指定的文件中。 +- filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。 +- format:指定handler使用的日志显示格式。 +- datefmt:指定日期时间格式。 +- level:设置rootlogger(后边会讲解具体概念)的日志级别 +- stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件(f=open- (‘test.log’,’w’)),默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。 +- format参数中可能用到的格式化串: + - %(name)s Logger的名字 + - %(levelno)s 数字形式的日志级别 + - %(levelname)s 文本形式的日志级别 + - %(pathname)s 调用日志输出函数的模块的完整路径名,可能没有 + - %(filename)s 调用日志输出函数的模块的文件名 + - %(module)s 调用日志输出函数的模块名 + - %(funcName)s 调用日志输出函数的函数名 + - %(lineno)d 调用日志输出函数的语句所在的代码行 + - %(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示 + - %(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数 + - %(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒 + - %(thread)d 线程ID。可能没有 + - %(threadName)s 线程名。可能没有 + - %(process)d 进程ID。可能没有 + - %(message)s用户输出的消息 + +### logger对象配置 + +```python +import logging + +logger = logging.getLogger() + +# 创建一个handler,用于写入日志文件 +fh = logging.FileHandler('test.log',encoding='utf-8') +# 再创建一个handler,用于输出到控制台 +ch = logging.StreamHandler() + +formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + +fh.setLevel(logging.DEBUG) +fh.setFormatter(formatter) + +ch.setFormatter(formatter) + + +logger.addHandler(fh) #logger对象可以添加多个fh和ch对象 +logger.addHandler(ch) +logger.debug('logger debug message') +logger.info('logger info message') +logger.warning('logger warning message') +logger.error('logger error message') +logger.critical('logger critical message') +``` + +logging库提供了多个组件:Logger、Handler、Filter、Formatter。Logger对象提供应用程序可直接使用的接口,Handler发送日志到适当的目的地,Filter提供了过滤日志信息的方法,Formatter指定日志显示格式。另外,可以通过:logger.setLevel(logging.Debug)设置级别,当然,也可以通过fh.setLevel(logging.Debug)单对文件流设置某个级别。 + + +### logger的配置文件 + +```python +""" +logging配置 +""" + +import os +import logging.config + +# 定义三种日志输出格式 开始 + +standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \ + '[%(levelname)s][%(message)s]' #其中name为getlogger指定的名字 + +simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s' + +id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s' + +# 定义日志输出格式 结束 + +logfile_dir = os.path.dirname(os.path.abspath(__file__)) # log文件的目录 + +logfile_name = 'all2.log' # log文件名 + +# 如果不存在定义的日志目录就创建一个 +if not os.path.isdir(logfile_dir): + os.mkdir(logfile_dir) + +# log文件的全路径 +logfile_path = os.path.join(logfile_dir, logfile_name) + +# log配置字典 +LOGGING_DIC = { + 'version': 1, + 'disable_existing_loggers': False, + 'formatters': { + 'standard': { + 'format': standard_format + }, + 'simple': { + 'format': simple_format + }, + }, + 'filters': {}, + 'handlers': { + #打印到终端的日志 + 'console': { + 'level': 'DEBUG', + 'class': 'logging.StreamHandler', # 打印到屏幕 + 'formatter': 'simple' + }, + #打印到文件的日志,收集info及以上的日志 + 'default': { + 'level': 'DEBUG', + 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件 + 'formatter': 'standard', + 'filename': logfile_path, # 日志文件 + 'maxBytes': 1024*1024*5, # 日志大小 5M + 'backupCount': 5, + 'encoding': 'utf-8', # 日志文件的编码,再也不用担心中文log乱码了 + }, + }, + 'loggers': { + #logging.getLogger(__name__)拿到的logger配置 + '': { + 'handlers': ['default', 'console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕 + 'level': 'DEBUG', + 'propagate': True, # 向上(更高level的logger)传递 + }, + }, +} + + +def load_my_logging_cfg(): + logging.config.dictConfig(LOGGING_DIC) # 导入上面定义的logging配置 + logger = logging.getLogger(__name__) # 生成一个log实例 + logger.info('It works!') # 记录该文件的运行状态 + +if __name__ == '__main__': + load_my_logging_cfg() +``` + +``` +注意: + + +#1、有了上述方式我们的好处是:所有与logging模块有关的配置都写到字典中就可以了,更加清晰,方便管理 + + +#2、我们需要解决的问题是: + 1、从字典加载配置:logging.config.dictConfig(settings.LOGGING_DIC) + + 2、拿到logger对象来产生日志 + logger对象都是配置到字典的loggers 键对应的子字典中的 + 按照我们对logging模块的理解,要想获取某个东西都是通过名字,也就是key来获取的 + 于是我们要获取不同的logger对象就是 + logger=logging.getLogger('loggers子字典的key名') + + + 但问题是:如果我们想要不同logger名的logger对象都共用一段配置,那么肯定不能在loggers子字典中定义n个key + 'loggers': { + 'l1': { + 'handlers': ['default', 'console'], # + 'level': 'DEBUG', + 'propagate': True, # 向上(更高level的logger)传递 + }, + 'l2: { + 'handlers': ['default', 'console' ], + 'level': 'DEBUG', + 'propagate': False, # 向上(更高level的logger)传递 + }, + 'l3': { + 'handlers': ['default', 'console'], # + 'level': 'DEBUG', + 'propagate': True, # 向上(更高level的logger)传递 + }, + +} + + +#我们的解决方式是,定义一个空的key + 'loggers': { + '': { + 'handlers': ['default', 'console'], + 'level': 'DEBUG', + 'propagate': True, + }, + +} + +这样我们再取logger对象时 +logging.getLogger(__name__),不同的文件__name__不同,这保证了打印日志时标识信息不同,但是拿着该名字去loggers里找key名时却发现找不到,于是默认使用key=''的配置 +``` + +## collections模块 + +在内置数据类型(dict、list、set、tuple)的基础上,collections模块还提供了几个额外的数据类型:Counter、deque、defaultdict、namedtuple和OrderedDict等。 + +1. namedtuple: 生成可以使用名字来访问元素内容的tuple + +2. deque: 双端队列,可以快速的从另外一侧追加和推出对象 + +3. Counter: 计数器,主要用来计数 + +4. OrderedDict: 有序字典 + +5. defaultdict: 带有默认值的字典 + +### namedtuple + +```python +from collections import namedtuple +point = namedtuple('point',['x','y']) +p = point(1,2) +print(p.x) +``` + +一个点的二维坐标就可以表示成,但是,看到(1, 2),很难看出这个tuple是用来表示一个坐标的。 + +这时,namedtuple就派上了用场 + +### deque + +使用list存储数据时,按索引访问元素很快,但是插入和删除元素就很慢了,因为list是线性存储,数据量大的时候,插入和删除效率很低。 + +deque是为了高效实现插入和删除操作的双向列表,适合用于队列和栈 + +```python +from collections import deque + +q = deque(['a','b','c']) +q.append('x') +q.appendleft('y') + +print(q) +``` + +deque除了实现list的append()和pop()外,还支持appendleft()和popleft(),这样就可以非常高效地往头部添加或删除元素。 + +### OrderedDict + +```python +from collections import OrderedDict + +d = dict([('a',1),('b',2),('c',3)]) +print(d) + +od = OrderedDict([('a',1),('b',2),('c',3)]) +print(od) +``` + +注意,OrderedDict的Key会按照插入的顺序排列,不是Key本身排序 + +### defaultdict + +有如下值集合 [11,22,33,44,55,66,77,88,99,90...],将所有大于 66 的值保存至字典的第一个key中,将小于 66 的值保存至第二个key的值中。 + +即: {'k1': 大于66 , 'k2': 小于66} + +```python +li = [11,22,33,44,55,77,88,99,90] + +result = {} +for row in li: + if row < 66: + if 'key1' not in result: + result['key1']=[] + result['key1'].append(row) + else: + if 'key2' not in result: + result['key2']=[] + result['key2'].append(row) +print(result) +``` + +```python +from collections import defaultdict + +li = [11,22,33,44,55,77,88,99,90] +result=defaultdict(list) + +for row in li: + if row > 66: + result['key1'].append(row) + else: + result['key2'].append(row) + +print(result) +``` + +### counter + +Counter类的目的是用来跟踪值出现的次数。它是一个无序的容器类型,以字典的键值对形式存储,其中元素作为key,其计数作为value。 + +```python +from collections import Counter + +c = Counter('qazxswqazxswqazxswsxaqwsxaqws') +print(c) +``` + +## 时间有关的模块 + +常用方法 + +- time.sleep(secs) + - (线程)推迟指定的时间运行。单位为秒。 +- time.time() + - 获取当前时间戳 + +表示时间的三种方式 + +在Python中,通常有这三种方式来表示时间:时间戳、元组(struct_time)、格式化的时间字符串: + +1. **时间戳**(timestamp) :通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量。我们运行“type(time.time())”,返回的是float类型。 + +2. 格式化的时间字符串(Format String): ‘1999-12-06’ + +| %y | 两位数的年份表示(00-99) | +| ---- | :---------------------------------------- | +| %Y | 四位数的年份表示(000-9999) | +| %m | 月份(01-12) | +| %d | 月内中的一天(0-31) | +| %H | 24小时制小时数(0-23) | +| %I | 12小时制小时数(01-12) | +| %M | 分钟数(00=59) | +| %S | 秒(00-59) | +| %a | 本地简化星期名称 | +| %A | 本地完整星期名称 | +| %b | 本地简化的月份名称 | +| %B | 本地完整的月份名称 | +| %c | 本地相应的日期表示和时间表示 | +| %j | 年内的一天(001-366) | +| %p | 本地A.M.或P.M.的等价符 | +| %U | 一年中的星期数(00-53)星期天为星期的开始 | +| %w | 星期(0-6),星期天为星期的开始 | +| %W | 一年中的星期数(00-53)星期一为星期的开始 | +| %x | 本地相应的日期表示 | +| %X | 本地相应的时间表示 | +| %Z | 当前时区的名称 | +| %% | %号本身 | + +3. 元组(struct_time) :struct_time元组共有9个元素共九个元素:(年,月,日,时,分,秒,一年中第几周,一年中第几天等) + +| 索引(Index) | 属性(Attribute) | 值(Values) | +| :------------ | :------------------------ | :----------------- | +| 0 | tm_year(年) | 比如2011 | +| 1 | tm_mon(月) | 1月12日 | +| 2 | tm_mday(日) | 1月31日 | +| 3 | tm_hour(时) | 0 - 23 | +| 4 | tm_min(分) | 0 - 59 | +| 5 | tm_sec(秒) | 0 - 60 | +| 6 | tm_wday(weekday) | 0 - 6(0表示周一) | +| 7 | tm_yday(一年中的第几天) | 1 - 366 | +| 8 | tm_isdst(是否是夏令时) | 默认为0 | + +```python +import time + +# 第一种时间格式,时间戳的形式 +print(time.time()) + +# 第二种时间格式,格式化的时间 +print(time.strftime('%Y-%m-%d %X')) +print(time.strftime('%Y-%m-%d %H-%M-%S')) + +# 第三种时间格式,结构化的时间,是一个元组 +print(time.localtime()) +``` + +小结:时间戳是计算机能够识别的时间;时间字符串是人能够看懂的时间;元组则是用来操作时间的 + +**几种格式之间的转换** + + + ![img](10.常用模块/987936105.png) + +```python +import time + +# 格式化时间 ----> 结构化时间 +ft = time.strftime('%Y/%m/%d %H:%M:%S') +st = time.strptime(ft,'%Y/%m/%d %H:%M:%S') +print(st) +# 结构化时间 ---> 时间戳 +t = time.mktime(st) +print(t) + +# 时间戳 ----> 结构化时间 +t = time.time() +st = time.localtime(t) +print(st) +# 结构化时间 ---> 格式化时间 +ft = time.strftime('%Y/%m/%d %H:%M:%S',st) +print(ft) +``` + + ![img](10.常用模块/838049513.png) + +```python +import time + +#结构化时间 --> %a %b %d %H:%M:%S %Y串 +#time.asctime(结构化时间) 如果不传参数,直接返回当前时间的格式化串 +print(time.asctime(time.localtime(1550312090.4021888))) + +#时间戳 --> %a %d %d %H:%M:%S %Y串 +#time.ctime(时间戳) 如果不传参数,直接返回当前时间的格式化串 +print(time.ctime(1550312090.4021888)) +``` + +计算时间差 + +```python +import time + +start_time=time.mktime(time.strptime('2017-09-11 08:30:00','%Y-%m-%d %H:%M:%S')) +end_time=time.mktime(time.strptime('2019-09-12 11:00:50','%Y-%m-%d %H:%M:%S')) +dif_time=end_time-start_time +struct_time=time.gmtime(dif_time) +print('过去了%d年%d月%d天%d小时%d分钟%d秒'%(struct_time.tm_year-1970,struct_time.tm_mon-1, + struct_time.tm_mday-1,struct_time.tm_hour, + struct_time.tm_min,struct_time.tm_sec)) +``` + +### datatime模块 + +```python +# datatime模块 +import datetime +now_time = datetime.datetime.now() # 现在的时间 +# 只能调整的字段:weeks days hours minutes seconds +print(datetime.datetime.now() + datetime.timedelta(weeks=3)) # 三周后 +print(datetime.datetime.now() + datetime.timedelta(weeks=-3)) # 三周前 +print(datetime.datetime.now() + datetime.timedelta(days=-3)) # 三天前 +print(datetime.datetime.now() + datetime.timedelta(days=3)) # 三天后 +print(datetime.datetime.now() + datetime.timedelta(hours=5)) # 5小时后 +print(datetime.datetime.now() + datetime.timedelta(hours=-5)) # 5小时前 +print(datetime.datetime.now() + datetime.timedelta(minutes=-15)) # 15分钟前 +print(datetime.datetime.now() + datetime.timedelta(minutes=15)) # 15分钟后 +print(datetime.datetime.now() + datetime.timedelta(seconds=-70)) # 70秒前 +print(datetime.datetime.now() + datetime.timedelta(seconds=70)) # 70秒后 + +current_time = datetime.datetime.now() +# 可直接调整到指定的 年 月 日 时 分 秒 等 + +print(current_time.replace(year=1977)) # 直接调整到1977年 +print(current_time.replace(month=1)) # 直接调整到1月份 +print(current_time.replace(year=1989,month=4,day=25)) # 1989-04-25 18:49:05.898601 + +# 将时间戳转化成时间 +print(datetime.date.fromtimestamp(1232132131)) # 2009-01-17 +``` + +## random模块 + +用来生成随机数模块 + +```python +import random + +print(random.random()) # 大于0且小于1之间的小数 +print(random.uniform(1,3)) # 大于1小于3的小数 + +print(random.randint(1,5)) # 大于等于1且小于等于5之间的整数 +print(random.randrange(1,10,2)) # 大于等于1且小于10之间的奇数 + +ret = random.choice([1,'23',[4,5]]) # 1或者23或者[4,5] +print(ret) + +a,b = random.sample([1,'23',[4,5]],2) # 列表元素任意2个组合 +print(a,b) + +item = [1,3,5,7,9] +random.shuffle(item) # 打乱次序 +print(item) +``` + +生成随机验证码 + +```python +import random + +def v_code(): + + code = '' + for i in range(5): + + num=random.randint(0,9) + alf=chr(random.randint(65,90)) + add=random.choice([num,alf]) + code="".join([code,str(add)]) + + return code + +print(v_code()) +``` + +## OS模块 + +os模块是与操作系统交互的一个接口 + +当前执行这个python文件的工作目录相关的**工作路径** + +| os.getcwd() | 获取当前工作目录,即当前python脚本工作的目录路径 | +| :------------------ | :----------------------------------------------- | +| os.chdir("dirname") | 改变当前脚本工作目录;相当于shell下cd | +| os.curdir | 返回当前目录: ('.') | +| os.pardir | 获取当前目录的父目录字符串名:('..') | + +**文件夹相关** + +| os.makedirs('dirname1/dirname2') | 可生成多层递归目录 | +| :------------------------------- | :----------------------------------------------------------- | +| os.removedirs('dirname1') | 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推 | +| os.mkdir('dirname') | 生成单级目录;相当于shell中mkdir dirname | +| os.rmdir('dirname') | 删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname | +| os.listdir('dirname') | 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印 | + +**文件相关** + +| os.remove() | 删除一个文件 | +| :----------------------------- | :---------------- | +| os.rename("oldname","newname") | 重命名文件/目录 | +| os.stat('path/filename') | 获取文件/目录信息 | + +操作系统差异相关 + +| os.sep | 输出操作系统特定的路径分隔符,win下为"\\\",Linux下为"/" | +| :--------- | :------------------------------------------------------ | +| os.linesep | 输出当前平台使用的行终止符,win下为"\t\n",Linux下为"\n" | +| os.pathsep | 输出用于分割文件路径的字符串 win下为;,Linux下为: | +| os.name | 输出字符串指示当前使用平台。win->'nt'; Linux->'posix' | + +执**行系统命令相关** + +| os.system("bash command") | 运行shell命令,直接显示 | +| :----------------------------- | :-------------------------- | +| os.popen("bash command).read() | 运行shell命令,获取执行结果 | +| os.environ | 获取系统环境变量 | + +**path系列,和路径相关** + +| os.path.abspath(path) | 返回path规范化的绝对路径 | +| :---------------------------------- | :----------------------------------------------------------- | +| os.path.split(path) | 将path分割成目录和文件名二元组返回 | +| os.path.dirname(path) | 返回path的目录。其实就是os.path.split(path)的第一个元素 | +| os.path.basename(path) | 返回path最后的文件名。如何path以/或\结尾,那么就会返回空值,即os.path.split(path)的第二个元素。 | +| os.path.exists(path) | 如果path存在,返回True;如果path不存在,返回False | +| os.path.isabs(path) | 如果path是绝对路径,返回True | +| os.path.isfile(path) | 如果path是一个存在的文件,返回True。否则返回False | +| os.path.isdir(path) | 如果path是一个存在的目录,则返回True。否则返回False | +| os.path.join(path1[, path2[, ...]]) | 将多个路径组合后返回,第一个绝对路径之前的参数将被忽略 | +| os.path.getatime(path) | 返回path所指向的文件或者目录的最后访问时间 | +| os.path.getmtime(path) | 返回path所指向的文件或者目录的最后修改时间 | +| os.path.getsize(path) | 返回path的大小 | + +```python +import os + +print(os.stat('.\config')) # 当前目录下的config文件的信息 + +# 运行结果 +# os.stat_result(st_mode=33206, st_ino=2814749767208887, st_dev=1788857329, st_nlink=1, st_uid=0, st_gid=0, st_size=185, st_atime=1550285376, st_mtime=1550285376, st_ctime=1550285376) +``` + +| st_mode | inode 保护模式 | +| :------- | :----------------------------------------------------------- | +| st_ino | inode 节点号 | +| st_dev | inode 驻留的设备 | +| st_nlink | inode 的链接数 | +| st_uid | 所有者的用户ID | +| st_gid | 所有者的组ID | +| st_size | 普通文件以字节为单位的大小;包含等待某些特殊文件的数据 | +| st_atime | 上次访问的时间 | +| st_mtime | 最后一次修改的时间 | +| st_ctime | 由操作系统报告的"ctime"。在某些系统上(如Unix)是最新的元数据更改的时间,在其它系统上(如Windows)是创建时间(详细信息参见平台的文档) | + +## sys模块 + +sys模块是与python解释器交互的一个接口 + +| sys.argv | 命令行参数List,第一个元素是程序本身路径 | +| :----------- | :----------------------------------------------------- | +| sys.exit(n) | 退出程序,正常退出时exit(0),错误退出sys.exit(1) | +| sys.version | 获取Python解释程序的版本信息 | +| sys.path | 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值 | +| sys.platform | 返回操作系统平台名称 | + +## re模块 + +### 正则表达式 + +正则就是用一些具有特殊含义的符号组合到一起(称为正则表达式)来描述字符或者字符串的方法。或者说:正则就是用来描述一类事物的规则。(在Python中)它内嵌在Python中,并通过 re 模块实现。正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹配引擎执行。 + +| 元字符 | 匹配内容 | +| :----- | :----------------------------------------------------------- | +| \w | 匹配字母(包含中文)或数字或下划线 | +| \W | 匹配非字母(包含中文)或数字或下划线 | +| \s | 匹配任意的空白符 | +| \S | 匹配任意非空白符 | +| \d | 匹配数字 | +| \D | 匹配非数字 | +| \A | 从字符串开头匹配 | +| \z | 匹配字符串的结束,如果是换行,只匹配到换行前的结果 | +| \n | 匹配一个换行符 | +| \t | 匹配一个制表符 | +| ^ | 匹配字符串的开始 | +| $ | 匹配字符串的结尾 | +| . | 匹配任意字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符。 | +| [...] | 匹配字符组中的字符 | +| [^...] | 匹配除了字符组中的字符的所有字符 | +| * | 匹配0个或者多个左边的字符。 | +| + | 匹配一个或者多个左边的字符。 | +| ? | 匹配0个或者1个左边的字符,非贪婪方式。 | +| {n} | 精准匹配n个前面的表达式。 | +| {n,m} | 匹配n到m次由前面的正则表达式定义的片段,贪婪方式 | +| a | b | +| () | 匹配括号内的表达式,也表示一个组 | + +#### 单字符匹配 + +```python +import re + +print(re.findall('\w','上大人123asdfg%^&*(_ \t \n)')) +print(re.findall('\W','上大人123asdfg%^&*(_ \t \n)')) + +print(re.findall('\s','上大人123asdfg%^&*(_ \t \n)')) +print(re.findall('\S','上大人123asdfg%^&*(_ \t \n)')) + +print(re.findall('\d','上大人123asdfg%^&*(_ \t \n)')) +print(re.findall('\D','上大人123asdfg%^&*(_ \t \n)')) + +print(re.findall('\A上大','上大人123asdfg%^&*(_ \t \n)')) +print(re.findall('^上大','上大人123asdfg%^&*(_ \t \n)')) + +print(re.findall('666\z','上大人123asdfg%^&*(_ \t \n)666')) +print(re.findall('666\Z','上大人123asdfg%^&*(_ \t \n)666')) +print(re.findall('666$','上大人123asdfg%^&*(_ \t \n)666')) + +print(re.findall('\n','上大人123asdfg%^&*(_ \t \n)')) +print(re.findall('\t','上大人123asdfg%^&*(_ \t \n)')) +``` + +#### 重复匹配 + +```python +import re + +print(re.findall('a.b', 'ab aab a*b a2b a牛b a\nb')) +print(re.findall('a.b', 'ab aab a*b a2b a牛b a\nb',re.DOTALL)) + +print(re.findall('a?b', 'ab aab abb aaaab a牛b aba**b')) + +print(re.findall('a*b', 'ab aab aaab abbb')) +print(re.findall('ab*', 'ab aab aaab abbbbb')) + +print(re.findall('a+b', 'ab aab aaab abbb')) + +print(re.findall('a{2,4}b', 'ab aab aaab aaaaabb')) + +print(re.findall('a.*b', 'ab aab a*()b')) + +print(re.findall('a.*?b', 'ab a1b a*()b, aaaaaab')) +# .*? 此时的?不是对左边的字符进行0次或者1次的匹配, +# 而只是针对.*这种贪婪匹配的模式进行一种限定:告知他要遵从非贪婪匹配 推荐使用! + +# []: 括号中可以放任意一个字符,一个中括号代表一个字符 +# - 在[]中表示范围,如果想要匹配上- 那么这个-符号不能放在中间. +# ^ 在[]中表示取反的意思. +print(re.findall('a.b', 'a1b a3b aeb a*b arb a_b')) +print(re.findall('a[abc]b', 'aab abb acb adb afb a_b')) +print(re.findall('a[0-9]b', 'a1b a3b aeb a*b arb a_b')) +print(re.findall('a[a-z]b', 'a1b a3b aeb a*b arb a_b')) +print(re.findall('a[a-zA-Z]b', 'aAb aWb aeb a*b arb a_b')) +print(re.findall('a[0-9][0-9]b', 'a11b a12b a34b a*b arb a_b')) +print(re.findall('a[*-+]b','a-b a*b a+b a/b a6b')) +print(re.findall('a[-*+]b','a-b a*b a+b a/b a6b')) +print(re.findall('a[^a-z]b', 'acb adb a3b a*b')) + +# 分组:() 制定一个规则,将满足规则的结果匹配出来 +print(re.findall('(.*?)_sb', 'cs_sb zhao_sb 日天_sb')) +print(re.findall('href="(.*?)"','点击')) + +print(re.findall('compan(y|ies)','Too many companies have gone bankrupt, and the next one is my company')) +print(re.findall('compan(?:y|ies)','Too many companies have gone bankrupt, and the next one is my company')) +# 分组() 中加入?: 表示将整体匹配出来而不只是()里面的内容 +``` + +#### 常用方法举例 + +```python +import re + +# findall 全部找到返回一个列表 +print(re.findall('a','aghjmnbghagjmnbafgv')) + +# search 只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None +print(re.search('sb|chensong', 'chensong sb sb demon 日天')) +print(re.search('chensong', 'chensong sb sb barry 日天').group()) + +# match:None,同search,不过在字符串开始处进行匹配,完全可以用search+^代替match +print(re.match('sb|chensong', 'chensong sb sb demon 日天')) +print(re.match('chensong', 'chensong sb sb barry 日天').group()) + +# split 分割 可按照任意分割符进行分割 +print(re.split('[::,;;,]','1;3,c,a:3')) + +# sub 替换 +print(re.sub('帅哥','sb','陈松是一个帅哥')) + +# complie 根据包含的正则表达式的字符串创建模式对象。可以实现更有效率的匹配。 +obj = re.compile('\d{2}') +print(obj.search('abc123eeee').group()) +print(obj.findall('1231232aasd')) + +ret = re.finditer('\d','asd123affess32432') # finditer返回一个存放匹配结果的迭代器 +print(ret) +print(next(ret).group()) +print(next(ret).group()) +print([i.group() for i in ret]) +``` + +#### 命名分组举例 + +命名分组匹配 + +```python +import re + +ret = re.search("<(?P\w+)>\w+","

hello

") +print(ret.group('tag_name')) +print(ret.group()) + +ret = re.search(r"<(\w+)>\w+","

hello

") +# 如果不给组起名字,也可以用\序号来找到对应的组,表示要找的内容和前面的组内容一致 +# 获取的匹配结果可以直接用group(序号)拿到对应的值 +print(ret.group(1)) +print(ret.group()) +``` + +## shutil模块 + +高级的 文件、文件夹、压缩包 处理模块 + +### shutil.copyfileobj(fsrc, fdst[, length]) + +将文件内容拷贝到另一个文件中 + +```python +import shutil + +shutil.copyfileobj(open('config','r'),open('config.new','w')) +``` + +### shutil.copyfile(src, dst) + +拷贝文件 + +```python +import shutil + +shutil.copyfile('config','config1') # 目标文件无需存在 +``` + +### shutil.copymode(src, dst) + +仅拷贝权限。内容、组、用户均不变 + +```python +import shutil + +shutil.copymode('config','config1') # 目标文件必须存在 +``` + +### shutil.copystat(src, dst) + +仅拷贝状态的信息,包括:mode bits, atime, mtime, flags + +```python +import shutil + +shutil.copystat('config','config1') # 目标文件必须存在 +``` + +### shutil.copy(src, dst) + +拷贝文件和权限 + +```python +import shutil + +shutil.copy('config','config1') # 目标文件必须存在 +``` + +### shutil.ignore_patterns(*patterns) + +### shutil.copytree(src, dst, symlinks=False, ignore=None) + +递归的去拷贝文件夹 + +```python +import shutil + +shutil.copytree('folder1', 'folder2', ignore=shutil.ignore_patterns('*.pyc', 'tmp*')) +# 目标目录不能存在,注意对folder2目录父级目录要有可写权限,ignore的意思是排除 +# 硬链接 + +shutil.copytree('f1', 'f2', symlinks=True, ignore=shutil.ignore_patterns('*.pyc', 'tmp*')) +# 软链接 +``` + +### shutil.rmtree(path[, ignore_errors[, onerror]]) + +递归的去删除文件 + +```python +import shutil + +shutil.rmtree('folder1') +``` + +### shutil.move(src, dst) + +递归的去移动文件,它类似mv命令,其实就是重命名。 + +```python +import shutil + +shutil.move('folder1', 'folder3') +``` + +### shutil.make_archive(base_name, format,...) + +- 创建压缩包并返回文件路径,例如:zip、tar + - base_name: 压缩包的文件名,也可以是压缩包的路径。只是文件名时,则保存至当前目录,否则保存至指定路径, + - 如 data_bak =>保存至当前路径 + - 如:/tmp/data_bak =>保存至/tmp/ + - format: 压缩包种类,“zip”, “tar”, “bztar”,“gztar” + - root_dir: 要压缩的文件夹路径(默认当前目录) + - owner: 用户,默认当前用户 + - group: 组,默认当前组 + - logger: 用于记录日志,通常是logging.Logger对象 + +```python +# 将 /data 下的文件打包放置当前程序目录 +import shutil +ret = shutil.make_archive("data_bak", 'gztar', root_dir='/data') + + +# 将 /data下的文件打包放置 /tmp/目录 +import shutil +ret = shutil.make_archive("/tmp/data_bak", 'gztar', root_dir='/data') +``` + +shutil 对压缩包的处理是调用 ZipFile 和 TarFile 两个模块来进行的 + +```python +import zipfile + +# 压缩 +z = zipfile.ZipFile('laxi.zip', 'w') +z.write('a.log') +z.write('data.data') +z.close() + +# 解压 +z = zipfile.ZipFile('laxi.zip', 'r') +z.extractall(path='.') +z.close() +``` + +```python +import tarfile + +# 压缩文件 +t = tarfile.open('/tmp/egon.tar','w') +t.add('/test1/a.py',arcname='a.bak') +t.add('/test1/b.py',arcname='b.bak') +t.close() + +# 解压缩文件 +t = tarfile.open('/tmp/egon.tar','r') +t.extractall('/egon') +t.close() +``` + diff --git a/01.基础语法/10.常用模块/3856406007.png b/01.基础语法/10.常用模块/3856406007.png new file mode 100644 index 0000000..25d9672 Binary files /dev/null and b/01.基础语法/10.常用模块/3856406007.png differ diff --git a/01.基础语法/10.常用模块/5NnyAJyLO6F1x0aY.png!thumbnail b/01.基础语法/10.常用模块/5NnyAJyLO6F1x0aY.png!thumbnail new file mode 100644 index 0000000..d25fca5 Binary files /dev/null and b/01.基础语法/10.常用模块/5NnyAJyLO6F1x0aY.png!thumbnail differ diff --git a/01.基础语法/10.常用模块/5sL2I6iz3J2Qn00r.png!thumbnail b/01.基础语法/10.常用模块/5sL2I6iz3J2Qn00r.png!thumbnail new file mode 100644 index 0000000..de7072f Binary files /dev/null and b/01.基础语法/10.常用模块/5sL2I6iz3J2Qn00r.png!thumbnail differ diff --git a/01.基础语法/10.常用模块/838049513.png b/01.基础语法/10.常用模块/838049513.png new file mode 100644 index 0000000..0a77c8b Binary files /dev/null and b/01.基础语法/10.常用模块/838049513.png differ diff --git a/01.基础语法/10.常用模块/987936105.png b/01.基础语法/10.常用模块/987936105.png new file mode 100644 index 0000000..69bfec4 Binary files /dev/null and b/01.基础语法/10.常用模块/987936105.png differ diff --git a/01.基础语法/10.常用模块/VA9mmGsaAk8HNGKh.png!thumbnail b/01.基础语法/10.常用模块/VA9mmGsaAk8HNGKh.png!thumbnail new file mode 100644 index 0000000..8230537 Binary files /dev/null and b/01.基础语法/10.常用模块/VA9mmGsaAk8HNGKh.png!thumbnail differ diff --git a/01.基础语法/12.异常处理.md b/01.基础语法/12.异常处理.md new file mode 100644 index 0000000..6eb5b35 --- /dev/null +++ b/01.基础语法/12.异常处理.md @@ -0,0 +1,331 @@ +# 异常处理 + +## 异常和错误 + +### 程序中难免出现错误,而错误分成两种 + +1. 语法错误(这种错误,根本过不了python解释器的语法检测,必须在程序执行前就改正) + +```python +#语法错误示范一 +if + +#语法错误示范二 +def test: + pass + +#语法错误示范三 +print(haha +``` + +### 逻辑错误 + +```python +#用户输入不完整(比如输入为空)或者输入非法(输入不是数字) +num=input(">>: ") +res1 = int(num) + +#无法完成计算 +res1=1/0 +res2=1+'str' +``` + +### 异常 + +异常就是程序运行时发生错误的信号 +异常之后的代码就不执行 + + ![img](12.异常处理/1480155108.png) + +### 异常种类 + +在python中不同的异常可以用不同的类型(python中统一了类与类型,类型即类)去标识,不同的类对象标识不同的异常,一个异常标识一种错误 + +```python +# 触发IndexError +l=['eagle','aa'] +l[3] +# 触发KeyError +dic={'name':'eagle'} +dic['age'] + +#触发ValueError +s='hello' +int(s) +``` + +常见异常 + +| AttributeError | 试图访问一个对象没有的属性,比如foo.x,但是foo没有属性x | +| :---------------- | :----------------------------------------------------------- | +| IOError | 输入/输出异常;基本上是无法打开文件 | +| ImportError | 无法引入模块或包;基本上是路径问题或名称错误 | +| IndentationError | 语法错误(的子类) ;代码没有正确对齐 | +| IndexError | 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5] | +| KeyError | 试图访问字典里不存在的键 | +| KeyboardInterrupt | Ctrl+C被按下 | +| NameError | 使用一个还未被赋予对象的变量 | +| SyntaxError | Python代码非法,代码不能编译(个人认为这是语法错误,写错了) | +| TypeError | 传入对象类型与要求的不符合 | +| UnboundLocalError | 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,导致你以为正在访问它 | +| ValueError | 传入一个调用者不期望的值,即使值的类型是正确的 | + +其他错误 + +```python +ArithmeticError +AssertionError +AttributeError +BaseException +BufferError +BytesWarning +DeprecationWarning +EnvironmentError +EOFError +Exception +FloatingPointError +FutureWarning +GeneratorExit +ImportError +ImportWarning +IndentationError +IndexError +IOError +KeyboardInterrupt +KeyError +LookupError +MemoryError +NameError +NotImplementedError +OSError +OverflowError +PendingDeprecationWarning +ReferenceError +RuntimeError +RuntimeWarning +StandardError +StopIteration +SyntaxError +SyntaxWarning +SystemError +SystemExit +TabError +TypeError +UnboundLocalError +UnicodeDecodeError +UnicodeEncodeError +UnicodeError +UnicodeTranslateError +UnicodeWarning +UserWarning +ValueError +Warning +ZeroDivisionError +``` + +## 异常处理 + +- python解释器检测到错误,触发异常(也允许程序员自己触发异常) +- 程序员编写特定的代码,专门用来捕捉这个异常(这段代码与程序逻辑无关,与异常处理有关) +- 如果捕捉成功则进入另外一个处理分支,执行你为其定制的逻辑,使程序不会崩溃,这就是异常处理 + **首先须知,异常是由程序的错误引起的,语法上的错误跟异常处理无关,必须在程序运行前就修正** + +```python +num1=input('>>: ') #输入一个字符串试试 +if num1.isdigit(): + int(num1) #我们的正统程序放到了这里,其余的都属于异常处理范畴 +elif num1.isspace(): + print('输入的是空格,就执行我这里的逻辑') +elif len(num1) == 0: + print('输入的是空,就执行我这里的逻辑') +else: + print('其他情情况,执行我这里的逻辑') + +''' +问题一: +使用if的方式我们只为第一段代码加上了异常处理,但这些if,跟你的代码逻辑并无关系,这样你的代码会因为可读性差而不容易被看懂 + +问题二: +这只是我们代码中的一个小逻辑,如果类似的逻辑多,那么每一次都需要判断这些内容,就会倒置我们的代码特别冗长。 +''' +``` + +总结: + +1. if判断式的异常处理只能针对某一段代码,对于不同的代码段的相同类型的错误你需要写重复的if来进行处理。 + +2. 在你的程序中频繁的写与程序本身无关,与异常处理有关的if,会使得你的代码可读性极其的差 + +3. if是可以解决异常的,只是存在1,2的问题,所以,千万不要妄下定论if不能用来异常处理。 + +```python +def test(): + print('test.runing') + +choice_dic = { + '1':test +} + +while True: + choice = (input('>>: ').strip()) + if not choice or choice not in choice_dic:continue + choice_dic[choice]() +``` + +**python:为每一种异常定制了一个类型,然后提供了一种特定的语法结构用来进行异常处理** + +### 基本语法 + +```python +try: + 被检测的代码块 +except 异常类型: + try中一旦检测到异常,就执行这个位置的逻辑 +``` + +将文件的每一行变成一个迭代器,然后读出来 + +```python +f = open('a.txt') + +g = (line.strip() for line in f) +for line in g: + print(line) +else: + f.close() +``` + +但是如果超出了迭代器的范围就会出现`StopIteration`错误 + +使用异常处理 + +```python +try: + f = open('a.txt') + + g = (line.strip() for line in f) + print(next(g)) + print(next(g)) + print(next(g)) + print(next(g)) + print(next(g)) + print(next(g)) + print(next(g)) + print(next(g)) + print(next(g)) + print(next(g)) +except StopIteration: + f.close() + print('读取出错') +``` + +### 异常类只能用来处理指定的异常情况 + +```python +s1 = 'hello' +try: + int(s1) +except IndexError as e: + print e +``` + +### 多分支 + +主要是用来针对不同的错误情况进行错误处理 + +```python +s1 = 'hello' +try: + int(s1) +except IndexError as e: + print(e) +except KeyError as e: + print(e) +except ValueError as e: + print(e) +``` + +### 万能异常:Exception + +```python +s1 = 'hello' +try: + int(s1) +except Exception as e: + print(e) +``` + +多分支加万能异常 + +```python +s1 = 'hello' +try: + int(s1) +except IndexError as e: + print(e) +except KeyError as e: + print(e) +except ValueError as e: + print(e) +except Exception as e: + print(e) +``` + +## 其他异常情况 + +```python +s1 = '10' +try: + int(s1) +except IndexError as e: + print(e) +except KeyError as e: + print(e) +except ValueError as e: + print(e) +except Exception as e: + print(e) +else: + print('try内代码块没有异常则执行我') +finally: + print('无论异常与否,都会执行该模块,通常是进行清理工作') +``` + +### 主动触发异常 + +```python +try: + raise TypeError('类型错误') +except Exception as e: + print(e) +``` + +### 自定义异常 + +```python +class EvaException(BaseException): + def __init__(self,msg): + self.msg=msg + def __str__(self): + return self.msg + +try: + raise EvaException('类型错误') +except EvaException as e: + print(e) +``` + +### 断言 + +表达式位True时,程序继续运行,表达式为False时程序终止运行,并报AssertionError错误 + +```python +assert 1 == 1 +assert 1 == 2 +``` + +### try..except的方式比较if的方式的好处 + +1. 把错误处理和真正的工作分开来 +2. 代码更易组织,更清晰,复杂的工作任务更容易实现 +3. 毫无疑问,更安全了,不至于由于一些小的疏忽而使程序意外崩溃了 diff --git a/01.基础语法/12.异常处理/1480155108.png b/01.基础语法/12.异常处理/1480155108.png new file mode 100644 index 0000000..517862f Binary files /dev/null and b/01.基础语法/12.异常处理/1480155108.png differ diff --git a/01.基础语法/12.异常处理/YG9kCGCs3sF9bTJI.png!thumbnail b/01.基础语法/12.异常处理/YG9kCGCs3sF9bTJI.png!thumbnail new file mode 100644 index 0000000..6b8de07 Binary files /dev/null and b/01.基础语法/12.异常处理/YG9kCGCs3sF9bTJI.png!thumbnail differ diff --git a/01.基础语法/13.垃圾回收机制.md b/01.基础语法/13.垃圾回收机制.md new file mode 100644 index 0000000..f54e444 --- /dev/null +++ b/01.基础语法/13.垃圾回收机制.md @@ -0,0 +1,618 @@ +# 垃圾回收机制 + +## 总概括 + +如果将应用程序比作人的身体:所有你所写的那些优雅的代码,业务逻辑,算法,应该就是大脑。垃圾回收就是应用程序就是相当于人体的腰子,过滤血液中的杂质垃圾,没有腰子,人就会得尿毒症,垃圾回收器为你的应该程序提供内存和对象。如果垃圾回收器停止工作或运行迟缓,像尿毒症,你的应用程序效率也会下降,直至最终崩溃坏死。 + +在C/C++中采用**用户自己管理维护内存**的方式。自己管理内存极其自由,可以任意申请内存,但也为大量内存泄露、悬空指针等bug埋下隐患。 + +因此在现在的高级语言(java、C#等)都采用了垃圾收集机制。python也采用了垃圾收集机制。 + +Python的垃圾回收机制到底是什么回事?从网上找到一大堆的文档,看的也是一知半解,最终就学会了一句话: + +`引用计数器为主、分代回收和标记清除为辅`。 + +但是实际上其内部原理还是有很多复杂地方的。 + +引用计数器为主 + +标记清除和分代回收为辅+缓存机制 + +基于C语言源码底层,让你真正了解垃圾回收机制的实现。 + +●引用计数器 + +●标记清除 + +●分代回收 + +●缓存机制 + +●Python的C源码(3.8.2版本) + +## 一、引用计数器 + +### 1.1环状的双向链表(Refchain) + +![图片](data:image/png;base64,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TmstJHFdF52qiufzyXEcnOdJp7UWkriui062eb1eHMfBnJNOay0kcV0XnaqK5/PJcRyc50mntRaSuK6LTrZ5vV4cx8Gck05rLSRxXRedqorn88lxHJznSae1FpK4rotOtnm9XhzHwZyTTmstJHFdF52qiufzyXEcnOdJp7UWkriui062eb1eHMfBnJNOay0kcV0XnaqK5/PJcRyc50mntRaSuK6LTrZ5vV4cx8Gck05rLSRxXRedqorn88lxHJznSae1FpK4rotOtnm9XhzHwZyTTmstJHFdF52qiufzyXEcnOdJp7UWkriui062eb1eHMfBnJNOay0kcV0XnaqK5/PJcRyc50mntRaSuK6LTrZ5vV4cx8Gck05rLSRxXRedqorn88lxHJznSae1FpK4rotOtnm9XhzHwZyTTmstJHFdF52qiufzyXEcnOdJp7UWkriui062eb1eHMfBnJNOay0kcV0XnaqK5/PJcRyc50mntRaSuK6LTrZ5vV4cx8Gck05rLSRxXRedqorn88lxHJznSae1FpK4rotOtnm9XhzHwZyTTmstJHFdF52qiufzyXEcnOdJp7UWkriui062eb1eHMfBnJNOay0kcV0XnaqK5/PJcRyc50mntRaSuK6LTrZ5vV4cx8Gck05rLSRxXRc/x4OIiIiIiIiIiIiIL+hBRERERERERERExBf0ICIiIiIiIiIiIuILehARERERERERERHxBT2IiIiIiIiIiIiI+IIeRERERERERERERHxBDyIiIiIiIiIiIiK+oAcRERERERERERERX9CDiIiIiIiIiIiIiC/oQURERERERERERMQX9CAiIiIiIiIiIiLiC3oQERERERERERER8QU9iIiIiIiIiIiIiPiCHkRERERERERERER8QQ8iIiIiIiIiIiIivqAHEREREREREREREV/Qg4iIiIiIiIiIiIgv6EFERERERERERETEF/QgIiIiIiIiIiIi4guaVcVPkYRtJFFVdLKNbaqKTrb5IImqopNtbFNVdJKEbSRRVXSyjW2qik62+SCJqqKTbWxTVXSShG0kUVV0so1tqopOtvkgiaqik21sU1V0koRtJFFVdLKNbaqKTrb5IImqopNtbFNVdJKEbSRRVXSyjW2qik62+SCJqqKTbWxTVXSShG0kUVV0so1tqopOtvkgiaqik21sU1V0koRtJFFVdLKNbaqKTrb5IImqopNtbFNVdJKEbSRRVXSyjW2qik62+SCJqqKTbWxTVXSShG0kUVV0so1tqopOtvkgiaqik21sU1V0koRtJFFVdLKNbaqKTrb5IImqopNtbFNVdJKEbSRRVXSyjW2qik62+SCJqqKTbWxTVXSShG0kUVV0so1tqopOtvkgiaqik21sU1V0koRtJFFVdLKNbaqKTrb5IImqopNtbFNVdJKEbSRRVXSyjW2qik62+SCJqqKTbWxTVXSShG0kUVV0so1tqopOtvkgiaqik21sU1X8HOO//Jf/Yn6CbSTxeDwYY9Bp33cejwdrLTqNMTjPk/f3d6qKTvu+83g8WGvRyTaSeDwejDHotO87j8eDtRadxhic58n7+ztVRad933k8Hqy16GQbSTweD8YYdNr3ncfjwVqLTmMMzvPk/f2dqqLTvu88Hg/WWnSyjSQejwdjDDrt+87j8WCtRacxBud58v7+TlXRad93Ho8Hay062UYSj8eDMQad9n3n8Xiw1qLTGIPzPHl/f6eq6LTvO4/Hg7UWnWwjicfjwRiDTvu+83g8WGvRaYzBeZ68v79TVXTa953H48Fai062kcTj8WCMQad933k8Hqy16DTG4DxP3t/fqSo67fvO4/FgrUUn20ji8XgwxqDTvu88Hg/WWnQaY3CeJ+/v71QVnfZ95/F4sNaik20k8Xg8GGPQad93Ho8Hay06jTE4z5P393eqik77vvN4PFhr0ck2kng8Howx6LTvO4/Hg7UWncYYnOfJ+/s7VUWnfd95PB6stehkG0k8Hg/GGHTa953H48Fai05jDM7z5P39naqi077vPB4P1lp0so0kHo8HYww67fvO4/FgrUWnMQbnefL+/k5V0Wnfdx6PB2stOtlGEo/HgzEGnfZ95/F4sNai0xiD8zx5f3+nqui07zuPx4O1Fp1sI4nH48EYg077vvN4PFhr0WmMwXmevL+/U1V02vedx+PBWotOtpHE4/FgjEGnfd95PB6steg0xuA8T97f36kqOu37zuPxYK3FzzH+23/7b+YnSOL79+98+/aNfd/pJAnbbNtGt/u+2baNMQadJGGbbdvoJInv37/z7ds39n2nkyRss20b3e77Zts2xhh0koRttm2jkyS+f//Ot2/f2PedTpKwzbZtdLvvm23bGGPQSRK22baNTpL4/v073759Y993OknCNtu20e2+b7ZtY4xBJ0nYZts2Okni+/fvfPv2jX3f6SQJ22zbRrf7vtm2jTEGnSRhm23b6CSJ79+/8+3bN/Z9p5MkbLNtG93u+2bbNsYYdJKEbbZto5Mkvn//zrdv39j3nU6SsM22bXS775tt2xhj0EkSttm2jU6S+P79O9++fWPfdzpJwjbbttHtvm+2bWOMQSdJ2GbbNjpJ4vv373z79o193+kkCdts20a3+77Zto0xBp0kYZtt2+gkie/fv/Pt2zf2faeTJGyzbRvd7vtm2zbGGHSShG22baOTJL5//863b9/Y951OkrDNtm10u++bbdsYY9BJErbZto1Okvj+/Tvfvn1j33c6ScI227bR7b5vtm1jjEEnSdhm2zY6SeL79+98+/aNfd/pJAnbbNtGt/u+2baNMQadJGGbbdvoJInv37/z7ds39n2nkyRss20b3e77Zts2xhh0koRttm2jkyS+f//Ot2/f2PedTpKwzbZtdLvvm23bGGPQSRK22baNn2Oe58lPqSrGGOz7znmedFprIYnzPOlkm/u+2fedOSed1lpI4jxPOlUVYwz2fec8TzqttZDEeZ50ss193+z7zpyTTmstJHGeJ52qijEG+75znied1lpI4jxPOtnmvm/2fWfOSae1FpI4z5NOVcUYg33fOc+TTmstJHGeJ51sc983+74z56TTWgtJnOdJp6pijMG+75znSae1FpI4z5NOtrnvm33fmXPSaa2FJM7zpFNVMcZg33fO86TTWgtJnOdJJ9vc982+78w56bTWQhLnedKpqhhjsO8753nSaa2FJM7zpJNt7vtm33fmnHRaayGJ8zzpVFWMMdj3nfM86bTWQhLnedLJNvd9s+87c046rbWQxHmedKoqxhjs+855nnRaayGJ8zzpZJv7vtn3nTknndZaSOI8TzpVFWMM9n3nPE86rbWQxHmedLLNfd/s+86ck05rLSRxniedqooxBvu+c54nndZaSOI8TzrZ5r5v9n1nzkmntRaSOM+TTlXFGIN93znPk05rLSRxniedbHPfN/u+M+ek01oLSZznSaeqYozBvu+c50mntRaSOM+TTra575t935lz0mmthSTO86RTVTHGYN93zvOk01oLSZznSSfb3PfNvu/MOem01kIS53nSqaoYY7DvO+d50mmthSTO86STbe77Zt935px0WmshifM8+TkeRERERERERERERHxBDyIiIiIiIiIiIiK+oAcRERERERERERERX9CDiIiIiIiIiIiIiC/oQURERERERERERMQX9CAiIiIiIiIiIiLiC3oQERERERERERER8QU9iIiIiIiIiIiIiPiCHkRERERERERERER8QQ8iIiIiIiIiIiIivqAHEREREREREREREV/Qg4iIiIiIiIiIiIgv6EFERERERERERETEF/QgIiIiIiIiIiIi4gt6EBEREREREREREfEFPYiIiIiIiIiIiIj4gh5EREREREREREREfEEPIiIiIiIiIiIiIr6gBxERERERERERERFf0Fxr8VNsY5v7vllr0amqsM1ai89w3zdVRaeqwjZrLTrZxjb3fbPWolNVYZu1Fp/hvm+qik5VhW3WWnSyjW3u+2atRaeqwjZrLT7Dfd9UFZ2qCtustehkG9vc981ai05VhW3WWnyG+76pKjpVFbZZa9HJNra575u1Fp2qCtustfgM931TVXSqKmyz1qKTbWxz3zdrLTpVFbZZa/EZ7vumquhUVdhmrUUn29jmvm/WWnSqKmyz1uIz3PdNVdGpqrDNWotOtrHNfd+stehUVdhmrcVnuO+bqqJTVWGbtRadbGOb+75Za9GpqrDNWovPcN83VUWnqsI2ay062cY2932z1qJTVWGbtRaf4b5vqopOVYVt1lp0so1t7vtmrUWnqsI2ay0+w33fVBWdqgrbrLXoZBvb3PfNWotOVYVt1lp8hvu+qSo6VRW2WWvRyTa2ue+btRadqgrbrLX4DPd9U1V0qipss9aik21sc983ay06VRW2WWvxGe77pqroVFXYZq1FJ9vY5r5v1lp0qipss9biM9z3TVXRqaqwzVqLn2NK4qdI4oMkJNHJNraRRDfbSGKMQSfb2EYSnSTxQRKS6GQb20iim20kMcagk21sI4lOkvggCUl0so1tJNHNNpIYY9DJNraRRCdJfJCEJDrZxjaS6GYbSYwx6GQb20iikyQ+SEISnWxjG0l0s40kxhh0so1tJNFJEh8kIYlOtrGNJLrZRhJjDDrZxjaS6CSJD5KQRCfb2EYS3WwjiTEGnWxjG0l0ksQHSUiik21sI4lutpHEGINOtrGNJDpJ4oMkJNHJNraRRDfbSGKMQSfb2EYSnSTxQRKS6GQb20iim20kMcagk21sI4lOkvggCUl0so1tJNHNNpIYY9DJNraRRCdJfJCEJDrZxjaS6GYbSYwx6GQb20iikyQ+SEISnWxjG0l0s40kxhh0so1tJNFJEh8kIYlOtrGNJLrZRhJjDDrZxjaS6CSJD5KQRCfb2EYS3WwjiTEGnWxjG0n8HPO6Ln5KVfF8PjmOg/M86bTWQhLXddHJNq/Xi+M4mHPSaa2FJK7rolNV8Xw+OY6D8zzptNZCEtd10ck2r9eL4ziYc9JprYUkruuiU1XxfD45joPzPOm01kIS13XRyTav14vjOJhz0mmthSSu66JTVfF8PjmOg/M86bTWQhLXddHJNq/Xi+M4mHPSaa2FJK7rolNV8Xw+OY6D8zzptNZCEtd10ck2r9eL4ziYc9JprYUkruuiU1XxfD45joPzPOm01kIS13XRyTav14vjOJhz0mmthSSu66JTVfF8PjmOg/M86bTWQhLXddHJNq/Xi+M4mHPSaa2FJK7rolNV8Xw+OY6D8zzptNZCEtd10ck2r9eL4ziYc9JprYUkruuiU1XxfD45joPzPOm01kIS13XRyTav14vjOJhz0mmthSSu66JTVfF8PjmOg/M86bTWQhLXddHJNq/Xi+M4mHPSaa2FJK7rolNV8Xw+OY6D8zzptNZCEtd10ck2r9eL4ziYc9JprYUkruuiU1XxfD45joPzPOm01kIS13XRyTav14vjOJhz0mmthSSu66JTVfF8PjmOg/M86bTWQhLXddHJNq/Xi+M4mHPSaa2FJK7rolNV8Xw+OY6D8zzptNZCEtd10ck2r9eL4ziYc9JprYUkruuiU1XxfD45joPzPOm01kIS13XRyTav14vjOJhz0mmthSSu6+LneBARERERERERERHxBT2IiIiIiIiIiIiI+IIeRERERERERERERHxBDyIiIiIiIiIiIiK+oAcRERERERERERERX9CDiIiIiIiIiIiIiC/oQURERERERERERMQX9CAiIiIiIiIiIiLiC3oQERERERERERER8QU9iIiIiIiIiIiIiPiCHkRERERERERERER8QQ8iIiIiIiIiIiIivqAHEREREREREREREV/Qg4iIiIiIiIiIiIgv6EFERERERERERETEF/QgIiIiIiIiIiIi4gt6EBEREREREREREfEFPYiIiIiIiIiIiIj4gh5EREREREREREREfEHTNj/FNh9sY5vPYJtOkvhgG9t8Btt0ss0H29jmM9imkyQ+2MY2n8E2nWzzwTa2+Qy26SSJD7axzWewTSfbfLCNbT6DbTpJ4oNtbPMZbNPJNh9sY5vPYJtOkvhgG9t8Btt0ss0H29jmM9imkyQ+2MY2n8E2nWzzwTa2+Qy26SSJD7axzWewTSfbfLCNbT6DbTpJ4oNtbPMZbNPJNh9sY5vPYJtOkvhgG9t8Btt0ss0H29jmM9imkyQ+2MY2n8E2nWzzwTa2+Qy26SSJD7axzWewTSfbfLCNbT6DbTpJ4oNtbPMZbNPJNh9sY5vPYJtOkvhgG9t8Btt0ss0H29jmM9imkyQ+2MY2n8E2nWzzwTa2+Qy26SSJD7axzWewzc8x/ut//a/mJ9jm+XxyXRdzTrrZZoxBN9uMMfgMthlj0Mk2z+eT67qYc9LNNmMMutlmjMFnsM0Yg062eT6fXNfFnJNuthlj0M02Yww+g23GGHSyzfP55Lou5px0s80Yg262GWPwGWwzxqCTbZ7PJ9d1Meekm23GGHSzzRiDz2CbMQadbPN8Prmuizkn3WwzxqCbbcYYfAbbjDHoZJvn88l1Xcw56WabMQbdbDPG4DPYZoxBJ9s8n0+u62LOSTfbjDHoZpsxBp/BNmMMOtnm+XxyXRdzTrrZZoxBN9uMMfgMthlj0Mk2z+eT67qYc9LNNmMMutlmjMFnsM0Yg062eT6fXNfFnJNuthlj0M02Yww+g23GGHSyzfP55Lou5px0s80Yg262GWPwGWwzxqCTbZ7PJ9d1Meekm23GGHSzzRiDz2CbMQadbPN8Prmuizkn3WwzxqCbbcYYfAbbjDHoZJvn88l1Xcw56WabMQbdbDPG4DPYZozBzzHP8+SnSOL1erHvO29vb3S67xtJHMdBJ9ustdj3nW3b6HTfN5I4joNOkni9Xuz7ztvbG53u+0YSx3HQyTZrLfZ9Z9s2Ot33jSSO46CTJF6vF/u+8/b2Rqf7vpHEcRx0ss1ai33f2baNTvd9I4njOOgkidfrxb7vvL290em+byRxHAedbLPWYt93tm2j033fSOI4DjpJ4vV6se87b29vdLrvG0kcx0En26y12PedbdvodN83kjiOg06SeL1e7PvO29sbne77RhLHcdDJNmst9n1n2zY63feNJI7joJMkXq8X+77z9vZGp/u+kcRxHHSyzVqLfd/Zto1O930jieM46CSJ1+vFvu+8vb3R6b5vJHEcB51ss9Zi33e2baPTfd9I4jgOOkni9Xqx7ztvb290uu8bSRzHQSfbrLXY951t2+h03zeSOI6DTpJ4vV7s+87b2xud7vtGEsdx0Mk2ay32fWfbNjrd940kjuOgkyRerxf7vvP29kan+76RxHEcdLLNWot939m2jU73fSOJ4zjoJInX68W+77y9vdHpvm8kcRwHnWyz1mLfd7Zto9N930jiOA46SeL1erHvO29vb3S67xtJHMdBJ9ustdj3nW3b6HTfN5I4joNOkni9Xuz7ztvbG53u+0YSx3HQyTZrLfZ9Z9s2Ot33jSSO46CTJF6vF/u+8/b2Rqf7vpHEcRx0ss1ai33f2baNTvd9I4njOPg55v+Jn1JVjDHYto05J52qijEGc0462WatxbZtzDnpVFWMMZhz0qmqGGOwbRtzTjpVFWMM5px0ss1ai23bmHPSqaoYYzDnpFNVMcZg2zbmnHSqKsYYzDnpZJu1Ftu2MeekU1UxxmDOSaeqYozBtm3MOelUVYwxmHPSyTZrLbZtY85Jp6pijMGck05VxRiDbduYc9KpqhhjMOekk23WWmzbxpyTTlXFGIM5J52qijEG27Yx56RTVTHGYM5JJ9ustdi2jTknnaqKMQZzTjpVFWMMtm1jzkmnqmKMwZyTTrZZa7FtG3NOOlUVYwzmnHSqKsYYbNvGnJNOVcUYgzknnWyz1mLbNuacdKoqxhjMOelUVYwx2LaNOSedqooxBnNOOtlmrcW2bcw56VRVjDGYc9KpqhhjsG0bc046VRVjDOacdLLNWott25hz0qmqGGMw56RTVTHGYNs25px0qirGGMw56WSbtRbbtjHnpFNVMcZgzkmnqmKMwbZtzDnpVFWMMZhz0sk2ay22bWPOSaeqYozBnJNOVcUYg23bmHPSqaoYYzDnpJNt1lps28ack05VxRiDOSedqooxBtu2MeekU1UxxmDOSSfbrLXYto05J52qijEGc046VRVjDLZtY85Jp6pijMGck062WWuxbRtzTjpVFWMM5pz8HA8iIiIiIiIiIiIivqAHEREREREREREREV/Qg4iIiIiIiIiIiIgv6EFERERERERERETEF/QgIiIiIiIiIiIi4gt6EBEREREREREREfEFPYiIiIiIiIiIiIj4gh5EREREREREREREfEEPIiIiIiIiIiIiIr6gBxERERERERERERFf0IOIiIiIiIiIiIiIL+hBRERERERERERExBf0ICIiIiIiIiIiIuILehARERERERERERHxBT2IiIiIiIiIiIiI+IIeRERERERERERERHxBDyIiIiIiIiIiIiK+oAcRERERERERERERX9CDiIiIiIiIiIiIiC9orrX4KbaxzX3frLXoVFXYZq3FZ7jvm6qiU1Vhm7UWnWxjm/u+WWvRqaqwzVqLz3DfN1VFp6rCNmstOtnGNvd9s9aiU1Vhm7UWn+G+b6qKTlWFbdZadLKNbe77Zq1Fp6rCNmstPsN931QVnaoK26y16GQb29z3zVqLTlWFbdZafIb7vqkqOlUVtllr0ck2trnvm7UWnaoK26y1+Az3fVNVdKoqbLPWopNtbHPfN2stOlUVtllr8Rnu+6aq6FRV2GatRSfb2Oa+b9ZadKoqbLPW4jPc901V0amqsM1ai062sc1936y16FRV2GatxWe475uqolNVYZu1Fp1sY5v7vllr0amqsM1ai89w3zdVRaeqwjZrLTrZxjb3fbPWolNVYZu1Fp/hvm+qik5VhW3WWnSyjW3u+2atRaeqwjZrLT7Dfd9UFZ2qCtustehkG9vc981ai05VhW3WWnyG+76pKjpVFbZZa9HJNra575u1Fp2qCtustfgM931TVXSqKmyz1qKTbWxz3zdrLTpVFbZZa/EZ7vumquhUVdhmrcXPMSXxUyTxQRKS6GQb20iim20kMcagk21sI4lOkvggCUl0so1tJNHNNpIYY9DJNraRRCdJfJCEJDrZxjaS6GYbSYwx6GQb20iikyQ+SEISnWxjG0l0s40kxhh0so1tJNFJEh8kIYlOtrGNJLrZRhJjDDrZxjaS6CSJD5KQRCfb2EYS3WwjiTEGnWxjG0l0ksQHSUiik21sI4lutpHEGINOtrGNJDpJ4oMkJNHJNraRRDfbSGKMQSfb2EYSnSTxQRKS6GQb20iim20kMcagk21sI4lOkvggCUl0so1tJNHNNpIYY9DJNraRRCdJfJCEJDrZxjaS6GYbSYwx6GQb20iikyQ+SEISnWxjG0l0s40kxhh0so1tJNFJEh8kIYlOtrGNJLrZRhJjDDrZxjaS6CSJD5KQRCfb2EYS3WwjiTEGnWxjG0l0ksQHSUiik21sI4lutpHEGINOtrGNJH6OeV0XP6WqeD6fHMfBeZ50Wmshieu66GSb1+vFcRzMOem01kIS13XRqap4Pp8cx8F5nnRaayGJ67roZJvX68VxHMw56bTWQhLXddGpqng+nxzHwXmedFprIYnruuhkm9frxXEczDnptNZCEtd10amqeD6fHMfBeZ50Wmshieu66GSb1+vFcRzMOem01kIS13XRqap4Pp8cx8F5nnRaayGJ67roZJvX68VxHMw56bTWQhLXddGpqng+nxzHwXmedFprIYnruuhkm9frxXEczDnptNZCEtd10amqeD6fHMfBeZ50Wmshieu66GSb1+vFcRzMOem01kIS13XRqap4Pp8cx8F5nnRaayGJ67roZJvX68VxHMw56bTWQhLXddGpqng+nxzHwXmedFprIYnruuhkm9frxXEczDnptNZCEtd10amqeD6fHMfBeZ50Wmshieu66GSb1+vFcRzMOem01kIS13XRqap4Pp8cx8F5nnRaayGJ67roZJvX68VxHMw56bTWQhLXddGpqng+nxzHwXmedFprIYnruuhkm9frxXEczDnptNZCEtd10amqeD6fHMfBeZ50Wmshieu66GSb1+vFcRzMOem01kIS13XRqap4Pp8cx8F5nnRaayGJ67roZJvX68VxHMw56bTWQhLXddGpqng+nxzHwXmedFprIYnruuhkm9frxXEczDnptNZCEtd18XM8iIiIiIiIiIiIiPiCHkRERERERERERER8QQ8iIiIiIiIiIiIivqAHEREREREREREREV/Qg4iIiIiIiIiIiIgv6EFERERERERERETEF/QgIiIiIiIiIiIi4gt6EBEREREREREREfEFPYiIiIiIiIiIiIj4gh5EREREREREREREfEEPIiJsWNcIAAAgAElEQVQiIiIiIiIiIr6gBxERERERERERERFf0CRa/f73v+e3v/0t/1/Y5scff+Tt7Y05J52qCtvMOen2/v7OnJPH40GnqsI2c0462ebHH3/k7e2NOSf/T7/85S/5xS9+wRiDiPhf3+9//3t++9vf8j9imx9//JG3tzfmnHSqKmwz56Tb+/s7c04ejwedqgrbzDnpZJsff/yRt7c35pz8lF/+8pf84he/YIxBREREREREh0m0+cMf/sCvf/1r1lrEn5bjOPjVr37FDz/8QET8r+0Pf/gDv/71r1lrEX9ajuPgV7/6FT/88APx//b73/+e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zJBEjJFSpqamcLtXCIGZmRnMDEnEGCltGAamp6epqoqSzAxJxBgpycxYXV1lenqapml4L9q2xe1Oo9GImZkZrjcMA9PT01RVRUlmhiRijJRkZqyurjI9PU3TNJQUQsDtXqPRiLqumZ6epqoqSjIzJBFj5HaEGCM3k3OmqiqapiHGSEkpJcyMGCMlSWIYBpqmIYRASSklzIwYIzcSQsDtXnVdE2PkdqSUMDNijJQkiWEYaJqGEAIlpZQwM2KM3EoIAbd71XVNjJGdSilhZsQYKUkSwzDQNA0hBEpKKWFmxBi5lRACbveq65oYIzuVUsLMiDFSkiSGYaBpGkIIlJRSwsyIMbITIQTc7lXXNTFGdiKlhJkRY6QkSQzDQNM0hBAoKaWEmRFjpJQQAm73quuaGCMpJcyMGCMlSWIYBpqmIYRASSklzIwYIyXlnKmqiqZpiDHyXoxGI9zuVNc1MUauJYlhGGiahhACJaWUMDNijJSUc6aqKpqmIcZISVVV4Xavuq6ZaJqGEAIlpZQwM2KM3I4a55xzzjnnnHPOOeec24NqnHPOOeecc84555xzbg+qcc4555xzzjnnnHPOuT2oxjnnnHPOOeecc8455/agGuecc84555xzzjnnnNuDapxzzjnnnHPOOeecc24PqnHOOeecc84555xzzrk9qMY555xzzjnnnHPOOef2oBrnnHPOOeecc84555zbg2qcc84555xzzjnnnHNuD6pxzjnnnHPOOeecc865PajGOeecc84555xzzjnn9qAa55xzzjnnnHPOOeec24NqnHPOOeecc84555xzbg+qcc4555xzzjnnnHPOuT2oxjnnnHPOOeecc8455/aggNsTXntjg9N/8CrLVzY5ONvyv/1P/x3/9//zE1750Tpnv3CUwwcizjnnnHPOOeecc87tJTXuA+/80hqP/t4iy1c2cc4555x7P22Y8U///M/5O9//Pq9tbLDt3HjMyZde4tx4jHPu5jbM+Kd//uf8ne9/n9c2NnDug+L82honX3qJs5cvs+382honX3qJs5cv45xzd0qN+8B78f9dZeKphXnOf+khvvmbD/LXPxJ5P5z99mX+zv/+fV57YwPn7rRzL485+Tsvce7lMc7tFedeHnPyd17i/NIazjnnnHPOOefeWUgpcTOSkMQwDKSUKCnnjCRSStwJwzCQc6aknDOS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) + +在python程序中,创建的任何对象都会放在refchain的双向链表中 + +例如: + +```python +name = "小猪佩奇" # 字符串对象 +age = 18 # 整形对象 +hobby = ["吸烟","喝酒","烫头"] # 列表对象 +``` + +这些对象都会放到这些双向链表当中,也就是帮忙维护了python中所有的对象。 +也就是说如果你得到了refchain,也就得到了python程序中的所有对象。 + +### 1.2不同类型对象的存放形式 + +刚刚提到了**所有的对象都存放在环状的双向链表**中,而不同类型的对象存放在双向链表中既有一些**共性特征**也有一些**不同特征**。 + +```python +## name = "小猪佩奇" +## 创建这个对象时,内部会创建一些数据,并且打包在一起 +## 哪些数据:【指向上一个对象的指针、指向下一个对象的指针、类型(这里为字符串)、引用的个数】 + +""" +引用的个数: + + 比如 name = '小猪佩奇' ,会给“小猪佩奇”开辟一个内存空间用来存放到双向链表中。 + 这时候如果有 new = name,不会创建两个“小猪佩奇”,而是将new指向之前的那个小猪佩奇, + 而引用的个数变为2,也就是"小猪佩奇"这个对象被引用了两次。 +""" +``` + +* **相同点**:刚刚讲到的四个种数据每个对象都包含有。 + +```python +## 内部会创建一些数据,【指向上一个对象的指针、指向下一个对象的指针、类型、引用的个数】 +age = 18 # 整形对象 + +## 内部会创建一些数据,【指向上一个对象的指针、指向下一个对象的指针、类型、引用的个数】 +hobby = ["吸烟","喝酒","烫头"] # 列表对象 +``` + +* **不同点**: + 不同的数据类型还会创建不同的值: + +```python +## 内部会创建一些数据,【指向上一个对象的指针、指向下一个对象的指针、类型、引用的个数、val=18】 +age = 18 # 整形对象 + +## 内部会创建一些数据,【指向上一个对象的指针、指向下一个对象的指针、类型、引用的个数、items=元素、元素的个数】 +hobby = ["抽烟","喝酒","烫头"] # 列表对象 +``` + +所以在python中创建的对象会加到环形双向链表中,但是每一种类型的数据对象在存到链表中时,所存放的数据个数可能是不同的(有相同点有不同点)。 + +#### 两个重要的结构体 + +Python解释器由c语言开发完成,py中所有的操作最终都由底层的c语言来实现并完成,所以想要了解底层内存管理需要结合python源码来进行解释。 + +```c +##define PyObject_HEAD PyObject ob_base ; +##define PyObject_VAR_HEAD PyVarObject ob_base; + +//宏定义,包含上一个、下一个,用于构造双向链表用。(放到refchain链表中时,要用到) +##define _PyObject_HEAD_EXTRA \ + struct _object *_ob_next; \ + struct _object *_ob_prev; + +typedef struct _object { + _PyObject_HEAD_EXTRA //用于构造双向链表 + Py_ssize_t ob_refcnt; //引用计数器 + struct _typeobject *ob_type; //数据类型 +} PyObject; + +typedef struct { + PyObject ob_base; // PyObject对象 + Py_ssize_t ob_size; /* Number of items in variable part, 即:元素个数*/ +} PyVarObject; +``` + +在C源码中如何体现每个对象中都有的相同的值:PyObject结构体(4个值:_ob_next、_ob_prev、ob_refcnt、*ob_type) +9-13行 定义了一个结构体,第10行实际上就是6,7两行,用来存放前一个对象,和后一个对象的位置。 + +这个结构体可以存贮四个值(**这四个值是对象都具有的**)。 + +在C源码中如何体现由多个元素组成的对象:PyObject + ob_size(元素个数) + +15-18行又定义了一个结构体,第16行相当于代指了9-13行中的四个数据。 + +而17行又多了一个数据字段,叫做元素个数,这个结构体。 + +以上源码是Python内存管理中的基石,其中包含了: + +* 2个结构体 +* **PyObject**,此结构体中包含3个元素。 + * PyObject_HEAD_EXTRA,用于构造双向链表。 + * ob_refcnt,引用计数器。 + * *ob_type,数据类型。 +* **PyVarObject**,次结构体中包含4个元素(ob_base中包含3个元素) + * ob_base,PyObject结构体对象,即:包含PyObject结构体中的三个元素。 + * ob_size,内部元素个数。 + +#### 类型封装的结构体 + +在我们了解了这两个结构体,现在我们来看看每一个数据类型都封装了哪些值: + +* flaot类型 + float结构体: + +```c +typedef struct { + PyObject_HEAD # 这里相当于代表基础的4个值 + double ob_fval; +} PyFloatObject; +``` + +例: + +```c +data = 3.14 + +内部会创建: + _ob_next = refchain中的上一个对象 + _ob_prev = refchain中的后一个对象 + ob_refcnt = 1 引用个数 + ob_type= float 数据类型 + ob_fval = 3.14 +``` + +* int类型 + int结构体: + +```c +struct _longobject { + PyObject_VAR_HEAD + digit ob_digit[1]; +}; + +// longobject.h + +/* Long (arbitrary precision) integer object interface */ +typedef struct _longobject PyLongObject; /* Revealed in longintrepr.h */ +``` + +道理都是相同的,第2行代指第二个重要的结构体,第三行是int形特有的值,总结下来就是这个结构体中有几个值,那么创建这个类型对象的时候内部就会创建几个值。 + +* list类型 + list结构体: + +```c +typedef struct { + PyObject_VAR_HEAD + + /* Vector of pointers to list elements. list[0] is ob_item[0], etc. */ + PyObject **ob_item; + + /* ob_item contains space for 'allocated' elements. The number + * currently in use is ob_size. + * Invariants: + * 0 <= ob_size <= allocated + * len(list) == ob_size + * ob_item == NULL implies ob_size == allocated == 0 + * list.sort() temporarily sets allocated to -1 to detect mutations. + * + * Items must normally not be NULL, except during construction when + * the list is not yet visible outside the function that builds it. + */ + Py_ssize_t allocated; +} PyListObject; +``` + +* tuple类型 + tuple结构体: + +```c +typedef struct { + PyObject_VAR_HEAD + PyObject *ob_item[1]; + + /* ob_item contains space for 'ob_size' elements. + * Items must normally not be NULL, except during construction when + * the tuple is not yet visible outside the function that builds it. + */ +} PyTupleObject; +``` + +* dict类型 + dict结构体: + +```c +typedef struct { + PyObject_HEAD + Py_ssize_t ma_used; + PyDictKeysObject *ma_keys; + PyObject **ma_values; +} PyDictObject; +``` + +到这里我们就学到了什么是环状双向链表,以及双向链表中存放的每一种数据类型的对象都是怎样的。 + +### 1.3引用计数器 + +```python +v1 = 3.14 +v2 = 999 +v3 = (1,2,3) +``` + +当python程序运行时,会根据数据类型的不同,找到其对应的结构体,根据结构体中的字段,来进行创建相关的数据,然后将对象添加到refchain双向链表中。 +为了体现我们看过源码的牛逼之处,我们还可以进一步理解。 + +在C源码中有两个关键的结构体:PyObject、PyvarObject + +* PyObject(存储是上一个对象,下一个对象,类型,引用的个数,是每一个对象都具有的)。 +* PyvarObject(存储的是由多个元素组成的类型数据具有的值,例如字符串,int)。 + +- \1. python3中没有long类型,只有int类型,但py3内部的int是基于long实现。 + +* * \2. python3中对int长度没有限制,其内部使用由多个元素组成的类似于“字符串”的机制来存储的。 + 每个对象中都有ob_refcnt ,它就是引用计数器,创建时默认是1,当有其他变量重新引用的时候,引用计数器就会发生变化。 + +#### 计数器增加 + +当发生以下四种情况的时候,该对象的引用**计数器+1**:** + +```python +a=14 # 对象被创建   +b=a # 对象被引用  +func(a) # 对象被作为参数,传到函数中 +List=[a,"a","b",2] # 对象作为一个元素,存储在容器中   +b = 9999 # 引用计数器的值为1 +c = b # 引用计数器的值为2 +``` + +#### 计数器减小 + +当发生以下四种情况时,该对象的引用计数器**-1** + +```python +当该对象的别名被显式销毁时  del a +当该对象的引别名被赋予新的对象,   a=26 +一个对象离开它的作用域,例如 func函数执行完毕时,函数里面的局部变量的引用计数器就会减一(但是全局变量不会) +将该元素从容器中删除时,或者容器被销毁时。 +a = 999 +b = a # 当前计数器为2 +del b # 删除变量b:b对应的对象的引用计数器-1 (此时计数器为1) +del a # 删除变量a:a对应的对象的引用计数器-1 (此时引用计数器为0) + +当引用计数器为0 时,意味着没有人再使用这个对象,这个对象就变成垃圾,垃圾回收。 +回收:1.对象从refchain的链表移除。 + 2.将对象进行销毁,内存归还给操作系统,可用内存就增加。 +``` + +**当引用计数器**为0 时,意味着没有人再使用这个对象,这个对象就变成垃圾,垃圾回收。 +**回收:1.对象从refchain的链表移除。** + **2.将对象进行销毁,内存归还给操作系统,可用内存就增加**。 + +以上就是引用计数器大体上的机制,但是后面的缓存机制学习完之后我们才会进一步理解,这里不是简单的说计数器等于0就销毁,内部还有一定的缓冲,目前就简单理解成计数器为0,我们就进行垃圾回收。 + +#### 例子 + +```python +a = "雷霆嘎巴" # 创建对象并初始话引用计数器为1 +b = a # 计数器发生变化 +c = a +d = a +e = a + +f = "小猪佩奇" # 创建对象并初始话引用计数器为1 +``` + +![图片](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABV4AAAHxCAYAAACVuKejAAAgAElEQVR4AezBYYyd5Z3f/e91fJ+Z62ZwZoyzXuwAyQhvMglu6jAQ7xOaDJLVYj8KOwuNlC55EbdVZl+sDm6kJvtia7OMZVVK2ma9o7aKaSVbSatNpXU6Mq0dVVEzm4BCtIMgdcCiIK8cYhN2goczHnyuzH39f09vVdPO+rHBhnsSDP/PJ+h/4X/JOTM3N8fg4CAxRpqUUsLMKMuSJklicXGRGCNFUdCklBJmRlmWNCnnzNzcHIODg8QYaVJKCTOjLEuaJInFxUVijBRFQZNSSpgZZVnSpJwzc3NzDA4OEmOkSSklzIyyLGmSJBYXF4kxUhQFTUopYWaUZUmTcs7Mzc0xODhIjJEmpZQwM8qypEmSWFxcJMZIURQ0KaWEmVGWJU3KOTM3N8fg4CAxRpqUUsLMKMuSJklicXGRGCNFUdCklBJmRlmWNCnnzNzcHIODg8QYaVJKCTOjLEuaJInFxUVijBRFQZNSSpgZZVnSpJwzc3NzDA4OEmOkSSklzIyyLGmSJBYXF4kxUhQFTUopYWaUZUmTcs7Mzc0xODhIjJEmpZQwM8qypEmSWFxcJMZIURQ0KaWEmVGWJU3KOTM3N8fg4CAxRpqUUsLMKMuSJklicXGRGCNFUdCklBJmRlmWNCnnzNzcHIODg8QYaVJKCTOjLEuaJInFxUVijBRFQZNSSpgZZVnSpJwzc3NzDA4OEmOkSSklzIyyLGmSJBYXF4kxUhQFTUopYWaUZUmTcs7Mzc0xODhIjJEmpZQwM8qypEmSWFxcJMZIURQ0KaWEmVGWJU3KOTM3N8fg4CAxRpqUUsLMKMuSJklicXGRGCNFUdCklBJmRlmWNCnnzNzcHIODg8QYaVJKCTOjLEuaJInFxUVijBRFQZNSSpgZZVnSpJwzc3NzDA4OEmOkSSklzIyyLGmSJBYXF4kxUhQFTUopYWaUZUmTcs7Mzc0xODhIjJGmtHDOOeecc84555xzzjnXqBbOOeecc84555xzzjnnGtXCOeecc84555xzzjnnXKNaOOecc84555xzzjnnnGtUC+ecc84555xzzjnnnHONauGcc84555xzzjnnnHOuUS2cc84555xzzjnnnHPONaqFc84555xzzjnnnHPOuUa1cM4555xzzjnnnHPOOdeoFs4555xzzjnnnHPOOeca1cI555xzzjnnnHPOOedcowqcu8aYGT/4wQ+YnZ3lcsyMCxcu0N/fT1EUNCnnjCSKoqBJklhaWqIoClqtFk3KOSOJoihokplx4cIF+vv7KYqCJuWckURRFDRJEktLSxRFQavV4mKf/OQnuf3222m1Wjjn3t7MjB/84AfMzs5SyzkjiaIoaJIklpaWKIqCVqtFk3LOSKIoCppkZly4cIH+/n6KoqBJOWckURQFTZLE0tISRVHQarVoUs4ZSRRFwZX65Cc/ye23306r1cI59+tnZvzgBz9gdnaWZZJYWlqiKAparRZNyjkjiaIoaJKZceHCBfr7+ymKgiblnJFEURQ0SRJLS0sURUGr1aJJOWckURQFTTIzLly4QH9/P0VR8EY++clPcvvtt9NqtXDOuSYVOHeNefLJJ/nyl7/M0tISzjXtW9/6Fl/5ylf41Kc+hXPu7e3JJ5/ky1/+MktLSzjXtG9961t85Stf4VOf+hTOuV+/J598ki9/+cssLS3hXNO+9a1v8ZWvfIVPfepTOOdck1o4d435/ve/z9LSEs6thqWlJWZnZ3HOvf19//vfZ2lpCedWw9LSErOzszjn3h6+//3vs7S0hHOrYWlpidnZWZxzrmkFzl3D7r//I1x3XRvn3qrXXlviyJFncM5dm+6//yNcd10b596q115b4siRZ3DOvX3df/9HuO66Ns69Va+9tsSRI8/gnHOrpcC5a9h117X54hd/G+feqq997Yc4565d113X5otf/G2ce6u+9rUf4px7e7vuujZf/OJv49xb9bWv/RDnnFtNLZxzzjnnnHPOOeecc841qoVzzjnnnHPOOeecc865RhUpJWqSkERVVaSUaFLOGUmklFgNVVWRc6ZJOWckkVKiSZKQRFVVpJRoUs4ZSaSUWA1VVZFzpkk5ZySRUuJK5ZxxbjXlnEkpcbVyzkgipUSTJCGJqqpIKdGknDOSSCmxGqqqIudMk3LOSCKlRJMkIYmqqkgp0aScM5JIKbEaqqoi50yTcs5IIqVEkyQhiaqqSCnxVuSccW415ZxJKXE5kpBEVVWklGhSzhlJpJRYDVVVkXOmSTlnJJFSokmSkERVVaSUaFLOGUmklFgNVVWRc6ZJOWckkVKiSZKQRFVVpJRoUs4ZSaSUeLNyzji3mnLOpJR4IzlnJJFSYjVUVUXOmSblnJFESokmSUISVVWRUqJJOWckkVJiNVRVRc6ZJuWckURKiSZJQhJVVZFSokk5ZySRUmI1VFVFzpkm5ZyRREqJJklCElVVkVKiKYWZUTMzamaGmdEkSUjCzGiaJMyMEAJNkoQkzIwmmRk1M8PMaJIkJGFmNE0SZkYIgSZJQhJmxpWShHOrSRJmxtWShCTMjCaZGTUzw8xokiQkYWY0TRJmRgiBJklCEmZGk8yMmplhZjRJEpIwM5omCTMjhECTJCEJM6NJZkbNzDAz3gpJOLeaJGFmXI6ZUTMzzIwmSUISZkbTJGFmhBBokiQkYWY0ycyomRlmRpMkIQkzo2mSMDNCCDRJEpIwM5pkZtTMDDOjSZKQhJnxZknCudUkCTPjjUhCEmZG0yRhZoQQaJIkJGFmNMnMqJkZZkaTJCEJM6NpkjAzQgg0SRKSMDOaZGbUzAwzo0mSkISZ0TRJmBkhBJokCUmYGU0yM2pmhpnRlKIsS2o5Z86fP09fXx8xRpqUUsLMKMuSJklicXGRvr4+iqKgSSklzIyyLGlSzpnz58/T19dHjJEmpZQwM8qypEmSWFxcpK+vj6IoaFJKCTOjLEuuVFEUOLeaiqKgLEuuVkoJM6MsS5qUc+b8+fP09fURY6RJKSXMjLIsaZIkFhcX6evroygKmpRSwswoy5Im5Zw5f/48fX19xBhpUkoJM6MsS5okicXFRfr6+iiKgiallDAzyrKkSTlnzp8/T19fHzFG3oqiKHBuNRVFQVmWXE7OmfPnz9PX10eMkSallDAzyrKkSZJYXFykr6+PoihoUkoJM6MsS5qUc+b8+fP09fURY6RJKSXMjLIsaZIkFhcX6evroygKmpRSwswoy5Im5Zw5f/48fX19xBhpUkoJM6MsS96soihwbjUVRUFZlryRlBJmRlmWNEkSi4uL9PX1URQFTUopYWaUZUmTcs6cP3+evr4+Yow0KaWEmVGWJU2SxOLiIn19fRRFQZNSSpgZZVnSpJwz58+fp6+vjxgjTUopYWaUZUmTJLG4uEhfXx9FUdCklBJmRlmWNCnnzPnz5+nr6yPGSFNaOOecc84555xzzjnnnGtUC+ecc84555xzzjnnnHONauGcc84555xzzjnnnHOuUS2cc84555xzzjnnnHPONaqFc84555xzzjnnnHPOuUa1cM4555z7Fcg5k3PGOeecc845594NWjjnnHPO/Qq8+uqr/JN/8k/4L//lvzA/P09KCeecc84555x7pypwzjnnnPsV+au/+iueeOIJDh06xPvf/35GR0fZsWMHIyMjOOece+eoqoqiKHDOOefezQqcc845537FFhcXeeaZZ3jmmWf4xje+wQc/+EHuuece7rzzTm655RbWrl2Lc865a9eZM2f4F//iX/DAAw+wefNmYow455xz7zYFzjnnnHO/Zs899xzPPfccfX19rF27lrvvvpvf+73fY3h4GOecc9eenDOPPfYYjz/+OO9973sZHh7m7rvv5p577mFoaAjnnHPu3aDAOeecc+5t4pe//CW/+MUv+PM//3P+83/+z9x66618/OMf54477uD2229nYGAA55xz1w5J/PVf/zV//dd/zY9+9CP+5b/8l9x11138vb/39xgZGeHmm2+mKAqcc865d6IC55xzf8Ozzz7LN77xDWqtVotaq9WiFkKg1mq1qIUQqIUQyDlTa7fbhBAIIRBCIIRALYRACIEQAiEEaiEEQgiEEAghUAshEEIghEBNEgsLCwwMDNDX10cIgVqr1aIWQiCEQC2EQAiBEAK1EAIhBEIIhBCohRAIIRBCYGlpCUn09/fTarWotVotloUQCCEQQqAWQiCEQAiBEAK1EAIhBEII1EII1Hq9Hv39/RRFQQiBEAIhBGohBGqtVotaCIFaCIEQAiuFEFjpl7/8JWZGjJGLhRC4WiEEajln5ufnMTP6+/u5lBACVyqEwLKUEpJIKfF6QghcqRACknjttdf45S9/SVEUvJ4QAlcqhEBKCTMj58wbCSFwJS5cuIAkrlTOmeeee47nnnuOb37zm6xZs4bf+Z3f4XOf+xwbNmxAEs45564tOWf+4i/+gr/4i7/guuuuY2hoiM9+9rP87u/+Ltdffz3OOefcO0mBc865v2F2dpbZ2Vncr1cIgZVCCKwUQmClEAIXCyGwLITASiEEVgohIIkQArUQAiuFEFgphMBKIQRWCiFwsRACy0IIrBRCYFkIgZVCCKwUQmCZJEIIhBBYFkLgYiEEloUQWCmEwEohBCRRCyEQQuBiIQRqIQRWCiFwsRACNTPjF7/4BW9Wzplvf/vbfPvb3+bmm29GEs45565dr732Gq+99hpf+9rX+Lf/9t+ydetW7rzzTu68804+9KEPURQFzjnn3LWswDnnnHsb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E9/61rf4XOu6siwL9/udTK015pzcbjfcnUzrurIsC/f7nUySiAhutxutNTKt68qyLNzvdzK11phzcrvdcHcyrevKsizc73cySSIiuN1utNbItK4ry7Jwv9/J1FpjzsntdsPdybSuK8uycL/fySSJiOB2u9FaI9O6rizLwv1+J1NrjTknt9sNdyfTuq4sy8L9fieTJCKC2+1Ga41M67qyLAv3+51MrTXmnNxuN9ydTOu6siwL9/udTJKICG63G601Mq3ryrIs3O93MrXWmHNyu91wdzKt68qyLNzvdzJJIiK43W601si0rivLsnC/38nUWmPOye12w93JtK4ry7Jwv9/JJImI4Ha70Voj07quLMvC/X4nU2uNOSe32w13J9O6rizLwv1+5zt99atf5enpif/Nn/zJn/ALv/AL/E8kERHcbjdaa2Ra15VlWbjf72RqrTHn5HajwPrjAAAgAElEQVS74e58rnfv3hERfPStb32LT63ryrIs3O93MkkiIrjdbrTWyLSuK8uycL/fydRaY87J7XbD3cm0rivLsnC/38kkiYjgdrvRWiPTuq4sy8L9fidTa405J7fbDXcn07quLMvC/X4nkyQigtvtRmuNTOu6siwL9/udTK015pzcbjfcnUzrurIsC/f7nUySiAhutxutNbKMt2/f8iIiuN1uXK9X1nUlU0QgiTkn2c7z5Hq90lojU0QgiTknmSKC2+3G9XplXVcyRQSSmHOS7TxPrtcrrTUyRQSSmHOSKSK43W5cr1fWdSVTRCCJOScv/vqv/5rv5e/+7u/4zd/8Tb6X8zy5Xq+01sgUEUhizkmmiOB2u3G9XlnXlU9dLhc+2raNt2/f8rkiAknMOcl2nifX65XWGpkiAknMOckUEdxuN67XK+u6kikikMSck2zneXK9XmmtkSkikMSck0wRwe1243q9sq4rmSICScw5yXaeJ9frldYamSICScw5yRQR3G43rtcr67qSKSKQxJyTbOd5cr1eaa2RKSKQxJyTTBHB7Xbjer2yriuZIgJJzDnJdp4n1+uV1hqZIgJJzDnJFBHcbjeu1yvrupIpIpDEnJNs53lyvV5prZEpIpDEnJNMEcHtduN6vbKuK5kiAknMOcl2nifX65XWGpkiAknMOckUEdxuN67XK+u6kikikMSck2zneXK9XmmtkSkikMSck+/0T//0T7g7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U8k2e2/WWpznSaWIQBL3fVMpMxljsNbivm8qRQSSuO+bSrbZe7PW4jxPKkUEkrjvm0qZyRiDtRb3fVMpIpDEfd9Uss3em7UW53lSKSKQxH3fVMpMxhistbjvm0oRgSTu+6aSbfberLU4z5NKEYEk7vumUmYyxmCtxX3fVIoIJHHfN5Vss/dmrcV5nlSKCCRx3zeVMpMxBmst7vumUkQgifu+qWSbvTdrLc7zpFJEIIn7vqmUmYwxWGtx3zeVIgJJ3PdNJdvsvVlrcZ4nlSICSdz3TaXMZIzBWov7vqkUEUjivm8q2WbvzVqL8zypFBFI4r5vKmUmYwzWWtz3TaWIQBL3fVPJNntv1lqc50mliEAS931TKTMZY7DW4r5vKkUEkrjvm0q22Xuz1uI8TypFBJK475tKmckYg7UW931TKSKQxH3fVLLN3pu1Fud5UikikMR931TKTMYYrLW475tKEYEk7vumkm323qy1OM+TShGBJO77plJmMsZgrcV931Q5aK211lprrbXWWmuttVbqoLXWWmuttdZaa6211lqpg9Zaa6211lprrbXWWmulDlprrbXWWmuttdZaa62VOmittdZaa6211lprrbVW6qC11lprrbXWWmuttdZaqYPWWmuttdZaa6211lprpQ5aa6211lprrbXWWmutlTporbXWWmuttdZaa621VuqgtdZaa6211lprrbXWWqmD1lprrbXWWmuttdZaa6UOWmuttdZaa6211lprrZU6aK211lprrbXWWmuttVbqoLXWWmuttdZaa6211lqpg9Zaa6211lprrbXWWmulDlprrbXWWmuttdZaa62VOmittdZaa6211lprrbVW6qC11lprrbXWWmuttdZaqYPWWmuttdZaa6211lprpc6I4Ms2ttl7ExFUykxsExH8hb03mUmlzMQ2EUEl29hm701EUCkzsU1E8Bf23mQmlTIT20QElWxjm703EUGlzMQ2EcFf2HuTmVTKTGwTEVSyjW323kQElTIT20QEf2HvTWZSKTOxTURQyTa22XsTEVTKTGwTEfyFvTeZSaXMxDYRQSXb2GbvTURQKTOxTUTwF/beZCaVMhPbRASVbGObvTcRQaXMxDYRwV/Ye5OZVMpMbBMRVLKNbfbeRASVMhPbRAR/Ye9NZlIpM7FNRFDJNrbZexMRVMpMbBMR/IW9N5lJpczENhFBJdvYZu9NRFApM7FNRPAX9t5kJpUyE9tEBJVsY5u9NxFBpczENhHBX9h7k5lUykxsExFUso1t9t5EBJUyE9tEBH9h701mUikzsU1EUMk2ttl7ExFUykxsExH8hb03mUmlzMQ2EUEl29hm701EUCkzsU1E8Bf23mQmlTIT20QElWxjm703EUGlzMQ2EcFf2HuTmVTKTGwTEVSyjW323kQEVU5JfEniSxKSqGQb20iimm0kMcagkm1sI4lKkviShCQq2cY2kqhmG0mMMahkG9tIopIkviQhiUq2sY0kqtlGEmMMKtnGNpKoJIkvSUiikm1sI4lqtpHEGINKtrGNJCpJ4ksSkqhkG9tIopptJDHGoJJtbCOJSpL4koQkKtnGNpKoZhtJjDGoZBvbSKKSJL4kIYlKtrGNJKrZRhJjDCrZxjaSqCSJL0lIopJtbCOJaraRxBiDSraxjSQqSeJLEpKoZBvbSKKabSQxxqCSbWwjiUqS+JKEJCrZxjaSqGYbSYwxqGQb20iikiS+JCGJSraxjSSq2UYSYwwq2cY2kqgkiS9JSKKSbWwjiWq2kcQYg0q2sY0kKkniSxKSqGQb20iimm0kMcagkm1sI4lKkviShCQq2cY2kqhmG0mMMahkG9tIopIkviQhiUq2sY0kqtlGEmMMKtnGNpKoJIkvSUiiyvk8D1+Zyfv95rou7vumUkQgied5qGSbz+fDdV2c50mliEASz/NQKTN5v99c18V931SKCCTxPA+VbPP5fLiui/M8qRQRSOJ5HiplJu/3m+u6uO+bShGBJJ7noZJtPp8P13VxnieVIgJJPM9Dpczk/X5zXRf3fVMpIpDE8zxUss3n8+G6Ls7zpFJEIInneaiUmbzfb67r4r5vKkUEknieh0q2+Xw+XNfFeZ5Uiggk8TwPlTKT9/vNdV3c902liEASz/NQyTafz4frujjPk0oRgSSe56FSZvJ+v7mui/u+qRQRSOJ5HirZ5vP5cF0X53lSKSKQxPM8VMpM3u8313Vx3zeVIgJJPM9DJdt8Ph+u6+I8TypFBJJ4nodKmcn7/ea6Lu77plJEIInneahkm8/nw3VdnOdJpYhAEs/zUCkzeb/fXNfFfd9Uiggk8TwPlWzz+Xy4rovzPKkUEUjieR4qZSbv95vrurjvm0oRgSSe56GSbT6fD9d1cZ4nlSICSTzPQ6XM5P1+c10X931TKSKQxPM8VLLN5/Phui7O86RSRCCJ53molJm832+u6+K+bypFBJJ4nodKtvl8PlzXxXmeVIoIJPE8D5Uyk/f7zXVd3PdNpYhAEs/zUMk2n8+H67o4z5NKEYEknuehUmbyfr+5rov7vqkUEUjieR4q2ebz+XBdF+d5UikikMTzPFTKTN7vN9d1cd83VQ5aa6211lprrbXWWmutlTporbXWWmuttdZaa621VuqgtdZaa6211lprrbXWWqmD1lprrbXWWmuttdZaa6UOWmuttdZaa6211lprrZU6aK211lprrbXWWmuttVbqoLXWWmuttdZaa6211lqpg9Zaa6211lprrbXWWmulDlprrbXWWmuttdZaa62VOmittdZaa6211lprrbVW6qC11lprrbXWWmuttdZaqYPWWmuttdZaa6211lprpQ5aa6211lprrbXWWmutlTporbXWWmuttdZaa621VuqgtdZaa6211lprrbXWWqmD1lprrbXWWmuttdZaa6UOWmuttdZaa6211lprrZU6aK211lprrbXWWmuttVbqoLXWWmuttdZaa6211lqp0zZftvmyjW3+gm0qSeLLNrb5C7apZJsv29jmL9imkiS+bGObv2CbSrb5so1t/oJtKkniyza2+Qu2qWSbL9vY5i/YppIkvmxjm79gm0q2+bKNbf6CbSpJ4ss2tvkLtqlkmy/b2OYv2KaSJL5sY5u/YJtKtvmyjW3+gm0qSeLLNrb5C7apZJsv29jmL9imkiS+bGObv2CbSrb5so1t/oJtKkniyza2+Qu2qWSbL9vY5i/YppIkvmxjm79gm0q2+bKNbf6CbSpJ4ss2tvkLtqlkmy/b2OYv2KaSJL5sY5u/YJtKtvmyjW3+gm0qSeLLNrb5C7apZJsv29jmL9imkiS+bGObv2CbSrb5so1t/oJtKkniyza2+Qu2qWSbL9vYpsr4v//7P/M/tnm/3zzPw3meVLPNGINqthlj8BdsM8agkm3e7zfP83CeJ9VsM8agmm3GGPwF24wxqGSb9/vN8zyc50k124wxqGabMQZ/wTZjDCrZ5v1+8zwP53lSzTZjDKrZZozBX7DNGINKtnm/3zzPw3meVLPNGINqthlj8BdsM8agkm3e7zfP83CeJ9VsM8agmm3GGPwF24wxqGSb9/vN8zyc50k124wxqGabMQZ/wTZjDCrZ5v1+8zwP53lSzTZjDKrZZozBX7DNGINKtnm/3zzPw3meVLPNGINqthlj8BdsM8agkm3e7zfP83CeJ9VsM8agmm3GGPwF24wxqGSb9/vN8zyc50k124wxqGabMQZ/wTZjDCrZ5v1+8zwP53lSzTZjDKrZZozBX7DNGINKtnm/3zzPw3meVLPNGINqthlj8BdsM8agkm3e7zfP83CeJ9VsM8agmm3GGPwF24wxqGSb9/vN8zyc50k124wxqGabMQZ/wTZjDCrZ5v1+8zwP53lS5bzvmy9JfD4f1lr8+/ePSntvJHFdF5VsExGstZhzUmnvjSSu66KSJD6fD2st/v37R6W9N5K4rotKtokI1lrMOam090YS13VRSRKfz4e1Fv/+/aPS3htJXNdFJdtEBGst5pxU2nsjieu6qCSJz+fDWot///5Rae+NJK7ropJtIoK1FnNOKu29kcR1XVSSxOfzYa3Fv3//qLT3RhLXdVHJNhHBWos5J5X23kjiui4qSeLz+bDW4t+/f1TaeyOJ67qoZJuIYK3FnJNKe28kcV0XlSTx+XxYa/Hv3z8q7b2RxHVdVLJNRLDWYs5Jpb03kriui0qS+Hw+rLX49+8flfbeSOK6LirZJiJYazHnpNLeG0lc10UlSXw+H9Za/Pv3j0p7byRxXReVbBMRrLWYc1Jp740kruuikiQ+nw9rLf79+0elvTeSuK6LSraJCNZazDmptPdGEtd1UUkSn8+HtRb//v2j0t4bSVzXRSXbRARrLeacVNp7I4nruqgkic/nw1qLf//+UWnvjSSu66KSbSKCtRZzTirtvZHEdV1UksTn82Gtxb9//6i090YS13VRyTYRwVqLOSeV9t5I4rouKkni8/mw1uLfv39U2nsjieu6qGSbiGCtxZyTSntvJHFdF5Uk8fl8WGvx798/Ku29kcR1XVSyTUSw1mLOSaW9N5K4rotKkvh8Pqy1+PfvH1XO/+ErMxljMOfkPE8qZSZjDM7zpJJtIoI5J+d5UikzGWNwnieVMpMxBnNOzvOkUmYyxuA8TyrZJiKYc3KeJ5UykzEG53lSKTMZYzDn5DxPKmUmYwzO86SSbSKCOSfneVIpMxljcJ4nlTKTMQZzTs7zpFJmMsbgPE8q2SYimHNynieVMpMxBud5UikzGWMw5+Q8TyplJmMMzvOkkm0igjkn53lSKTMZY3CeJ5UykzEGc07O86RSZjLG4DxPKtkmIphzcp4nlTKTMQbneVIpMxljMOfkPE8qZSZjDM7zpJJtIoI5J+d5UikzGWNwnieVMpMxBnNOzvOkUmYyxuA8TyrZJiKYc3KeJ5UykzEG53lSKTMZYzDn5DxPKmUmYwzO86SSbSKCOSfneVIpMxljcJ4nlTKTMQZzTs7zpFJmMsbgPE8q2SYimHNynieVMpMxBud5UikzGWMw5+Q8TyplJmMMzvOkkm0igjkn53lSKTMZY3CeJ5UykzEGc07O86RSZjLG4DxPKtkmIphzcp4nlTKTMQbneVIpMxljMOfkPE8qZSZjDM7zpJJtIoI5J+d5UikzGWNwnieVMpMxBnNOzvOkUmYyxuA8TyrZJiKYc3KeJ5UykzEG53lSKTMZYzDn5DxPKmUmYwzO86SSbSKCOSfneVIpMxljcJ4nlTKTMQZzTs7zpMpBa6211lprrbXWWmuttVIHrbXWWmuttdZaa6211kodtNZaa6211lprrbXWWit10FprrbXWWmuttdZaa63UQWuttdZaa6211lprrbVSB6211lprrbXWWmuttdZKHbTWWmuttdZaa6211lorddBaa6211lprrbXWWmut1EFrrbXWWmuttdZaa621UgettdZaa6211lprrbXWSh201lprrbXWWmuttdZaK3XQWmuttdZaa6211lprrdRBa6211lprrbXWWmuttVIHrbXWWmuttdZaa6211kodtNZaa6211lprrbXWWit10FprrbXWWmuttdZaa63UQWuttdZaa6211lprrbVSB6211lprrbXWWmuttdZKHbTWWmuttdZaa6211lordUYEX7axzd6biKBSZmKbiOAv7L3JTCplJraJCCrZxjZ7byKCSpmJbSKCv7D3JjOplJnYJiKoZBvb7L2JCCplJraJCP7C3pvMpFJmYpuIoJJtbLP3JiKolJnYJiL4C3tvMpNKmYltIoJKtrHN3puIoFJmYpuI4C/svclMKmUmtokIKtnGNntvIoJKmYltIoK/sPcmM6mUmdgmIqhkG9vsvYkIKmUmtokI/sLem8ykUmZim4igkm1ss/cmIqiUmdgmIvgLe28yk0qZiW0igkq2sc3em4igUmZim4jgL+y9yUwqZSa2iQgq2cY2e28igkqZiW0igr+w9yYzqZSZ2CYiqGQb2+y9iQgqZSa2iQj+wt6bzKRSZmKbiKCSbWyz9yYiqJSZ2CYi+At7bzKTSpmJbSKCSraxzd6biKBSZmKbiOAv7L3JTCplJraJCCrZxjZ7byKCSpmJbSKCv7D3JjOplJnYJiKoZBvb7L2JCCplJraJCP7C3pvMpFJmYpuIoJJtbLP3JiKockriSxJfkpBEJdvYRhLVbCOJMQaVbGMbSVSSxJckJFHJNraRRDXbSGKMQSXb2EYSlSTxJQlJVLKNbSRRzTaSGGNQyTa2kUQlSXxJQhKVbGMbSVSzjSTGGFSyjW0kUUkSX5KQRCXb2EYS1WwjiTEGlWxjG0lUksSXJCRRyTa2kUQ120hijEEl29hGEpUk8SUJSVSyjW0kUc02khhjUMk2tpFEJUl8SUISlWxjG0lUs40kxhhUso1tJFFJEl+SkEQl29hGEtVsI4kxBpVsYxtJVJLElyQkUck2tpFENdtIYoxBJdvYRhKVJPElCUlUso1tJFHNNpIYY1DJNraRRCVJfElCEpVsYxtJVLONJMYYVLKNbSRRSRJfkpBEJdvYRhLVbCOJMQaVbGMbSVSSxJckJFHJNraRRDXbSGKMQSXb2EYSlSTxJQlJVLKNbSRRzTaSGGNQyTa2kUQlSXxJQhJVzud5+MpM3u8313Vx3zeVIgJJPM9DJdt8Ph+u6+I8TypFBJJ4nodKmcn7/ea6Lu77plJEIInneahkm8/nw3VdnOdJpYhAEs/zUCkzeb/fXNfFfd9Uiggk8TwPlWzz+Xy4rovzPKkUEUjieR4qZSbv95vrurjvm0oRgSSe56GSbT6fD9d1cZ4nlSICSTzPQ6XM5P1+c10X931TKSKQxPM8VLLN5/Phui7O86RSRCCJ53molJm832+u6+K+bypFBJJ4nodKtvl8PlzXxXmeVIoIJPE8D5Uyk/f7zXVd3PdNpYhAEs/zUMk2n8+H67o4z5NKEYEknuehUmbyfr+5rov7vqkUEUjieR4q2ebz+XBdF+d5UikikMTzPFTKTN7vN9d1cd83lSICSTzPQyXbfD4fruviPE8qRQSSeJ6HSpnJ+/3mui7u+6ZSRCCJ53moZJvP58N1XZznSaWIQBLP81ApM3m/31zXxX3fVIoIJPE8D5Vs8/l8uK6L8zypFBFI4nkeKmUm7/eb67q475tKEYEknuehkm0+nw/XdXGeJ5UiAkk8z0OlzOT9fnNdF/d9UykikMTzPFSyzefz4bouzvOkUkQgied5qJSZvN9vruvivm8qRQSSeJ6HSrb5fD5c18V5nlSKCCTxPA+VMpP3+811Xdz3TaWIQBLP81DJNp/Ph+u6OM+TShGBJJ7noVJm8n6/ua6L+76pctBaa6211lprrbXWWmut1EFrrbXWWmuttdZaa621UgettdZaa6211lprrbXWSh201lprrbXWWmuttdZaK3XQWmuttdZaa6211lprrdRBa6211lprrbXWWmuttVIHrbXWWmuttdZaa6211kodtNZaa6211lprrbXWWit10FprrbXWWmuttdZaa63UQWuttdZaa6211lprrbVSB6211lprrbXWWmuttdZKHbTWWmuttdZaa6211lorddBaa6211lprrbXWWmut1EFrrbXWWmuttdZaa621UgettdZaa6211lprrbXWSh201lprrbXWWmuttdZaK3XQWmuttdZaa6211lprrdRBa6211lprrbXWWmuttVIHrbXWWmuttdZaa6211kqdmcmXJGwjicykkm1sk5lUss2XJDKTSraxTWZSSRK2kURmUsk2tslMKtnmSxKZSSXb2CYzqSQJ20giM6lkG9tkJpVs8yWJzKSSbWyTmVSShG0kkZlUso1tMpNKtvmSRGZSyTa2yUwqScI2kshMKtnGNplJJdt8SSIzqWQb22QmlSRhG0lkJpVsY5vMpJJt/vYS4AAAIABJREFUviSRmVSyjW0yk0qSsI0kMpNKtrFNZlLJNl+SyEwq2cY2mUklSdhGEplJJdvYJjOpZJsvSWQmlWxjm8ykkiRsI4nMpJJtbJOZVLLNlyQyk0q2sU1mUkkStpFEZlLJNrbJTCrZ5ksSmUkl29gmM6kkCdtIIjOpZBvbZCaVbPMlicykkm1sk5lUkoRtJJGZVLKNbTKTSrb5kkRmUsk2tslMKknCNpLITCrZxjaZSSXbfEkiM6lkG9tkJpUkYRtJZCaVbGObzKSSbb4kkZlUso1tMpNKkrCNJDKTSraxTWZSyTZfkshMKtnGNplJJUnYRhKZSZXxn//8x/yPbSRxHAdjDCqttTiOg4ig0hiD+775/f0lM6m01uI4DiKCSraRxHEcjDGotNbiOA4igkpjDO775vf3l8yk0lqL4ziICCrZRhLHcTDGoNJai+M4iAgqjTG475vf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aNuWGCO1NDjnnHPOOeecc84555yrqsE555xzzjnnnHPOOedcVQ3OOeecc84555xzzjnnqmpwzjnnnHPOOeecc845V1WDc84555xzzjnnnHPOuaoanHPOOeecc84555xzzlXV4JxzzjnnnHPOOeecc66qBuecc84555xzzjnnnHNVNTjnnHPOOeecc84555yrqsE555xzzjnnnHPOOedcVQ3OOeecc84555xzzjnnqmpwzjnnnHPOOeecc845V1XEvW1bu/t88VsbuNvbmAvOuXevrd19vvitDdztbcwF55x7I3+2uYm7vW1PE+5Xb5L4s81N3O3LJJxz7z4R97Z957++gnPvVH/2t5u429v2OOHe2nf+6ys4906ytb/PFzc2cLe3sRRcHf/hH/8R59zre+of/gHn3qm29vf54sYG7vY2loL7/4u4X8pDDz3EN77xDXLOuIOl73seeOAB3Fv7D9/7R5w7yB566CG+8Y1vkHPGHSx93/PAAw/g3th3XnkF597pPvGJT/C1r32NUgruYGmahhMnTuBunY997GP85V/+JWaGOzhCCNx99924m/edV17BuYMq4n4pH/7wh3nqqad45pln+EVI4urVqywsLBBjpKZSCpKIMVLbbDYjxkjTNNRUSkESMUZqksTVq1dZWFggxsj1Tp06xcmTJ3Gv7xOf+ARf+9rXKKXgDpamaThx4gTu//XhD3+Yp556imeeeYa3IomrV6+ysLBAjJGaSilIIsZIbbPZjBgjTdNQUykFScQYqUkSV69eZWFhgRgjb+TUqVOcPHkS9//10EMP8Y1vfIOcM+5g6fueBx54APeLOXnyJI8//jh/93d/R9/3tG1LTWaGJNq2pbZpmmjblhACNZkZkmjblpoksbe3R9/3tG3L23XixAlOnz6Nu3Ueeughrl69yqVLl5gzMyTRti21TdNE27aEEKjJzJBE27bUJIm9vT36vqdtW2oyMyTRti2/jA996EM8/PDDuDd3+vRp/uIv/lMNyYQAABH4SURBVIKcM+5g6fueBx54APffBf0cP1dKYWtri+XlZVJK1JRzxswYhoGaJDGOIyklYozUlHPGzBiGgZpKKWxtbbG8vExKiZpyzpgZwzBQkyTGcSSlRIyRmnLOmBnDMFBTKYWtrS2Wl5dJKVFTzhkzYxgGapLEOI6klIgxUlPOGTNjGAbeipnx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xswYhoGaJDGOI33fE2OkppwzZsYwDNRUSmF3d5e+70kpUVPOGTNjGAZqksQ4jvR9T4yRmnLOmBnDMFBTKYXd3V36vielRE05Z8yMYRioSRLjONL3PTFGaso5Y2YMw0BNpRR2d3fp+56UEjXlnDEzhmGgJkmM40jf98QYqSnnjJkxDAM1lVLY3d2l73tSStSUc8bMGIaBmiQxjiN93xNjpKacM2bGMAzUVEphd3eXvu9JKVFTzhkzYxgGapLEOI70fU+MkZpyzpgZwzBQUymF3d1d+r4npURNOWfMjGEYqEkS4zjS9z0xRmrKOWNmDMNATaUUdnd36fuelBI15ZwxM4ZhoCZJjONI3/fEGKkp54yZMQwDNZVS2N3dpe97UkrU0uCcc84555xzzjnnnHOuqgbnnHPOOeecc84555xzVTU455xzzjnnnHPOOeecq6rBOeecc84555xzzjnnXFUNzjnnnHPOOeecc84556pqcM4555xzzjnnnHPOOVdVg3POOeecc84555xzzrmqGpxzzjnnnHPOOeecc85V1eCcc84555xzzjnnnHOuqgbnnHPOOeecc84555xzVTU455xzzjnnnHPOOeecq6rBOeecc84555xzzjnnXFUNzjnnnHPOOeecc84556pqcM4555xzzjnnnHPOOVdVg3POOeecc84555xzzrmqGpxzzjnnnHPOOeecc85V1eCcc84555xzzjnnnHOuqgbnnHPOOeecc84555xzVTU455xzzjnnnHPOOeecqyqWUpgzMyRhZpRSqEkSkiilUJMk5syMUgo1SUISpRRqMjMkYWaUUqhJEpIopVCTJObMjFIKNUlCEqUUajIzJGFmlFKoSRKSKKVQkyTmzIxSCjVJQhKlFGoyMyRhZpRSqEkSkiilUJMk5syMUgo1SUISpRRqMjMkYWaUUqhJEpIopVCTJObMjFIKNUlCEqUUajIzJGFmlFKoSRKSKKVQkyTmzIxSCjVJQhKlFGoyMyRhZpRSqEkSkiilUJMk5syMUgo1SUISpRRqMjMkYWaUUqhJEpIopVCTJObMjFIKNUlCEqUUajIzJGFmlFKoSRKSKKVQkyTmzIxSCjVJQhKlFGoyMyRhZpRSqEkSkiilUJMk5syMUgo1SUISpRRqMjMkYWaUUqhJEpIopVCTJObMjFIKNUlCEqUUajIzJGFmlFKo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) + +当我们将"雷霆嘎巴"的对象的引用计数器减小至0时,就将其移除,并且相邻两边直接连接。 + +### 1.4循环引用问题 + +一种编程语言利用引用计数器实现垃圾管理和回收,已经是比较完美的了,只要计数器为0就回收,不为0就不回收,即简单明了,又能实现垃圾管理。 + +但是如果真正这样想就太单纯了,因为,仅仅利用引用计数器实现垃圾管理和回收,就会存在一个BUG,就是循环引用问题。 + +比如: + +```python +v1 = [1,2,3] # refchain中创建一个列表对象,由于v1=对象,所以列表引对象用计数器为1. +v2 = [4,5,6] # refchain中再创建一个列表对象,因v2=对象,所以列表对象引用计数器为1. +v1.append(v2) # 把v2追加到v1中,则v2对应的[4,5,6]对象的引用计数器加1,最终为2. +v2.append(v1) # 把v1追加到v1中,则v1对应的[1,2,3]对象的引用计数器加1,最终为2. + +del v1 # 引用计数器-1 +del v2 # 引用计数器-1 + +最终v1,v2引用计数器都是1 +``` + +![图片](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABVsAAAIcCAYAAADoo34mAAAgAElEQVR4AezBX4ymZ33f//f3ea77ea7bk2XGcerUyz9vTcmCVz8cxoZIFBYpam2kpZu6UVGIIrYHmJ5s3UgVJxQr+JD+QdEqrXBONoIiUaWmFq7sHiCVQCyMPJaRRhhZuBsVx5s4gz2Zmcc7F3Nf38+v98FEqxXGa881gM339TL9P7VWNjY2WF5eJudMS6UU3J2+72lJEovFgpwzKSVaKqXg7vR9T0u1VjY2NlheXibnTEulFNydvu9pSRKLxYKcMyklWiql4O70fU9LtVY2NjZYXl4m50xLpRTcnb7vaUkSi8WCnDMpJVoqpeDu9H1PS7VWNjY2WF5eJudMS6UU3J2+72lJEovFgpwzKSVaKqXg7vR9T0u1VjY2NlheXibnTEulFNydvu9pSRKLxYKcMyklWiql4O70fU9LtVY2NjZYXl4m50xLpRTcnb7vaUkSi8WCnDMpJVoqpeDu9H1PS7VWNjY2WF5eJudMS6UU3J2+72lJEovFgpwzKSVaKqXg7vR9T0u1VjY2NlheXibnTEulFNydvu9pSRKLxYKcMyklWiql4O70fU9LtVY2NjZYXl4m50xLpRTcnb7vaUkSi8WCnDMpJVoqpeDu9H1PS7VWNjY2WF5eJudMS6UU3J2+72lJEovFgpwzKSVaKqXg7vR9T0u1VjY2NlheXibnTEulFNydvu9pSRKLxYKcMyklWiql4O70fU9LtVY2NjZYXl4m50xLpRTcnb7vaUkSi8WCnDMpJVoqpeDu9H1PS7VWNjY2WF5eJudMS6UU3J2+72lJEovFgpwzKSVaKqXg7vR9T0u1VjY2NlheXibnTEulFNydvu9pSRKLxYKcMyklWiql4O70fU9LtVY2NjZYXl4m50xLpRTcnb7vaUkSi8WCnDMpJVoqpeDu9H1PS7VWNjY2WF5eJufMQU0IIYQQQgghhBBCCCGEcGATQgghhBBCCCGEEEIIIRzYhBBCCCGEEEIIIYQQQggHNiGEEEIIIYQQQgghhBDCgU0IIYQQQgghhBBCCCGEcGATQgghhBBCCCGEEEIIIRzYhBBCCCGEEEIIIYQQQggHNiGEEEIIIYQQQgghhBDCgU0IIYQQQgghhBBCCCGEcGATQgghhBBCCCGEEEIIIRzYhBBCCCGEEEIIIYQQQggHNiGEEEIIIYQQQgghhBDCgU0IIYQQQgghhBBCCCGEcGATQgghhBBCCCGEEEIIIRxYkoQkRpKQxGGQREvuzkgSkjgMkmhJEiNJSOIwSKIld2ckCUkcBkm0JImRJCRxGCTRkrszkoQkDoMkWpLESBKSOAySaMndGUlCEodBEi1JYiQJSRwGSbTk7owkIYnDIImWJDGShCQOgyRacndGkpDEYZBES5IYSUISh0ESLbk7I0lI4jBIoiVJjCQhicMgiZbcnZEkJHEYJNGSJEaSkMRhkERL7s5IEpI4DJJoSRIjSUjiMEiiJXdnJAlJHAZJtCSJkSQkcRgk0ZK7M5KEJA6DJFqSxEgSkjgMkmjJ3RlJQhKHQRItSWIkCUkcBkm05O6MJCGJwyCJliQxkoQkDoMkWnJ3RpKQxGGQREuSGElCEodBEi25OyNJSOIwSKIlSYwkIYmDsu3tbf0/7Ozs0Pc9KSVak4SZ0ZokzIzDIAkzoyVJ7Ozs0Pc9KSVak4SZ0ZokzIzDIAkzoyVJ7Ozs0Pc9KSVak4SZ0ZokzIzDIAkzoyVJ7Ozs0Pc9KSVak4SZ0ZokzIzDIAkzoyVJ7Ozs0Pc9KSVak4SZ0ZokzIzDIAkzoyVJ7Ozs0Pc9KSVak4SZ0ZokzIzDIAkzoyVJ7Ozs0Pc9KSVak4SZ0ZokzIzDIAkzoyVJ7Ozs0Pc9KSVak4SZ0ZokzIzDIAkzoyVJ7Ozs0Pc9KSVak4SZ0ZokzIzDIAkzoyVJ7Ozs0Pc9KSVak4SZ0ZokzIzDIAkzoyVJ7Ozs0Pc9KSVak4SZ0ZokzIzDIAkzoyVJ7Ozs0Pc9KSVak4SZ0ZokzIzDIAkzoyVJ7Ozs0Pc9KSVak4SZ0ZokzIzDIAkzoyVJ7Ozs0Pc9KSVak4SZ0ZokzIzDIAkzoyVJ7Ozs0Pc9KSVak4SZ0ZokzIzDIAkzoyVJ7Ozs0Pc9KSUOKuWccXcWiwVd1zGfz2lpGAbcndlsRkuSKKXQdR3T6ZSWhmHA3ZnNZrTk7iwWC7quYz6f09IwDLg7s9mMliRRSqHrOqbTKS0Nw4C7M5vNaMndWSwWdF3HfD6npWEYcHdmsxktSaKUQtd1TKdTWhqGAXdnNpvRkruzWCzouo75fE5LwzDg7sxmM1qSRCmFruuYTqe0NAwD7s5sNqMld2exWNB1HfP5nJaGYcDdmc1mtCSJUgpd1zGdTmlpGAbcndlsRkvuzmKxoOs65vM5LQ3DgLszm81oSRKlFLquYzqd0tIwDLg7s9mMltydxWJB13XM53NaGoYBd2c2m9GSJEopdF3HdDqlpWEYcHdmsxktuTuLxYKu65jP57Q0DAPuzmw2oyVJlFLouo7pdEpLwzDg7sxmM1pydxaLBV3XMZ/PaWkYBtyd2WxGS5IopdB1HdPplJaGYcDdmc1mtOTuLBYLuq5jPp/T0jAMuDuz2YyWJFFKoes6ptMpLQ3DgLszm81oyd1ZLBZ0Xcd8PqelYRhwd2azGS1JopRC13VMp1NaGoYBd2c2m9GSu7NYLOi6jvl8TkvDMODuzGYzWpJEKYWu65hOp7Q0DAPuzmw2oyV3Z7FY0HUd8/mcloZhwN2ZzWa0JIlSCl3XMZ1OaWkYBtyd2WxGS+7OYrGg6zrm8zktDcOAuzObzWhJEqUUuq5jOp3S0jAMuDuz2YyW3J3FYkHXdcznc1oahgF3Zzab0ZIkSil0Xcd0OqWlYRhwd2azGS25O4vFgq7rmM/nHFT6f6i1YmZMp1NSSrRUa8XMSCnRkiRKKUynU1JKtFRrxcxIKdFSrRUzYzqdklKipVorZkZKiZYkUUphOp2SUqKlWitmRkqJlmqtmBnT6ZSUEi3VWjEzUkq0JIlSCtPplJQSLdVaMTNSSrRUa8XMmE6npJRoqdaKmZFSoiVJlFKYTqeklGip1oqZkVKipVorZsZ0OiWlREu1VsyMlBItSaKUwnQ6JaVES7VWzIyUEi3VWjEzptMpKSVaqrViZqSUaEkSpRSm0ykpJVqqtWJmpJRoqdaKmTGdTkkp0VKtFTMjpURLkiilMJ1OSSnRUq0VMyOlREu1VsyM6XRKSomWaq2YGSklWpJEKYXpdEpKiZZqrZgZKSVaqrViZkynU1JKtFRrxcxIKdGSJEopTKdTUkq0VGvFzEgp0VKtFTNjOp2SUqKlWitmRkqJliRRSmE6nZJSoqVaK2ZGSomWaq2YGdPplJQSLdVaMTNSSrQkiVIK0+mUlBIt1VoxM1JKtFRrxcyYTqeklGip1oqZkVKiJUmUUphOp6SUaKnWipmRUqKlWitmxnQ6JaVES7VWzIyUEi1JopTCdDolpURLtVbMjJQSLdVaMTOm0ykpJVqqtWJmpJRoSRKlFKbTKSklWqq1YmaklGip1oqZMZ1OSSnRUq0VMyOlREuSKKUwnU5JKdFSrRUzI6VES7VWzIzpdEpKiYOaEEIIIYQQQgghhBBCCOHAJoQQQgghhBBCCCGEEEI4sAkhhBBCCCGEEEIIIYQQDmxCCCGEEEIIIYQQQgghhAObEEIIIYQQQgghhBBCCOHAJoQQQgghhBBCCCGEEEI4sAkhhBBCCCGEEEIIIYQQDmxCCCGEEEIIIYQQQgghhAObEEIIIYQQQgghhBBCCOHAJoQQQgghhBBCCCGEEEI4sAkhhBBCCCGEEEIIIYQQDmxCCCGEEEIIIYQQQgghhANLhPAa4u5885vfZG1tjZfi7ly6dIn5fE5KiZZqrUgipURLktjb2yOlxGQyoaVaK5JIKdGSu3Pp0iXm8zkpJVqqtSKJlBItSWJvb4+UEpPJhCu9//3v593vfjeTyYQQws83d+eb3/wma2trjGqtSCKlREuS2NvbI6XEZDKhpVorkkgp0ZK7c+nSJebzOSklWqq1IomUEi1JYm9vj5QSk8mElmqtSCKlxNV6//vfz7vf/W4mkwkhhJ89d+eb3/wma2tr7JPE3t4eKSUmkwkt1VqRREqJltydS5cuMZ/PSSnRUq0VSaSUaEkSe3t7pJSYTCa0VGtFEiklWnJ3Ll26xHw+J6XEy3n/+9/Pu9/9biaTCSGE0EIihNeQxx9/nE9+8pPs7e0RQmtf/vKX+exnP8sHPvABQgg/3x5//HE++clPsre3RwitffnLX+azn/0sH/jABwgh/Ow9/vjjfPKTn2Rvb48QWvvyl7/MZz/7WT7wgQ8QQggtTAjhNeQb3/gGe3t7hHAY9vb2WFtbI4Tw8+8b3/gGe3t7hHAY9vb2WFtbI4Tw8+Eb3/gGe3t7hHAY9vb2WFtbI4QQWkmE8Bp1553v5JprOkI4qBdf3OP++79LCOG16c4738k113SEcFAvvrjH/fd/lxDCz68773wn11zTEcJBvfjiHvff/11CCKG1RAivUddc0/H7v/8bhHBQn/vctwghvHZdc03H7//+bxDCQX3uc98ihPDz7ZprOn7/93+DEA7qc5/7FiGEcBgmhBBCCCGEEEIIIYQQQjiwCSGEEEIIIYQQQgghhBAOLJVSkIQkhmGglEJLtVYkUUrhMAzDQK2VlmqtSKKUQkuSkMQwDJRSaKnWiiRKKRyGYRiotdJSrRVJlFK4WrVWQjhMtVZKKbxStVYkUUqhJUlIYhgGSim0VGtFEqUUDsMwDNRaaanWiiRKKbQkCUkMw0AphZZqrUiilMJhGIaBWist1VqRRCmFliQhiWEYKKVwELVWQjhMtVZKKbwUSUhiGAZKKbRUa0USpRQOwzAM1FppqdaKJEoptCQJSQzDQCmFlmqtSKKUwmEYhoFaKy3VWpFEKYWWJCGJYRgopdBSrRVJlFJ4tWqthHCYaq2UUng5tVYkUUrhMAzDQK2VlmqtSKKUQkuSkMQwDJRSaKnWiiRKKRyGYRiotdJSrRVJlFJoSRKSGIaBUgot1VqRRCmFwzAMA7VWWqq1IolSCi1JQhLDMFBK4aCSu+PujNwdd6clSUjC3WlNEu6OmdGSJCTh7rTk7ozcHXenJUlIwt1pTRLujpnRkiQk4e5cLUmEcJgk4e68UpKQhLvTkrszcnfcnZYkIQl3pzVJuDtmRkuSkIS705K7M3J33J2WJCEJd6c1Sbg7ZkZLkpCEu9OSuzNyd9ydg5BECIdJEu7OS3F3Ru6Ou9OSJCTh7rQmCXfHzGhJEpJwd1pyd0bujrvTkiQk4e60Jgl3x8xoSRKScHdacndG7o6705IkJOHuvFqSCOEwScLdeTmSkIS705ok3B0zoyVJSMLdacndGbk77k5LkpCEu9OaJNwdM6MlSUjC3WnJ3Rm5O+5OS5KQhLvTmiTcHTOjJUlIwt1pyd0ZuTvuzkGlvu+ptbKzs8NsNiPnTEulFNydvu9pSRKLxYLZbEZKiZZKKbg7fd/TUq2VnZ0dZrMZOWdaKqXg7vR9T0uSWCwWzGYzUkq0VErB3en7nquVUiKEw5RSou97XqlSCu5O3/e0VGtlZ2eH2WxGzpmWSim4O33f05IkFosFs9mMlBItlVJwd/q+p6VaKzs7O8xmM3LOtFRKwd3p+56WJLFYLJjNZqSUaKmUgrvT9z0t1VrZ2dlhNpuRc+YgUkqEcJhSSvR9z0uptbKzs8NsNiPnTEulFNydvu9pSRKLxYLZbEZKiZZKKbg7fd/TUq2VnZ0dZrMZOWdaKqXg7vR9T0uSWCwWzGYzUkq0VErB3en7npZqrezs7DCbzcg501IpBXen73terZQSIRymlBJ93/NySim4O33f05IkFosFs9mMlBItlVJwd/q+p6VaKzs7O8xmM3LOtFRKwd3p+56WJLFYLJjNZqSUaKmUgrvT9z0t1VrZ2dlhNpuRc6alUgruTt/3tCSJxWLBbDYjpURLpRTcnb7vaanWys7ODrPZjJwzBzUhhBBCCCGEEEIIIYQQwoFNCCGEEEIIIYQQQgghhHBgE0IIIYQQQgghhBBCCCEc2IQQQgghhBBCCCGEEEIIBzYhhBBCCCGEEEIIIYQQwoFNCCGEEEI4ZLVWaq2EEEIIIYQQwuvZhBBCCCGEQ/a3f/u3/Jt/82/4n//zf7K5uUkphRBCCCGEEEJ4vUmEEEIIIfwU/MVf/AWPPvoo58+f561vfSurq6vccccdHD9+nBBCCK8fwzCQUiKEEEL4RZQIIYQQQvgpWiwWfPe73+W73/0uX/jCF3j729/O7bffzm233cZb3vIWjhw5QgghhNeuZ599lv/wH/4DH/3oR3nb295GzpkQQgjhF0UihBBCCOFn6KmnnuKpp55iNptx5MgRPvjBD/I7v/M7HDt2jBBCCK89tVb+/M//nEceeYRf+ZVf4dixY3zwgx/k9ttvZ2VlhRBCCOH1LBFCCCGE8HPgRz/6ET/84Q/57//9v/M//sf/4KabbuI973kPt956K+9+97tZWloihBDCa4ck/uZv/oa/+Zu/4dvf/jb/8T/+R973vvfxT/7JP+H48eO8+c1vJqVECCGE8HqSCCGE8HeefPJJvvCFLzCaTCaMJpMJIzNjNJlMGJkZIzOj1sqo6zrMDDPDzDAzRmaGmWFmmBkjM8PMMDPMjJGZYWaYGSNJbG9vs7S0xGw2w8wYTSYTRmaGmTEyM8wMM2NkZpgZZoaZMTIzzAwzY29vD0nM53MmkwmjyWTCPjPDzDAzRmaGmWFmmBkjM8PMMDNGZsZod3eX+XxOSgkzw8wwM0ZmxmgymTAyM0ZmhplxOTPjcj/60Y9wd3LOXMnMeKXMjFGtlc3NTdyd+XzOj2NmXC0zY18pBUmUUvhJzIyrZWZI4sUXX+RHP/oRKSV+EjPjapkZpRTcnVorL8fMuBqXLl1CEler1spTTz3FU089xRe/+EWm0yn/9J/+U373d3+X66+/HkmEEEJ4bam18md/9mf82Z/9Gddccw0rKyt85CMf4bd+67f4pV/6JUIIIYTXg0QIIYS/s7a2xtraGuFny8y4nJlxOTPjcmbGlcyMfWbG5cyMy5kZkjAzRmbG5cyMy5kZlzMzLmdmXMnM2GdmXM7M2GdmXM7MuJyZsU8SZoaZsc/MuJKZsc/MuJyZcTkzQxIjM8PMuJKZMTIzLmdmXMnMGLk7P/zhD3m1aq185Stf4Stf+QpvfvObkUQIIYTXrhdffJEXX3yRz33uc/yX//JfuOWWW7jtttu47bbb+LVf+zVSSoQQQgivRYkQQgjh54wkLieJEEL4afrud7/LF7/4RcwMM8PMGJkZZoYkFosFfd/TdR2TyYTRZDJhZGaMJpMJIzPDzDAzzIyRmWFmmBlmxsjMGIYBScznc0aTyYTRZDJBEpPJhNFkMmFkZozMDDPDzBhNJhNGk8mEfbu7u8znc1JKmBkjM8PMMDNGZoaZYWaYGSMzw8wwM0ZmhplhZpgZe3t7SCLnjJlhZozMDDPDzDAzRmaGmWFmjMwMM+NKZkatleeff55hGJjP57wUM+OVMDNKKUji0qVLvBQz42qZGSNJvPjii+zu7pJS4qWYGVfLzBiVUnB39vb2eDlmxtUwM2qtLBYLptMpwzDwUsyMq3Hp0iVeid3dXb71rW/xrW99i9Eb3/hGPvKRj3D77bdz5MgRQgghhNeSRAghhL/z67/+6/yjf/SPkIQkJCGJkSQkIYmRJEaS2NvbQxIpJSQhCUlIYiQJSUhCEiNJSEISI0lIQhKSGLk7u7u7pJSYTqdIYuTujNydfZKQhCRGkpCEJCQxkoQkJFFrRRLT6RR3Z+TumBnuzkgSkhi5OyNJjCQhCUlIYiQJSQzDgJlhZkhCEpKQxEgSkhhJYuTujCQhiZEkJCEJSUhCEiNJSGIkCUlIYiQJSUhCEiNJSGLk7pgZ7s7I3XF3zIyRJCQxkoQkJCEJSYwkIQlJ7HN3wuG5+eab+cxnPsP111/P5z//ef7rf/2vhHBYHn/8cR5//HHCT5eZcTkz43JmxuXMjMuZGZczMy5nZlzJzBiZGZczM/aZGVcyMy5nZlzOzLicmbHPzNhnZlzJzLicmXE5M+NyZsY+M+NyZsblzIzLmRmjWiuTyYTJZMLlzIx9ZsblzIzLmRmjYRg4iL/8y7/kP/2n/8TnP/953vzmN2NmhBBCCK8ViRBCCH/n5ptv5syZM7xSpRTcnb7vaanWysbGBsvLy+ScaamUgrvT9z0tSWKxWJBzJqVES6UU3J2+72mp1srGxgbLy8vknDkoSezb3d3F3ck5s08SI0mMJLFPEiNJjCQxksQ+SUhisViQc2Y6nSKJfZIYSWIkiZEkRpLYJ4l9khiVUnB35vM5+yQhiX2SGElinyRGktgnidHm5ib/9t/+WzY2Nrga0+mUm266iVtvvZXjx49z4403ct111/H3//7fZ2RmhBBefyRxOUmEEEIIIbyWJEIIIYTQlJmxbzKZMJpOp7QkiVHOmZQSLZVScHf6vqeVpaUlptMpP8lsNuPIkSN88IMf5Hd+53c4duwYIfw0SfydX//1X+d973sfkpCEJEaSkIS7s7OzQ86Z6XSKJCQxkoQkJCGJkSQkIYmRJCQhCUlIYiSJWivuznQ6ZeTujNwdM8PdkYQkJLHP3RlJYuTujNydkSSGYcDMMDMkMZKEJCQxkoQkJCGJkSQkIYmRuzNyd0bujiTMDElIYiQJSUhCEiNJSEISI0lIQhKSGElCEpLY29tjOp0ykoQkRpKQhCQkMZKEJCQxkoQkJCEJSYwkIQl3x8yQhCQkIYmRJCQhiZEkJCGJkSRG7k5o76Mf/Sgf+9jHOHLkCP/5P/9nnnzySUIIIYTXgkQIIYQQws/Q29/+dm6//XZuu+023vKWt3DkyBFC+Fkw4+/cfPPN/Mt/+S95KbVWNjY2WF5eJudMS6UU3J2+72lJEovFgpwzKSVaKqXg7vR9T0u1VjY2NlheXibnTEulFNydvu9pQRIjSezs7JBzZjqdMpLEPkmMJDGSxD5JjCQxksRIEqNSCu5OzhlJjCSxTxL7JCGJkST2SWIkiX3DMPD8889z5MgR5vM5khhJYp8kJHE5SUjicpL4wQ9+wNmzZ7laOWduueUWbrnlFv7hP/yH3HDDDbzhDW/gV37lVwghhBBeaxIhhBBCCD9FS0tLvPWtb2V1dZU77riD48ePE0IIr3Vmxr7JZMJkMmE6ndJSSgl3p+97Wqq1YmYsLy+Tc+aghmHg5VxzzTWsrKzwkY98hN/6rd/il37plwghhBBeD1KtFXdHEu5OrZWWJCGJWistSWLk7tRaaUkSkqi10pK7Iwl3p9ZKS5KQRK2VliQxcndqrbQkCUnUWrla7k4Ih8ndqbXySklCErVWWnJ3JOHu1FppSRKSqLXSkiRG7k6tlZYkIYlaKy25O5Jwd2qttCQJSdRaaUkSI3en1kpLkpBErZVWaq289a1v5Z//83/Ohz70Ia699lpmsxmjWiuvlLsTwmFyd2qtvBR3RxLuTq2VliQhiVorLUli5O7UWmlJEpKotdKSuyMJd6fWSkuSkEStlZYkMXJ3aq20JAlJ1Fppyd2RhLtTa+Wg3J0fZzKZ8L73vY9//I//McePH+dNb3oTKSVGtVZeirsTwmFyd2qtvBxJSKLWSkuSGLk7tVZakoQkaq205O5Iwt2ptdKSJCRRa6UlSYzcnVorLUlCErVWWnJ3JOHu1FppSRKSqLXSkiRG7k6tlZYkIYlaKy25O5Jwd2qtHFTa2NhAEu7O1tYWZkZLXdcxmUzY3t6mJTMj58zW1ha1Vlrquo7JZML29jYtScLd2drawsxoqes6JpMJ29vbtGRm5JzZ2tqi1kpLXdcxmUzY3t7mal26dIkQDtOlS5fY2Njgleq6jslkwvb2Ni1Jwt3Z2trCzGip6zomkwnb29u0ZGbknNna2qLWSktd1zGZTNje3qYlSbg7W1tbmBktdV3HZDJhe3ublsyMnDNbW1vUWmmp6zomkwnb29u04u78u3/37zAzJpMJW1tbHMSlS5cI4TBdunSJjY0NXook3J2trS3MjJa6rmMymbC9vU1LZkbOma2tLWqttNR1HZPJhO3tbVqShLuztbWFmdFS13VMJhO2t7dpyczIObO1tUWtlZa6rmMymbC9vU1LknB3tra2MDMO6oUXXmBkZlx33XXceOON3HbbbXzgAx9geXmZfZubm1yNS5cuEcJhunTpEhsbG7ycruuYTCZsb2/TkpmRc2Zra4taKy11XcdkMmF7e5uWJOHubG1tYWa01HUdk8mE7e1tWjIzcs5sbW1Ra6WlruuYTCZsb2/TkiTcna2tLcyMlrquYzKZsL29TUtmRs6Zra0taq201HUdk8mE7e1tWpKEu7O1tYWZcVBpeXkZd2dra4ulpSW6rqMld0cSOWdaG4aBpaUlzIyW3B1J5Jxpyd3Z2tpiaWmJrutoyd2RRM6Z1oZhYGlpCTOjJXdHEjlnrtZ8PieEwzSfz1leXuaVcnckkXOmJXdna2uLpaUluq6jJXdHEjlnWhuGgaWlJcyMltwdSeScacnd2draYmlpia7raMndkUTOmdaGYWBpaQkzoyV3RxI5Z1pyd7a2tlhaWqLrOg5iPp8TwmGaz+csLy/zUtydra0tlpaW6LqOltwdSeScaW0YBpaWljAzWnJ3JJFzpiV3Z2tri6WlJbquoyV3RxI5Z1obhoGlpSXMjJbcHUnknGnJ3dna2mJpaYmu6ziora0tfuM3foOPfOQj/Nqv/Rp93zObzXi15vM5IRym+XzO8vIyL8fdkUTOmdaGYWBpaQkzoyV3RxI5Z1pyd7a2tlhaWqLrOlpydySRc6a1YRhYWlrCzGjJ3ZFEzpmW3J2trS2Wlpbouo6W3B1J5JxpbRgGlpaWMIgXZpgAACAASURBVDNacnckkXOmJXdna2uLpaUluq7joFLOmVorZkbXdeScaamUgruTc6YlSQzDQNd1pJRoqZSCu5NzpqVaK2ZG13XknGmplIK7k3OmJUkMw0DXdaSUaKmUgruTc+ZqpZQI4TCllMg580qVUnB3cs60VGvFzOi6jpwzLZVScHdyzrQkiWEY6LqOlBItlVJwd3LOtFRrxczouo6cMy2VUnB3cs60JIlhGOi6jpQSLZVScHdyzrRUa8XM6LqOnDMHkVIihMOUUiLnzEuptWJmdF1HzpmWSim4OzlnWpLEMAx0XUdKiZZKKbg7OWdaqrViZnRdR86ZlkopuDs5Z1qSxDAMdF1HSomWSim4OzlnWqq1YmZ0XUfOmYM6duwYf/RHf8SolIK7k3Pm1UopEcJhSimRc+bllFJwd3LOtCSJYRjouo6UEi2VUnB3cs60VGvFzOi6jpwzLZVScHdyzrQkiWEY6LqOlBItlVJwd3LOtFRrxczouo6cMy2VUnB3cs60JIlhGOi6jpQSLZVScHdyzrRUa8XM6LqOnDMHNSGEEEIIIYQQQmgkpUQIIYTwi2pCCCGEEEIIIYQQQgghhANLhBBCCCGEV+zChRc4e/YhPvOZD7K6epRW1tae5a67vsq+M2du4ezZ93Klzc1d7r77Ie688x2cPn2cq3XhwgucPfsQFy9us++ee05y+vRxrsYDD3yPe+/9Ope7774Ps7p6lNbOnXuU8+efYN+JE9fzh3/4IVZWMqO1tWe5666vsu/MmVs4e/a9hBBCK+fOPcr580+w78SJ6/nDP/wQKyuZFtbWnuWuu77KvjNnbuHs2ffy41y48AJnzz7E6Ny5D3Hs2LX8JBcuvMDZsw9x8eI2V7rjjrfx6U+fJOfE1Th37lHOn3+Cfffcc5LTp49zGC5ceIGzZx/iM5/5IKurR9m3tvYsd931VfadOXMLZ8++lxBC+HmTCCGEEEIIV+2BB77Hvfd+ncN2330fZnX1KFdaW3uWu+76KvvuvPMdXK0HHvge9977da50771f59vf/ks+/emT5Jx4KefOPcr5809wpbvu+ir33HOS06eP08Lm5i533/0Q6+vPcbn19ef4zd/8E+6778Osrh5ldfUoa2ufYHNzl7vvfogQQmhlc3OXu+9+iPX157jc+vpz/OZv/gn33fdhVleP0sp9932Y1dWj/CQPPvgUFy9uc8MNR7gazz9/iYsXtzmIzc1d7r77IdbXn+Ny9977dd70pjewunqUVh544Hvce+/XeSmrq0dZW/sEm5u73H33Q4QQws+rRAghhBBCeFkXLrzA2bMPcfHiNidOXM+b3vQGHn74+/y0bG7ucvfdD7G+/hw33HCE973vzfzpn36Xq7W7O/Dtb/8ld9zxNj796ZPknBhduPACZ88+xMMPf58773wHq6tH+Unuueckp08fZ98DD3yPe+/9Ovff/yQnT97IykrmoJ5++nnW15/jvvs+zOrqUfadO/co588/wf33P8nNN19PzokQQjgMTz/9POvrz3HffR9mdfUo+86de5Tz55/g/vuf5OabryfnxE/D2tqznD//BK/GPfec5PTp47xSm5u73H33Q6yvP8cdd7yNT3/6JDknRg888D1auXDhBc6efYiLF7c5ceJ63vSmN/Dww98nhBBeqxIhhBBCCOGq3Xffh1ldPcq5c4/ys3DPPSc5ffo4DzzwPV6p3/3d/493vvPvcbljx67lM5/5IHfd9VUeeeQHrK4e5aWcPfternT77W/j29/+S555ZotWrrvuGr72tY+xspK53Mc/vspf/dUO3/nOX3Px4jbHjl1LCCEchuuuu4avfe1jrKxkLvfxj6/yV3+1w3e+89dcvLjNsWPXcth2dwfuv/9J3ve+NzP6P/9nk1fiTW96A6/G17/+F6yvP8eZM7dw9ux7udzp08dp7b77Pszq6lHOnXuUEEJ4LZsQQgghhPAL6MKFFzh16kt87GNfYXNzlytduPACp059iU996mvs7g4cO3YtDz74UVZXj/KzsLKS+ZM/+WecPn2cVyPnxDvf+fdobXd34JlntvhJLlx4gVOnvsTHPvYVNjd3udKFCy9w6tSX+NSnvsbu7sCNN66wspIJIYRWLlx4gVOnvsTHPvYVNjd3udKFCy9w6tSX+NSnvsbu7sCNN66wspL5efC//tf3+c53/pp/9a9u48iROVfrmWe2eLU2N3e5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35nnmd47mcyMiGCMQSZ3p7XGPM+MMchkZkQEYwwySWLfd+Z5pvdOJjMjIhhjkMndaa0xzzNjDDKZGRHBGINMktj3nXme6b2TycyICMYYZHJ3WmvM88wYg0xmRkQwxiCTJPZ9Z55neu9kMjMigjEGmdyd1hrzPDPGIJOZERGMMcgkiX3fmeeZ3juZzIyIYIzBW/3TP/0TL+JjH/sYv/3bv83z3J3WGvM8M8Ygk5kREYwxyCSJfd+Z55neOy/qeDzSWuOZMQbPMzMigjEGmdyd1hrzPDPGIJOZERGMMcgkiX3fmeeZ3juZzIyIYIxBJnentcY8z4wxyGRmRARjDDJJYt935nmm904mMyMiGGOQyd1prTHPM2MMMpkZEcEYg0yS2PedeZ7pvZPJzIgIxhhkcndaa8zzzBiD+5oopfyf/OM//iMv6u/+7u8opZRSSimlvDd9/OMf57vf/S4v4hOf+AT7vlNKKeXH00Qp5V0zMz772c/yot544w22baOUUkoppZTy3iKJf/iHf+BFvfnmm2zbRimllB9PE6WUd+3m5oavfvWrvKivf/3rnE4nSimllFJKKe8t19fXfPGLX+RFffe73+XTn/40pZRSfjxNlFLetb/927/l+9//Pi/KzPjIRz5CKaWUUkop5b3lW9/6Ft/4xjd4N/7yL/8SSZRSSvnx0ymlvCv7vvOZz3yGX/zFX+StvvOd7/A///M/3Lm8vOSnfuqneKs33niDp0+fMs8zpZRSSimllPeGv/mbv+H29pZ34/Of/zxvvvkmP//zP08ppZQfL51SyrvSWuNP/uRPeN6f/umf8qEPfYg7v/qrv8rv//7v87zWGqWUUkoppZT3jve///28//3v562+9a1v8eu//uvc+eVf/mX+7M/+jOdN00QppZQfP51SyrtyOBwYY/C83jvPHA4HxhiUUkoppZRS3tt67zyv985b9d4ppZRS7kyUUkoppZRSSimllFJKubeJUkoppZRSSimllFJKKfc2UUoppZRSSimllFJKKeXeJkoppZRSSimllFJKKaXc20QppZRSSimllFJKKaWUe5sopZRSSimllFJKKaWUcm8TpZRSSimllFJKKaWUUu5topRSSimllFJKKaWUUsq9TZRSSimllFJKKaWUUkq5t4lSSimllFJKKaWUUkop9zZRSimllFJKKaWUUkop5d4mSiml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niedqgpJzDnptvdmzskYg05VhSTmnHSqKn79+sXPnz85z5NOVYUk5px023sz52SMQaeqQhJzTjpVFb9+/eLnz5+c50mnqkISc0667b2ZczLGoFNVIYk5J52qil+/fvHz50/O86RTVSGJOSfd9t7MORlj0KmqkMSck05Vxa9fv/j58yfnedKpqpDEnJNue2/mnIwx6FRVSGLOSaeq4tevX/z8+ZPzPOlUVUhizkm3vTdzTsYYdKoqJDHnpFNV8evXL37+/Ml5nnSqKiQx56Tb3ps5J2MMOlUVkphz0qmq+PXrFz9//uQ8TzpVFZKYc9Jt782ckzEGnaoKScw56VRV/Pr1i58/f3KeJ52qCknMOem292bOyRiDTlWFJOacdKoqfv36xc+fPznPk05VhSTmnHTbezPnZIxBp6pCEnNOOlUVv3794ufPn5znSaeqQhJzTrrtvZlzMsagU1UhiTknnaqKX79+8fPnT87zpFNVIYk5J9323sw5GWPQqaqQxJyTTlXFr1+/+PnzJ+d50qmqkMSck257b+acjDHoVFVIYs5Jp6ri169f/Pz5k/M86VRVSGLOSbe9N3NOxhh0qiokMeekU1Xx69cvfv78yXmefNW675vMZIzBeZ7c902niKCquO+bTpLYe3OeJ2stOkUEVcV933TKTMYYnOfJfd90igiqivu+6SSJvTfnebLWolNEUFXc902nzGSMwXme3PdNp4igqrjvm06S2HtznidrLTpFBFXFfd90ykzGGJznyX3fdIoIqor7vukkib0353my1qJTRFBV3PdNp8xkjMF5ntz3TaeIoKq475tOkth7c54nay06RQRVxX3fdMpMxhic58l933SKCKqK+77pJIm9N+d5staiU0RQVdz3TafMZIzBeZ7c902niKCquO+bTpLYe3OeJ2stOkUEVcV933TKTMYYnOfJfd90igiqivu+6SSJvTfnebLWolNEUFXc902nzGSMwXme3PdNp4igqrjvm06S2HtznidrLTpFBFXFfd90ykzGGJznyX3fdIoIqor7vukkib0353my1qJTRFBV3PdNp8xkjMF5ntz3TaeIoKq475tOkth7c54nay06RQRVxX3fdMpMxhic58l933SKCKqK+77pJIm9N+d5staiU0RQVdz3TafMZIzBeZ7c902niKCquO+bTpLYe3OeJ2stOkUEVcV9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OSed9t5UFdd10amqeL/fnOfJx8cHnfbeVBXXddFJEhHBeZ7MOem096aquK6LTlXF+/3mPE8+Pj7otPemqriui06SiAjO82TOSae9N1XFdV10qire7zfnefLx8UGnvTdVxXVddJJERHCeJ3NOOu29qSqu66JTVfF+vznPk4+PDzrtvakqruuikyQigvM8mXPSae9NVXFdF52qivf7zXmefHx80GnvTVVxXRedJBERnOfJnJNOe2+qiuu66FRVvN9vzvPk4+ODTntvqorruugkiYjgPE/mnHTae1NVXNdFp6ri/X5znicfHx902ntTVVzXRSdJRATneTLnpNPem6riui46VRXv95vzPPn4+KDT3puq4rouOkkiIjjPkzknnfbeVBXXddGpqni/35znycfHB5323lQV13XRSRIRwXmezDnptPemqriui05Vxfv95jxPPj4+6LT3pqq4rotOkogIzvNkzkmnvTdVxXVddKoq3u8353ny8fFBp703VcV1XXSSRERwnidzTjrtvakqruuiU1Xxfr85z5OPjw++av0vZCZjDOacrLXolJmMMVhr0UkSEcGck7UWnTKTMQZrLTplJmMM5pysteiUmYwxWGvRSRIRwZyTtRadMpMxBmstOmUmYwzmnKy16JSZjDFYa9FJEhHBnJO1Fp0ykzEGay06ZSZjDOacrLXolJmMMVhr0UkSEcGck7UWnTKTMQZrLTplJmMM5pyslVUI3AAAIABJREFUteiUmYwxWGvRSRIRwZyTtRadMpMxBmstOmUmYwzmnKy16JSZjDFYa9FJEhHBnJO1Fp0ykzEGay06ZSZjDOacrLXolJmMMVhr0UkSEcGck7UWnTKTMQZrLTplJmMM5pysteiUmYwxWGvRSRIRwZyTtRadMpMxBmstOmUmYwzmnKy16JSZjDFYa9FJEhHBnJO1Fp0ykzEGay06ZSZjDOacrLXolJmMMVhr0UkSEcGck7UWnTKTMQZrLTplJmMM5pysteiUmYwxWGvRSRIRwZyTtRadMpMxBmstOmUmYwzmnKy16JSZjDFYa9FJEhHBnJO1Fp0ykzEGay06ZSZjDOacrLXolJmMMVhr0UkSEcGck7UWnTKTMQZrLTplJmMM5pysteiUmYwxWGvRSRIRwZyTtRadMpMxBmstOmUmYwzmnKy16JSZjDFYa9FJEhHBnJO1Fp0y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JokxBt0kMcbgPUhijEEnSdxuN87zZM5JN0mMMegmiTEG70ESYww6SeJ2u3GeJ3NOuklijEE3SYwxeA+SGGPQSRK3243zPJlz0k0SYwy6SWKMwXuQxBiDTpK43W6c58mck0fN4zioKu73O9u28fT0RKfruqgq9n2nkyQigm3bWNeVTtd1UVXs+06nquJ+v7NtG09PT3S6rouqYt93OkkiIti2jXVd6XRdF1XFvu90qiru9zvbtvH09ESn67qoKvZ9p5MkIoJt21jXlU7XdVFV7PtOp6rifr+zbRtPT090uq6LqmLfdzpJIiLYto11Xel0XRdVxb7vdKoq7vc727bx9PREp+u6qCr2faeTJCKCbdtY15VO13VRVez7Tqeq4n6/s20bT09PdLqui6pi33c6SSIi2LaNdV3pdF0XVcW+73SqKu73O9u28fT0RKfruqgq9n2nkyQigm3bWNeVTtd1UVXs+06nquJ+v7NtG09PT3S6rouqYt93OkkiIti2jXVd6XRdF1XFvu90qiru9zvbtvH09ESn67qoKvZ9p5MkIoJt21jXlU7XdVFV7PtOp6rifr+zbRtPT090uq6LqmLfdzpJIiLYto11Xel0XRdVxb7vdKoq7vc727bx9PREp+u6qCr2faeTJCKCbdtY15VO13VRVez7Tqeq4n6/s20bT09PdLqui6pi33c6SSIi2LaNdV3pdF0XVcW+73SqKu73O9u28fT0RKfruqgq9n2nkyQigm3bWNeVTtd1UVXs+06nquJ+v7NtG09PT3S6rouqYt93OkkiIti2jXVd6XRdF1XFvu90qiru9zvbtvH09ESn67qoKvZ9p5MkIoJt21jXlU7XdVFV7PtOp6rifr+zbRtPT088av4DMpMxBuu6MuekU2YyxmDOSSdJRATrujLnpFNmMsZgzkmnzGSMwbquzDnplJmMMZhz0kkSEcG6rsw56ZSZjDGYc9IpMxljsK4rc046ZSZjDOacdJJERLCuK3NOOmUmYwzmnHTKTMYYrOvKnJNOmckYgzknnSQREazrypyTTpnJGIM5J50ykzEG67oy56RTZjLGYM5JJ0lEBOu6MuekU2YyxmDOSafMZIzBuq7MOemUmYwxmHPSSRIRwbquzDnplJmMMZhz0ikzGWOwritzTjplJmMM5px0kkREsK4rc046ZSZjDOacdMpMxhis68qc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k062WWsxxuC6LjpVFZKYc9Jp781xHIwxmHPSqaqQxJyTTrZZazHG4LouOlUVkphz0mnvzXEcjDGYc9KpqpDEnJNOtllrMcbgui46VRWSmHPSae/NcRyMMZhz0qmqkMSck062WWsxxuC6LjpVFZKYc9Jp781xHIwxmHPSqaqQxJyTTrZZazHG4LouOlUVkphz0mnvzXEcjDGYc9KpqpDEnJNOtllrMcbgui46VRWSmHPSae/NcRyMMZhz0qmqkMSck062WWsxxuC6LjpVFZKYc9Jp781xHIwxmHPSqaqQxJyTTrZZazHG4LouOlUVkphz0mnvzXEcjDGYc9KpqpDEnJNOtllrMcbgui46VRWSmHPSae/NcRyMMZhz0qmqkMSck062WWsxxuC6LjpVFZKYc9Jp781xHIwxmHPSqaqQxJyTTrZZazHG4LouOlUVkphz0mnvzXEcjDGYc9KpqpDEnJNOtllrMcbgui46VRWSmHPSae/NcRyMMZhz8lc/RERERERERERERMSf/RARERERERERERERf/ZDRERERERERERERPzZDxERERERERERERHxZz9ERERERERERERExJ/9EBERERERERERERF/9kNERERERERERERE/NkPEREREREREREREfFnP0RERERERERERETEn/0QEREREREREREREX/2Q0RERERERERERET82Q8RERERERERERER8Wc/RERERERERERERMSf/RARERERERERERERf/ZDRERERERERERERPzZDxERERERERERERHxZz9ERERERERERERExJ/9EBERERERERERERF/9kNERERERERERERE/NlVVdjGNmstqopOe29sU1X8D2st9t502ntjm6qik21ss9aiqui098Y2VcX/sNZi702nvTe2qSo62cY2ay2qik57b2xTVfwPay323nTae2ObqqKTbWyz1qKq6LT3xjZVxf+w1mLvTae9N7apKjrZxjZrLaqKTntvbFNV/A9rLfbedNp7Y5uqopNtbLPWoqrotPfGNlXF/7DWYu9Np703tqkqOtnGNmstqopOe29sU1X8D2st9t502ntjm6qik21ss9aiqui098Y2VcX/sNZi702nvTe2qSo62cY2ay2qik57b2xTVfwPay323nTae2ObqqKTbWyz1qKq6LT3xjZVxf+w1mLvTae9N7apKjrZxjZrLaqKTntvbFNV/A9rLfbedNp7Y5uqopNtbLPWoqrotPfGNlXF/7DWYu9Np703tqkqOtnGNmstqopOe29sU1X8D2st9t502ntjm6qik21ss9aiqui098Y2VcX/sNZi702nvTe2qSo62cY2ay2qik57b2xTVfwPay323nTae2ObqqKTbWyz1qKq+KtLEpL4JQlJdLKNbSTRzTaSOI6DTraxjSQ6SeKXJCTRyTa2kUQ320jiOA462cY2kugkiV+SkEQn29hGEt1sI4njOOhkG9tIopMkfklCEp1sYxtJdLONJI7joJNtbCOJTpL4JQlJdLKNbSTRzTaSOI6DTraxjSQ6SeKXJCTRyTa2kUQ320jiOA462cY2kugkiV+SkEQn29hGEt1sI4njOOhkG9tIopMkfklCEp1sYxtJdLONJI7joJNtbCOJTpL4JQlJdLKNbSTRzTaSOI6DTraxjSQ6SeKXJCTRyTa2kUQ320jiOA462cY2kugkiV+SkEQn29hGEt1sI4njOOhkG9tIopMkfklCEp1sYxtJdLONJI7joJNtbCOJTpL4JQlJdLKNbSTRzTaSOI6DTraxjSQ6SeKXJCTRyTa2kUQ320jiOA462cY2kugkiV+SkEQn29hGEt1sI4njOOhkG9tIopMkfklCEn91Pc/D3pvP58N938w56VRVSOJ5HjrZ5vv9ct8313XRqaqQxPM8dNp78/l8uO+bOSedqgpJPM9DJ9t8v1/u++a6LjpVFZJ4nodOe28+nw/3fTPnpFNVIYnneehkm+/3y33fXNdFp6pCEs/z0Gnvzefz4b5v5px0qiok8TwPnWzz/X6575vruuhUVUjieR467b35fD7c982ck05VhSSe56GTbb7fL/d9c10XnaoKSTzPQ6e9N5/Ph/u+mXPSqaqQxPM8dLLN9/vlvm+u66JTVSGJ53notPfm8/lw3zdzTjpVFZJ4nodOtvl+v9z3zXVddKoqJPE8D5323nw+H+77Zs5Jp6pCEs/z0Mk23++X+765rotOVYUknueh096bz+fDfd/MOelUVUjieR462eb7/XLfN9d10amqkMTzPHTae/P5fLjvmzknnaoKSTzPQyfbfL9f7vvmui46VRWSeJ6HTntvPp8P930z56RTVSGJm7yWJQAAAOVJREFU53noZJvv98t931zXRaeqQhLP89Bp783n8+G+b+acdKoqJPE8D51s8/1+ue+b67roVFVI4nkeOu29+Xw+3PfNnJNOVYUknuehk22+3y/3fXNdF52qCkk8z0OnvTefz4f7vplz0qmqkMTzPHSyzff75b5vruuiU1Uhied56LT35vP5cN83c046VRWSeJ6HTrb5fr/c9811XXSqKiTxPA+d9t58Ph/u+2bOyV/9EBERERERERERERF/9kNERERERERERERE/NkPEREREREREREREfFnP0RERERERERERETEn/0D3WSUSJZ8m0IAAAAASUVORK5CYII=) + +两个引用计数器现在都是1,那么它们都不是垃圾所以都不会被回收,但如果是这样的话,我们的代码就会出现问题。 + +我们删除了v1和v2,那么就没有任何变量指向这两个列表,那么这两个列表之后程序运行的时候都无法再使用,但是这两个列表的引用计数器都不为0,所以不会被当成垃圾进行回收,所以这两个列表就会一直存在在我们的内存中,永远不会销毁,当这种代码越来越多时,我们的程序一直运行,内存就会一点一点被消耗,然后内存变满,满了之后就爆栈了。这时候如果重新启动程序或者电脑,这时候程序又会正常运行,其实这就是因为循环引用导致数据没有被及时的销毁导致了内存泄漏。 + +### 1.5总结 + +#### 优点 + +* 简单 +* 实时性:一旦没有引用,内存就直接释放了。 不用像其他机制等到特定时机。实时性还带来一个好处:处理回收内存的时间分摊到了平时 + +#### 缺点 + +* 维护引用计数消耗资源 +* 循环引用 + 对于如今的强大硬件,缺点1尚可接受,但是循环引用导致内存泄露,注定python还将引入新的回收机制(标记清除和分代收集)。 + +## 二、标记清除 + +### 2.1引入目的 + +为了解决循环引用的不足,python的底层不会单单只用引用计数器,引入了一个机制叫做标记清楚。 + +### 2.2实现原理 + +在python的底层中,再去维护一个链表,这个链表中专门放那些可能存在循环引用的对象。 + +那么哪些情况可能导致循环引用的情况发生? + +就是那些元素里面可以存放其他元素的元素。(list/dict/tuple/set,甚至class) + +例如: + +![图片](data:image/png;base64,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lBI15ZwxM/q+pyZJTCYTuq4jxkhNOWfMjL7vqamUwng8pus6UkrUlHPGzOj7npokMZlM6LqOGCM15ZwxM/q+p6ZSCuPxmK7rSClRU84ZM6Pve2qSxGQyoes6YozUlHPGzOj7nppKKYzHY7quI6VETTlnzIy+76lJEpPJhK7riDFSU84ZM6Pve2oqpTAej+m6jpQSNeWcMTP6vqcmSUwmE7quI8ZITTlnzIy+76mplMJ4PKbrOlJK1JRzxszo+55Xo8E555xzzjnnnHPObbkG55xzzjnnnHPOObflGpxzzjnnnHPOOefclmtwzjnnnHPOOeecc1uuwTnnnHPOOeecc85tuQbnnHPOOeecc845t+UanHPOOeecc84559yWa3DOOeecc84555xzW67BOeecc84555xzzm25Buecc84555xzzjm35Rqcc84555xzzjnn3JZrcM4555xzzjnnnHNbrsE555xzzjnnnHPObbkG55xzzjnnnHPOObflGpxzzjnnnHPOOefclmtwzjnnnHPOOeecc1uuwTnnnHPOOeecc85tuQbnnHPOuf8PbGxscOedd3L06FEuWF1dZc+ePXz729/mxY4ePcqdd97JxsYGr8TGxgZ33nknf/EXf8HGxgbOOeecc7U0OOecc+5/hZWVFXbv3s3q6iovtr6+zm233cbDDz/MxsYGf/mXf8nq6ipbYX19ndtuu40777yTjY0NXq61tTWeeOIJ3vCGN3DB6173Oq644gr+9V//lYttbGxw+vRprrrqKlJKOOecc879NIilFC7HzJCEmVFKoSZJSKKUQk2SmDIzSinUJAlJlFKoycyQhJlRSqEmSUiilEJNkpgyM0op1CQJSZRSqMnMkISZUUqhJklIopRCTZKYMjNKKdQkCUmUUqjJzJCEmVFKoSZJSKKUQk2SmDIzSinUJAlJlFKoycyQhJlRSqEmSUiilEJNkpgyM0op1CQJSZRSqMnMkISZUUqhJklIopTC1Pr6OrfffjtPPfUUL7Zjxw6Wl5e5++67WVtb4yf5yEc+wk033UQphQvMjKlSCqUULlZKQRJmxne+8x0eeughHnroIT73uc9x/fXXs76+zu23385TTz3FpezYsYNbbrmFj33sY1zOjh07+MxnPsP8/DwXMzMkYWb8+7//O08++SQ33XQTbdtSSuHlOHPmDGtra/ziL/4i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+tKXePLJJ5l64IEHWF1d5WI7duxg165dfPOb32TPnj3Mz8/zch0+fJjFxUUWFxdZXFxkcXGRw4cP82ptbGxw5513sri4yOLiIouLixw7doyTJ0/ytre9jcXFRXbv3s3q6ioXW11d5ZZbbuHJJ59k3759LCwsMLVjxw6mvvvd77K+vs5tt93GI488wkMPPcTb3vY25ufncc4555x7JSLOOeec+6l17Ngx9u/fz80338yjjz7K3r17WVpa4lLm5+fZs2cPhw8f5s1vfjMrKyvccMMNLC0t8VL+5V/+heeee47du3czlVJiz549fPzjH2f37t0sLCzwYidOnODYsWMcOnSI6667juXlZU6cOMHy8jIXrK2t8cQTTzD1wAMPcN1117GwsMDLcejQIZaWlni1vva1r3H11VdzQUqJI0eOcOTIES44evQop0+f5uDBg6SUeLGHH36Yw4cPc8H27du5IKXEe9/7Xj7ykY+wtrbGrl27+PznP09KCeecc865/4kG55xzzv1Uefjhh7n55ptZW1vj937v9/j617/O9773Pa688kpuvfVWLucd73gHu3bt4nOf+xx/9Ed/xPLyMi9ldXWVBx54gH379rGwsMAFO3bsYOfOnTz44INsbGxwsRMnTvDJT36SvXv3srS0xMLCAvv27ePYsWOsrKwwtbKyws0338y+fft49NFH2blzJ3fddRfr6+tczmtf+1oeeOABlpaWeLVWVlb40pe+xOte9zr+J1ZXV9m9ezeHDx9m7969PPTQQ2zbto0X+z//5/9w6NAhtm3bxvve9z5SSjjnnHPO/U81OOecc+6nwvr6OrfddhtTKysrrKyssLS0xMbGBtu3b+euu+5ifn6ey0kp8e53v5tf+7Vf43LW19e56667eMc73sHS0hIXSylxxx138Oyzz/LAAw9wwdGjR/nEJz7BRz/6UZaXl7ngHe94B3v37uXqq6/m6NGj7N+/n/vvv5+lpSVSStxxxx1MHThwgPX1dTbbyZMnuf/++7n33nuZn5/nq1/9KqdPn+b48eNsbGzwkzz88MPcfPPN7Nu3j5WVFZaXl7mU1dVVPvKRj/Arv/IrHD16lOXlZR5++GGcc8455/6nGpxzzjn3U2F+fp4vfvGLLC0tcbGrrrqKI0eOsLCwwMuxuLjIBz/4Qebn57mUF154gU9/+tNs376dffv2cSnz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) + + +![图片](data:image/png;base64,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WC6X9H1PJnen6zr6vieTu9N1Hcvlkr7vyeTudF1H3/dkkoSZsVwu6fueTO5O13X0fU8md6frOpbLJX3fk8nd6bqOvu/JJAkzY7lc0vc9mdydruvo+55M7k7XdSyXS/q+J5O703Udfd+TSRJmxnK5pO97Mrk7XdfR9z2Z3J2u61gul/R9TyZ3p+s6+r4nkyTMjOVySd/3ZHJ3uq6j73syuTtd17FcLun7nkzuTtd19H1PJkmYGcvlkr7vyeTudF1H3/dkcne6rmO5XNL3PZncna7r6PueTJIwM5bLJX3fk8nd6bqOvu/J5O50XcdyuaTvezK5O13X0fc9mSRhZiyXS/q+J5O703Udfd+Tyd3puo7lcknf92Ryd7quo+97MiwopZRSSimllFLKuS0opZRSSimllFLKuS0opZRSSimllFLKuS0opZRSSimllFLKuS0opZRSSimllFLKuS0opZRSSimllFLKuS0opZRSSimllFLKuS0opZRSSimllFLKuS0opZRSSimllFLKuS0opZRSSimllFLKuS0opZRSSimllFLKuS0opZRSSimllFLKuS0opZRSSimllFLKuS0opZRSSimllFLKuS0opZRSSimllFLKuS0opZRSSimllFLKuS0opZRSSimllFLKuS0opZRSSimllFLKuS0opZRSSimllFLKufVmRhZ3RxJmRiZJSGKeZ8yMTO6OJMyMizDPM+5OJndHEmZGJklIYp5nzIxM7o4kzIyLMM8z7k4md0cSZkYmSUhinmfMjEzujiTMjIswzzPuTiZ3RxJmRiZJSGKeZ8yMTO6OJMyMizDPM+5OJndHEmZGJklIYp5nzIxM7o4kzIyLMM8z7k4md0cSZkYmSUhinmfMjEzujiTMjIswzzPuTiZ3RxJmRiZJSGKeZ8yMTO6OJMyMizDPM+5OJndHEmZGJklIYp5nzIxM7o4kzIyLMM8z7k4md0cSZkYmSUhinmfMjEzujiTMjIswzzPuTiZ3RxJmRiZJSGKeZ8yMTO6OJMyMizDPM+5OJndHEmZGJklIYp5nzIxM7o4kzIwMfUSQRRKSiAgyRQQbEUFEkEkSkogIskkiIui6jkySkEREkCki2IgIIoJMkpBERJBNEhFB13VkkoQkIoJMEcFGRBARZJKEJCKCbJKICLquI5MkJBERZIoINiKCiCCTJCQREWSTRETQ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0Frjlhs3bvDkk09ycHDA7u4upZRSSvmf1VNKKaW8Avb29jg8PORTuXHjBk899RSPP/44ly5dYsPMiAje85738LGPfYyLcnR0xP7+Pq997Wv5wAc+wKVLl/hkN27c4Mknn+Tg4IDd3V1uuXLlCm984xvZ39/nq77qq3jooYd4+9vfTkTwhV/4hTz88MMcHBywu7vLjRs3uHr1Khv33Xcf999/P88++yx33HEHly5dopRSSin/O/SUUkop/z91eHjIAw88wBNPPMHe3h7/Vbu7uzz99NPcuHGDq1ev8tM//dO8/vWv56WuXLnC5cuXefTRR9k4Ozvjueee45lnnuH69evccvXqVTbuvvtuvvu7v5sf+IEf4Pnnn+czuXr1Ki/n7rvv5qGHHqK1RimllFIuTk8ppZTyCjg6OmJ/f5/nn3+eT+euu+7iU7n77ru5CHt7exweHnJeV65c4cqVK5gZEcFncunSJd773vdyy+HhIQ8//DAHBwfs7u5yy9NPP82Gu3N8fMzOzg6tNc7Oznj00Uf5x3/8Rz7+8Y/zyCOPsLe3RymllFL+Z/WUUkopr4APfehDvPa1r+XXf/3XuXTpEp/sxo0bPPXUUzz++ONcunSJDTMjInjPe97Dxz72MT7bnZ2d8cgjj/D+97+fW65evcrGfffdx/3330+WJ598kr/8y7/k4OCAD33oQ/zJn/wJe3t7fLIXXniBt771rbzlLW9hb2+PUkoppVy8BaWUUsoFOzs749lnn+WOO+7g0qVL/Ffs7+/z2GOP0Vrjs1lrjXe+85380R/9EU888QS33347v/3bv83h4SH7+/tkOTg44Pr169x///3s7u7yDd/wDfz93/89R0dH3HJ4eMhdd93FHXfcwRd90RdRSimllFdGTymllHLBzs7OeO6553jmmWe4fv06n85dd93Fp3P33Xfz0EMP0Vrjc92NGzd417vexUtdvXqVW65du8aVK1e4xcx45zvfye/93u9x9913c/nyZTYuXbrEXXfdxdNPP83+/j4HBwdcv36da9euceXKFUoppZTyyukppZRSLtilS5d473vfy0sdHR2xv7/P888/zxve8AYef/xxLl26xIaZERGM48jBwQEf+9jH+Fx0dHTERz7yEb7u676OW65cucKVK1e45fDwkIcffpiDgwN2d3d5qaOjI/b39/nnf/5nNm677TZaa9xy+fJlHn30Ufb29rj99tv57d/+bXZ3dymllFLKK2tBKaWU8j/gxo0bXL16lfvvv59r167x6ZydnfGxj32M2267jdYan0s+/vGP8853vpNXv/rV/HecnZ3xjne8g+/4ju/g1a9+NU899RR33303L9Va4+1vfztveMMbuP/++9nd3aWUUkopr7ze3ckiCUm4O5kiAklEBO5OJklIwt3JJImNiMDdySQJSbg7mSICSUQE7k4mSUjC3ckkiY2IwN3JJAlJuDuZIgJJRATuTiZJSMLdySSJjYjA3ckkCUm4O5kiAklEBO5OJklIwt3JJImNiMDdySQJSbg7mSICSUQE7s5/xtHREQ8++CCvec1reP/738+lS5f4nd/5HSTh7rg7G5KQxCc+8Qn+8R//kS/8wi/E3fmd3/kdfvzHf5zzuu2223j88cfZ3d3l5UQEG+6Ou/NyJCGJiOD555/ngQce4Bd/8Rf56q/+aj74wQ/yzDPPcPvtt/Mt3/It7O7ucktEsOHuuDsbR0dHPPjgg7zxjW/k93//95mmiWEYkIQk3J2Ns7MzHnvsMb7927+dX/iFX+Cxxx7jT//0T3nHO95Ba43PRBKScHcySWIjInB3MklCEu5OpohAEhGBu5NJEpJwdzJJYiMicHcySUIS7k6miEASEYG7k0kSknB3MkliIyJwdzJJQhLuTqaIQBIRgbuTSRKScHcySWIjInB3MklCEu5OpohAEhGBu5NJEpJwdzJJYiMicHcySUIS7k6miEASEYG7k0kSknB3MvTHx8dkWa1WLBYLTk9PySSJiODk5ISu68i0Wq1YLBacnp6Sqes6WmucnJzg7mRarVYsFgtOT0/JJImI4OTkhK7ryLRarVgsFpyenpKp6zpaa5ycnODuZFqtViwWC05PT8kkiYjg5OSEruvItFqtWCwWnJ6ekqnrOlprnJyc4O5kWq1WLBYLTk9PySSJiODk5ISu68i0Wq1YLBacnp6Sqes6WmucnJzg7mRarVYsFgtOT0/JJImI4OTkhK7reDl/9Vd/xQ//8A+z8e53v5uv/MqvZJ5njo+PWa/XzPPMxz/+cT7+8Y/z8MMP83d/93fc8uVf/uV8y7d8C8fHx9x555387u/+Lv9dXdfRWuPf//3fcXeOj495Oev1GnfnhRde4Pj4mJezWq1YLBZ84AMfYOPBBx/k9a9/Pf/0T//Eb/zGb/Dggw+y8R3f8R28+93v5iu/8ivZeP3rX88v/dIvsXF8fMzG53/+5/NLv/RLbEzTRERwenqKmfGJT3yC4+NjfuVXfoU/+IM/4NFHH+VLvuRLWK/XvPWtb+X9738/b3rTm3jzm9/M937v9/JyVqsVi8WC09NTMnVdR2uNk5MT3J1Mq9WKxWLB6ekpmSQREZycnNB1HZlWqxWLxYLT01MydV1Ha42TkxPcnUyr1YrFYsHp6SmZJBERnJyc0HUdmVarFYvFgtPTUzJ1XUdrjZOTE9ydTKvVisViwenpKZkkERGcnJzQdR2ZVqsVi8WC09NTMnVdR2uNk5MT3J1Mq9WKxWLB6ekpmSQREZycnNB1HZlWqxWLxYLT01MydV1Ha42TkxPcnUyr1YrFYsHp6SmZJBERnJyc0HUdmVarFYvFgtPTUzL0Ozs7ZIkIJNFaI1NEcHJywvb2NqvVikwRgSRaa2Sb55nt7W26riNTRCCJ1hqZIoKTkxO2t7dZrVZkiggk0Voj2zzPbG9v03UdmSICSbTWyBQRnJycsL29zWq1IlNEIInWGtnmeWZ7e5uu68gUEUiitUamiODk5ITt7W1WqxWZIgJJtNbINs8z29vbdF1HpohAEq01MkUEJycnbG9vs1qt+FT+/M//nO///u/nm77pm/jABz5Aa42XGseR5XLJF3zBF7Czs8Mv//IvExFIYrlckm2eZ7a3t+m6js9kHEcWiwWf93mfx87ODi8nInjxxRd5zWtew3d+53fy5je/mY2nn36a1WrFt33bt9Fa45u/+Zv5wR/8Qf7mb/6GT+dHf/RHueeee9iICE5OTtje3ma1WvFbv/Vb/NZv/RY///M/z4MPPshLvfnNb+bNb34zTz/9NN/6rd/KN33TN/EjP/IjtNZ4qYhAEq01ss3zzPb2Nl3XkSkikERrjUwRwcnJCdvb26xWKzJFBJJorZFtnme2t7fpuo5MEYEkWmtkighOTk7Y3t5mtVqRKSKQRGuNbPM8s729Tdd1ZIoIJNFaI1NEcHJywvb2NqvVikwRgSRaa2Sb55nt7W26riNTRCCJ1hqZIoKTkxO2t7dZrVZkiggk0Voj2zzPbG9v03UdmSICSbTWyBQRnJycsL29zWq1IlNEIInWGhk6/QeSmBkRwTiOZHJ3jo+P2dnZobVGJjMjIhjHkUySmKaJ1hp935PJzIgIxnEkk7tzfHzMzs4OrTUymRkRwTiOZJLENE201uj7nkxmRkQwjiOZ3J3j42N2dnZorZHJzIgIxnEkkySmaaK1Rt/3ZDIzIoJxHMnk7hwfH7Ozs0NrjUxmRkQwjiOZJDFNE601+r4nk5kREYzjSCZ35/j4mJ2dHVprZDIzIoJxHNJfQ28AACAASURBVMkkiWmaaK3R9z2ZzIyIYBxHbjk7O+PRRx/l3nvvZW9vj/8Od+f4+Jh//dd/5Sd+4id45JFH2N3dJYOZERGM40gmSUzTRGuNvu/JZGZEBOM4ksndOT4+Zmdnh9YamcyMiGAcRzJJYpomWmv0fU8mMyMiGMeRTO7O8fExOzs7tNbIZGZEBOM4kkkS0zTRWqPvezKZGRHBOI5kcneOj4/Z2dmhtUYmMyMiGMeRTJKYponWGn3fk8nMiAjGcSSTu3N8fMzOzg6tNTKZGRHBOI5kksQ0TbTW6PueTGZGRDCOI5ncnePjY3Z2dmitkcnMiAjGcSRDTymllFIuTGuNxx57jAxf+qVfyq/+6q9SSimllM9OC0oppZRSSimllHJuC0oppZRSSimllHJuC0oppZRSSimllHJuC0oppZRSSimllHJuC0oppZRSSimllHJuC0oppZRSSimllHJuC0oppZRSSimllHJuC0oppZRSSimllHJuC0oppZRSSimllHJuC0oppZRSSimllHJuC0oppZRSSimllHJuC0oppZRSSimllHJuC0oppZRSSimllHJuC0oppZRSSimllHJuC0oppZRSSimllHJuC0oppZRSSimllHJuC0oppZRSSimllHJuC0oppZRSSimllHJuvZmRxd2RhJmRSRKSmOcZMyOTuyMJM+MizPOMu5PJ3ZGEmZFJEpKY5xkzI5O7Iwkz4yLM84y7k8ndkYSZkUkSkpjnGTMjk7sjCTPjIszzjLuTyd2RhJmRSRKSmOcZMyOTuyMJM+MizPOMu5PJ3ZGEmZFJEpKY5xkzI5O7Iwkz4yLM84y7k8ndkYSZkUkSkpjnGTMjk7sjCTPjIszzjLuTyd2RhJmRSRKSmOcZMyOTuyMJM+MizPOMu5PJ3ZGEmZFJEpKY5xkzI5O7Iwkz4yLM84y7k8ndkYSZkUkSkpjnGTMjk7sjCTPjIszzjLuTyd2RhJmRSRKSmOcZMyOTuyMJM+MizPOMu5PJ3ZGEmZFJEpKY5xkzI5O7IwkzI0MfEWSRhCQigkwRwUZEEBFkkoQkIoJskogIuq4jkyQkERFkigg2IoKIIJMkJBERZJNERNB1HZkkIYmIIFNEsBERRASZJCGJiCCbJCKCruvIJAlJRASZIoKNiCAiyCQJSUQE2SQREXRdRyZJSCIiyBQRbEQEEUEmSUgiIsgmiYig6zoySUISEUGmiGAjIogIMklCEhFBNklEBF3XkUkSkogIMkUEGxFBRJBJEpKICLJJIiLouo5MkpBERJApItiICCKCTJKQRESQTRIRQdd1ZJKEJCKCTBHBRkQQEWSShCQigmySiAi6riOTJCQREWSKCDYigoggkyQkERFkk0RE0HUdmSQhiYggU0SwERFEBJkkIYmIIEM/jiNZzIyIYBxHMrk76/WaYRhorZHJzIgIxnEkkySmaWIYBvq+J5OZERGM40gmd2e9XjMMA601MpkZEcE4jmSSxDRNDMNA3/dkMjMignEcyeTurNdrhmGgtUYmMyMiGMeRTJKYpolhGOj7nkxmRkQwjiOZ3J31es0wDLTWyGRmRATjOJJJEtM0MQwDfd+TycyICMZxJJO7s16vGYaB1hqZzIyIYBxHMklimiaGYaDvezKZGRHBOI5kcnfW6zXDMNBaI5OZERGM40gmSUzTxDAM9H1PJjMjIhjHkUzuznq9ZhgGWmtkMjMignEcySSJaZoYhoG+78lkZkQE4ziSyd1Zr9cMw0BrjUxmRkQwjiOZJDFNE8Mw0Pc9mcyMiGAcRzK5O+v1mmEYaK2RycyICMZxJJMkpmliGAb6vieTmRERjONIJndnvV4zDAOtNTKZGRHBOI5kksQ0TQzDQN/3ZDIzIoJxHMnk7qzXa4ZhoLVGJjMjIhjHkQwLSimllFJKKaWUcm4LSimllFJKKaWUcm4LSimllFJKKaWUcm4LSimllFJKKaWUcm49pZRPKSL44z/+Y/7qr/6KTBHBiy++yNbWFn3fk8ndkUTf92SSxM2bN+n7nsViQSZ3RxJ935MpInjxxRfZ2tqi73syuTuS6Pue/66v//qv52u/9mtZLBaUUj73RQR/9Ed/xOHhIZ+KuyOJvu/JJImbN2/S9z2LxYJM7o4k+r4nU0Tw4osvsrW1Rd/3ZHJ3JNH3PZkkcfPmTfq+Z7FYkMndkUTf93w6X//1X8/Xfu3XslgsKKV8dusppXxKf/EXf8E73vEO5nmmlGy/+Zu/yU/+5E/ypje9iVLK574PfvCD/NAP/RA3b96klGy/+Zu/yU/+5E/ypje9iVLKZ7cFpZRP6Y//+I+Z55lSLsLNmzc5PDyklPK/wx/+4R9y8+ZNSrkIN2/e5PDwkFLKZ7+eUspndO+9/4dXvWpFKef1iU/c5Kmn/oZSyv9e9977f3jVq1aUcl6f+MRNnnrqbyilfO7oKaV8Rq961Yq3ve3/Usp5/czP/D9KKf+7vepVK972tv9LKef1Mz/z/yilfG5ZUEoppZRSSimllHNbUEoppZRSSimllHNbUEoppZRSSimllHNbUEoppZRSSimllHNbUEoppZRSSimllHNbUEoppZRSSimllHNbUEoppZRSSimllHNbUEoppZRSSimllHNbUEoppZRSSimllHNbUEoppZRSSimllHPrJZFNEpkksSEJSVwESWSKCDYkIYmLIIlMktiQhCQugiQyRQQbkpBEKZ9LJCGJWyKCDUlI4iJIIpMkNiQhiYsgiUwRwYYkJHERJJFJEhuSkMRFkESmiGBDEpK4CJLIJIkNSUjiv0ISpVwkSUjiP0sSG5KQxEWQRKaIYEMSkrgIksgkiQ1JSOIiSCJTRLAhCUlcBElkksSGJCRxESSRoZ+miUySmKaJTJKICMwMdyebJKZpIpskzAwzI5skpmkikyQiAjPD3ckmiWmayCYJM8PMyOTulHKRbt68yTRNfDJJmBlmRjZJTNNEJklEBGaGu5NNEtM0kU0SZoaZkU0S0zSRSRIRgZnh7mSTxDRNZJOEmWFmZJPENE1kkkREYGa4O/8VN2/epJSLdPPmTaZp4j9LEhGBmeHuZJPENE1kk4SZYWZkk8Q0TWSSRERgZrg72SQxTRPZJGFmmBnZJDFNE5kkERGYGe5ONklM00SGvrVGlnmeiQiGYSBTRDBNE6vViq2tLTLN80xEMAwDmSRhZqxWK5bLJZnmeSYiGIaBTBHBNE2sViu2trbINM8zEcEwDGSShJmxWq1YLpdkWiwWlHKR+r6ntcYtkjAzVqsVy+WSTPM8ExEMw0CmiGCaJlarFVtbW/8fe3AbXFd5Hnr/f699r621LRtLcGIQb0UNSQQIQpGJ58B0ROKTg50mowlN07x0EncSnJYZxc2HTnsmsUrkcT60H1JH0w+QZMbOW9sESDwwtTIPplXT4x5IDDY1xDwxUUIMMj7CFpK2tZf2uq/redaHPaPx4Lf4Fvjl+v2IqSgKRIRqtUpMqkqe56RpSqVSIaaiKBARqtUqMYkI9XqdNE1pa2sjpqIoEBGq1SoxqSp5npOmKZVKhZiKokBEqFarxCQi1Ot10jSlra2NM+G9x5jF5L0nyzJOl4hQr9dJ05S2tjZiKooCEaFarRKTqpLnOWmaUqlUiKkoCkSEarVKTCJCvV4nTVPa2tqIqSgKRIRqtUpMqkqe56RpSqVSIaaiKBARqtUqMYkI9XqdNE1pa2sjpqIoEBGq1Sox+P8fsYQQcM7hvSemEALOOSqVCt57Ygoh4JzDe09Mqkqe51QqFbz3xBRCwDmH956YQgg456hUKnjviSmEgHMO7z0xqSp5nlOpVPDeE5NzDmMWU5IkeO9pUVXyPKdSqeC9J6YQAs45vPfEFELAOUelUsF7T0whBJxzeO+JSVXJ85xKpYL3nphCCDjn8N4TUwgB5xyVSgXvPTGFEHDO4b0nJlUlz3MqlQree2IKIeCcw3tPTCEEnHNUKhW895yJJEkwZjElSYL3ntMVQsA5R6VSwXtPTCEEnHN474lJVcnznEqlgveemEIIOOfw3hNTCAHnHJVKBe89MYUQcM7hvScmVSXPcyqVCt57Ygoh4JzDe09MIQScc1QqFbz3xBRCwDmH954YEowxxhhjjDHGGHPWEowxxhhjjDHGGHPWEowxxhhjjDHGGHPWEowxxhhjjDHGGHPWEowxxhhjjDHGGHPWEowxxhhjjDHGGHPWEoy5QBRFgTHGGHO6QgiICMYYY0wsCcZcIIqi4LOf/SxPPPEEr7/+OkVRYIwxxpzIa6+9xn333cfDDz/M0aNHmZ+fxxhjjDkbHmMuIM888wx79uyhs7OT7u5u7rjjDtasWcMVV1yBMcYYc7xf/vKXfOUrX2FkZIRrrrmGm266iT/4gz/g5ptvxhhjjDlTHmMuMKrKkSNHOHLkCLt37+Yf/uEfWLlyJe9///u5+eab+Z3f+R2q1SrGGGNMy8zMDM8//zzPP/88P/jBD3jXu97F3XffzcqVK7n22mtZtmwZxhhjzKl4jLnAiQhPPfUUTz31FFmWUavV+OhHP8of//Efs3z5cowxxpjjvfDCC7zwwgtUq1UuueQS7rrrLj7+8Y9z3XXXYYwxxpyIx5iLSKPRoNFo8MADD/DNb36Tm2++mZUrV7Jq1SpuvPFG2traMMYYY1rm5+eZnJzkoYce4oc//CHXX389t99+O7fffju33XYbS5YswRhjjGnxmLeUiPDv//7vPP3005yuEAKqiveemFSVubk5qtUq3nvOlnMOVaUUQkBV8d4Tk6pSFAWVSgUR4UwURcEzzzzDM888w9e//nXa29tZs2YNn/70p7n00ksxZrE9//zzfOtb36JFVZmfn8d7T6VSIaaiKFBV0jQlJhGhXq+TZRlpmhJTURSoKmmaEpOqMj8/j/eeSqVCTEVRoKqkaUpMIkK9XifLMtI0JaaiKFBV0jQlJlVlfn4e7z2VSoWYiqJAVUnTlLMxOzvL3NwcpyuEwAsvvMALL7zAd77zHZIk4b3vfS/33XcfzWYTY2ITUVrq9ToTExOoKqqKqlJSVVQVVUVVKakqRVFw9OhRli5dSrVaRVVRVVSVkqqiqqgqJVVFVVFVVJWSqqKqqCqqSklVmZ+fR0RI05SSqqKqqColVUVVUVVUlZKqoqqoKiVVRVVRVVSVkqoyNzdHmqY45yipKqqKqqKqlFQVVUVVaRERSiKCcw4RoSQiqCpFUSAieO8pqSolEaEkIpRUlZKqoqqUVBVVRVUREZxziAilEALHjh2jra2NSqWCqqKqlFQVVUVVKakqqsqdd97JypUrSZIEc+HxmLfU7t27+au/+iuKosC8ter1Og8//DD/8i//wlVXXYUxi+3pp5/m6aefxhhzfhIRdu7cyc6dO1m2bBktRSEYE8ORI3O0/PCHP+SHP/wh5vz3T//0T/zt3/4t/f39mAtPgnlL/eQnP6EoCsy5pVKp4JzDGGOMMcaYmIqiYPfu3ZgLk8ecM/7oj/6ILMs4lRACqor3nphUlbm5Odra2qhUKsQUQkBV8d4TW7PZpFKpoKp873vf47fV3t7OBz7wAf70T/+Ujo4ORkZG+MUvfoExi+W2227j93//92lRVebn5/HeU6lUiKkoClSVNE2JSUSo1+tkWUaapsRUFAWqSpqmxKSqzM/P472nUqkQU1EUqCppmhKTiFCv18myjDRNiakoClSVNE2JSVWZn5/He0+lUiGmoihQVdI05WzMzs7yj//4jxw7dozfRpIkvPe97+W+++7j+9//Pv/8z/9MyfsEY2J729vexlVXXUXJOUfJOUfJOUeLc46WZrNJmqYkSUKLc46Scw7nHCXnHAs552hxzlFyzlFyzhFCoOS9p+Sco+Sco+Sco8U5R8k5R8k5x/Gcc7SEEPDe45zDOUeLc46Sc46Sc46Sc46FnHOUnHOUnHOURARVxXtPyTlHyTlHyTlHyTmHquKco+ScwzlHyTnHQs45VJVGo0FbWxuVSgXnHCXnHKqKc46Sc45Go8EPfvADzIXNY84ZWZbxF3/xF5xKnueICLVajZhCCExOTrJ8+XKyLCOmPM8REWq1GjGpKvV6nSzLKIqC733ve5wu7z233nor73nPe7j99tvp6emhWq1izJvlxhtv5FOf+hQtqkq9XifLMrz3xJTnOSJCrVYjphACk5OTLF++nCzLiCnPc0SEWq1GTKpKvV4nyzK898SU5zkiQq1WI6YQApOTkyxfvpwsy4gpz3NEhFqtRkyqSr1eJ8syvPfElOc5IkKtVuNsHD58mB/96EccO3aM01GpVLj++uu5/fbbuf3227nttttYsmQJpTRNOVdNTTXYsGEH+/YdptTbu4ItW9bS0ZFxvO3b9/PIIz9ny5a1dHRknMz4+FEGB3fw5S/fRV/flbwZRkaeZOvWPbT09q5gy5a1dHRkHG98/CiDgzuYmJihZWion4GBHkqNRsGmTWOMjh6g1NW1jJGRtXR3d3Ku+G//bQktd999N1/4whc4XSEEJicnWb58OVmWEVOe54gItVqNmFSVer1OlmV474kpz3NEhFqtRkwhBCYnJ1m+fDlZlnEyf//3f4+58HmMuYgsWbKEpUuX8pGPfISPfOQjLF++HGOMMeZEqtUql1xyCXfddRcf//jHue666zhfrVt3K4ODqzheo1GwadMYo6MHKPX2ruBktm/fz/DwGG+mqakGGzbsYN++wyy0b99hVq/exoMPfoi+vitp2b59P8PDYxxveHiMp556mY0b+8kyz+bNq9m8eTXbt+/n619/GmOMOVseYy5wSZJw++23s3btWm666SauueYa0jTFGGOMOZF3vetd3H333axcuZJrr72WZcuWcSHavn0/w8NjlNasuZ6DB6c5kfHxowwO7mBiYobe3hVcffUljI4e4M3w4otH2LfvMA8++CH6+q6kZWTkSbZu3cMjj/ycm25aQZZ5Go2Cp556mTVrrmfjxn6yzFMaHz/K4OAORkcPcM89N9DXdyXGGBObz/OcWEIIqCp5nhOTqqKqFEVBnufEFEJAVcnznMVQFAUhBE4khEBLCIE8zzmVEAKqSp7nxKSqqCpFUZDnOTGFEFBV8jxnMRRFwfz8PCXnHJdeeind3d389//+31m9ejUrVqygRUTI85xTERGMWUwhBPI853hFURBCIKYQAqpKnufEpKqoKkVRkOc5MYUQUFXyPGcxFEVBCIGYQgioKnmeE5OqoqoURUGe58QUQkBVyfOcxVAUBSEEYgohoKrkec7ZmJ+fR1UpLV26lGuuuYabbrqJtWvXcsMNN7BQnuecTAiB81Vv7wq2bFlLacOGHZzKgw9+iL6+KxkZeZI3y2WXLWHnzk/T0ZGx0L339nHo0Cx7977KxMQM3d2dlD75yVu48ca3sVB3dydf/vJdrF//KLt2/Ya+vis5n4QQyPOc06WqqCpFUZDnOTGFEFBV8jxnMRRFQQiBmEIIqCp5nhOTqqKqFEVBnuecTAiBlhACeZ5zMiEEVJU8z1kMRVEQQiCmEAKqSp7nxKSqqCpFUZDnOTGFEFBV8jwnBi8ixKKqqCoiQkwiQklEEBFiUlVUFREhNlVFRHDOcSKqSouqIiKciqqiqogIMYkIJRFBRIhJVVFVRITYVBURQUS49dZb+djHPsbv/d7vkWUZlUqFkohgzLlGVRERFlJVRATnHDGpKqqKiBCTiFASEUSEmFQVVUVEiE1VERGcc8SkqqgqIkJMIkJJRBARYlJVVBURITZVRURwzhGTqqKqiAhnQ0S47rrr+MxnPkN/fz9ZlpHnOUuWLEFEOBOqyvloYKCHgYEeSlNTDU6mu7uTxx77BG+F667r4HRlmefGG9/GhUZVERFOl4hQEhFEhJhUFVVFRIhNVRERnHPEpKqoKiJCTCJCSUQQEU5GVWlRVUSEk1FVVBURITZVRURwzhGTqqKqiAgxiQglEUFEiElVUVVEhBh8rVYjljzPERFqtRoxhRCYnZ2lWq2SZRkx5XmOiFCr1YhJVanX61SrVbz3nIj3nhbvPbVajVPJ8xwRoVarEVMIgdnZWarVKlmWEVOe54gItVqNmFSVer1OtVqlWq3yzW9+k1iSJMGYxeS9p1ar0aKq1Ot1qtUq3ntiyvMcEaFWqxFTCIHZ2Vmq1SpZlhFTnueICLVajZhUlXq9TrVaxXtPTHmeIyLUajViCiEwOztLtVolyzJiyvMcEaFWqxGTqlKv16lWq3jviSnPc0SEWq3G2bjqqqt44IEHSJKEUgiByclJqtUqWZZxJrz3mDdfo1Fw8OA0l11Wo7OzxqkcPDhN6dprl3O+8d5Tq9U4XSEEZmdnqVarZFlGTHmeIyLUajViUlXq9TrVahXvPTHleY6IUKvViCmEwOzsLNVqlSzLOBnvPS3ee2q1GieT5zkiQq1WIyZVpV6vU61W8d4TU57niAi1Wo2YQgjMzs5SrVbJsoyY8jxHRKjVasSQYMwFwnuPMcYYc7oqlQpJkmDOX9/+9l727TvMPffcQEdHxsmMjx/l619/mt7eFfT3X4cxxiyGBGOMMcYYY84zIyNPsnXrHtatu5WBgR5OZnz8KIODOyjdf/9ddHRkGGPMYvAYY4wxxhhznhgfP8rg4A4mJmYYGupnYKCHkxkZeZKtW/fQ27uCLVvW0tGRYYwxi8VjjDHGGGPMeWD79v0MD4/R27uC73znHjo6Mk5kaqrBhg072LfvMEND/QwM9GCMMYstwRhz0Ws0Cr74xZ2MjDxJy/j4UT74we+xe/crHG9k5Em++MWdNBoFZ6LRKPjiF3fyxS/upNEoMMYYY07X9u37GR4eY2ion23bPkxHR8aJTE012LBhB6WdOz/NwEAPxhjzZkgwxlz0JiZm2Lv3Va69djktnZ01Lrusxq5dv2GhRqPg0KFZrrhiKVnmMcYYYxbb7t2vMDw8xtBQPwMDPZxMo1Hwd3/3vylt2bKWjo4MY4x5s3iMMRe9I0fmmJiY4eqrL6GloyNj5cor+dnPXmFqqkFHR0ZpYmKGvXtf5Z57buB4jUbBpk1jjI4e4FRGRw9wIr29K9iyZS0dHRnGGGMubo1GwSOP/Jze3hX091/HqTz33GFGRw8wNNRPR0eGMca8mTzGmIverl2/obd3BW9/+6UsdMcd1/DjH7/I0aNzfPvbe9m6dQ8t69c/ykJr1lzPxo39bN68ms2bV/NGGo2CTZvGKG3c2E+WeYwxxlzYRkae5Mc/fpGRkbV0d3dyphqNgoMHp9m37zCrV2/jRNatu5XBwVUcPDhNaXh4jOHhMd5IV9cyRkbW0t3diTHGxOQxxlzUpqYa/Oxnr7Bv32FWr95Gy4MPfohLL61RevbZVxkcXMW99/axadMYV1yxlMHBVRhjjDEn02gUHDo0y7vffTldXcswxpgLnccYc1F78cUjvPbaHA899FG6uztZaGqqwWWX1XjppdcpTUzMsHfvq9xzzw2MjDzJoUOzbNzYT5Z5jDHGnN86OjK2bfswp2twcBWDg6s4mUaj4ODBae655wayzPPb6OjI2Lbtw5yugYEeBgZ6MMaYt4LHGHPRajQKHnnk59x77210d3dyvI6OjG3bPkzLs8++ymWX1Xj72y9l167f8Eamphps2LCDffsOczKjowd4I11dyxgZWUt3dyfGGGPOby++eITXXpvjllsuxxhjLgYeY8xFa2JihqVLq8zNFfT1PUDLmjXXs3FjP1nmaWk0Cp566mVWrrySjo6ME+noyNi27cO8kUajYNOmMUobN/aTZR5jjDFvjq1b97B16x56e1ewZctaOjoyFtvBg9O8+92X09W1jHNNo1GwadMYo6MHKHV1LcMYY86Wxxhz0eru7uR//a/fp/R//2+dQ4dm2bixn9KmTWOMjh6g9OCDH+LSS2vs3fsq99xzA8YYY84fHR0Z27Z9mLfCwEAPAwM9nIuyzLN582o2b16NMcbE4jHGmONkmWfz5tV89rO3MTi4g9KRI3NMTMywfv2jLDQ6eoDS0FA/peHhMU7H6OgBTmZoqJ+BgR6MMcYYY4w5X3iMMeY09PVdye7dn6NlZORJDh2aZePGfrLM0zIw0MMbGR8/yuDgDrq7O5ieztmyZS0dHRnGGGOMMcZcKBKMMRet8fGjfPCD36Ov7wG2bt3D6OgB7rzzm/T1PcDu3a8Qy9RUg/vv/zfe/e7L2bTpfVx99SW8+OIRjrd79yt8+tM/ZGqqgTHGGGOMMecbjzHmotXd3cljj32C0sjIkxw6NMvGjf1kmac0Pn6UszU11WDDhh289toc999/Fx0dGffccwOPPPJzbrppBVnmKY2MPMnWrXv42tc+gDHGGGOMMecjjzHGnEKjEfjiF3cyOnqA442OHqDU1bWMkZG1dHd30jI+fpTBwR1MTMwwNNRPd3cnpZtuWsEjj/yc5547zNvffikbNuzgtdfmeOihj9Ld3Ykxxpgz12gUbNo0xt69rzIyspbu7k7OVSMjT7J16x5K69bdyuDgKowx5kLgMcaY4zz++C95+9s7acmyCps3r2bz5tW0jIw8yaFDs2zc2E+WeY63fft+hofHaLn66ktoyTLPZz97G4ODO5iYmGHNmut54IEPkWUeY4wxF65Go2DTpjFGRw9wIdm+fT+PPPJztmxZS0dHhjHm4uVDCMSiqqgqIQRiEhFUFREhhEBMqoqqEkIgJlWlJCKEEDgRVaVFRAghcCqqiqoSQiAmEUFVERFCCMSkqqgqIQRiUlVKIkIIgZhUlYvR7t0TfPvbe9myZS1Hj85xpsbHjzI4uIOJiRnWrbuVD37wnQwO7uB43d2dfPnLd/E3f/NvfPazt5FlnouNiBBCoEVVKYkIIQRiUlVUlRACMYkIqoqIEEIgJlVFVQkhEJOqUhIRQgjEpKqoKiEEYhIRVBURIYRATKqKqhJCICZVpSQihBCISVVRVUIIxCQiqCoiQgiBMyEimFObtHlI9AAAIABJREFUmJhh795X6e1dwZYta+noyFhsIyNP8uMfv8jIyFq6uzuJpdEo2LRpjNHRA5R6e1ewmESEEAKnS0RQVUSEEAIxqSqqSgiBmFSVkogQQiAmVUVVCSEQk4igqogIIQRORkRoUVVCCJyMqqKqhBCISVUpiQghBGJSVVSVEAIxiQiqiogQQiAmVUVVCSEQg5+cnCSWNE1JkoSZmRliUlVEhOnpaZxzxJSmKUmSMDMzQ0zOObIsY3p6mhACJzI3N0fL3Nwck5OTnEqapiRJwszMDDGpKiLC9PQ0zjliStOUJEmYmZkhJuccWZYxPT1NCIGYiqLgYjM6eoCDB6fZsmUtHR0Z3/72XiYmZnjkkZ9z000ryDLPyWzfvp/h4TGGhvoZGOihND5+lOONjx/lq1/9T4aH38fIyFoGB3dw7723MTDQw8Vkbm6OyclJWpxzZFnG9PQ0IQRiStOUJEmYmZkhJlVFRJiensY5R0xpmpIkCTMzM8TknCPLMqanpwkhEFOapiRJwszMDDGpKiLC9PQ0zjliStOUJEmYmZkhJuccWZYxPT1NCIGY0jQlSRJmZmaISVUREaanp3HOcSbm5uYwp3bkyBwTEzPcfffb6ejIWGyNRsGhQ7PEtn37foaHxyitWXM9Bw9Os9jm5uaYnJzkdKkqIsL09DTOOWJK05QkSZiZmSEm5xxZljE9PU0IgZjSNCVJEmZmZohJVRERpqencc5xMnNzc7TMzc0xOTnJyaRpSpIkzMzMEJNzjizLmJ6eJoRATGmakiQJMzMzxKSqiAjT09M454gpTVOSJGFmZoYY/PLly4lFRFBVsiwjJhFhenqa9vZ20jQlJhFBVcmyjNiKoqC9vR3nHCfS1tZGS1tbG8uXL+dURARVJcsyYhIRpqenaW9vJ01TYhIRVJUsy4itKAra29txzhFTpVLhYjE11eBnP3uFrq5l3H//XXR0ZIyPH+WnP32Zb3/7Hr773Wf53OceZcuWtXR0ZJQGB1dxvIGBHgYGejiRqakGGzbs4OqrL+Fv//Z/kmWejo6Mhx76KJs2jTE8PMaDD36Ivr4ruRi0tbWxfPlyFiqKgvb2dpxzxCQiqCpZlhGTiDA9PU17eztpmhKTiKCqZFlGbEVR0N7ejnOOmEQEVSXLMmISEaanp2lvbydNU2ISEVSVLMuIrSgK2tvbcc4Rk4igqmRZRkwiwvT0NO3t7aRpyploa2vDXFx6e1ewZctaShs27GCxtbW1sXz5ck6XiDA9PU17eztpmhKTiKCqZFlGbEVR0N7ejnOOmEQEVSXLMmISEaanp2lvbydNU06mra2Nlra2NpYvX87JiAiqSpZlxFYUBe3t7TjniElEUFWyLCMmEWF6epr29nbSNCUmEUFVybKMGHyWZcSS5zkiQpZlxBRCwDlHmqZkWUZMeZ4jImRZRkyqSlEUpGmK954TqVQqtHjvybKMU8nzHBEhyzJiCiHgnCNNU7IsI6Y8zxERsiwjJlWlKArSNMV7T0xJknCxaDQKli9v4/OfX0V3dyeNRsE3vvE0f/iHN3LjjW9j8+bV7N79CqtXb+NEurqWMTKylu7uTt7I+vWP0tu7gi1b1tLRkbFQlnk2b17Nxo39bNo0xvr1jzI01M/AQA8XMu89WZbRoqoURUGapnjviSnPc0SELMuIKYSAc440TcmyjJjyPEdEyLKMmFSVoihI0xTvPTHleY6IkGUZMYUQcM6RpilZlhFTnueICFmWEZOqUhQFaZrivSemPM8REbIsI6YQAs450jQlyzLOhPeexTI11WDDhh3s23eYlt7eFWzZspaOjowTmZpqsGHDDvbtO0ypt3cFW7aspaMj40xs376f4eExhob6ueWWyxkc3MHExAwPPvgh+vqupNRoFGzaNMbo6AFa1q27lcHBVZTGx48yOLiDiYkZSlu37mHr1j10dS1jZGQt3d2dlKamGmzYsIN9+w7TMjTUz8BAD6Xt2/czPDzG0FA/d999PZs2jTE6eoBSb+8KtmxZS0dHRmlk5Em2bt1Dy0c+8n1K69bdyuDgKs7GwEAPAwM9lKamGrwZvPdkWcbpCiHgnCNNU7IsI6Y8zxERsiwjJlWlKArSNMV7T0x5niMiZFlGTCEEnHOkaUqWZZyM956WSqVClmWcTJ7niAhZlhGTqlIUBWma4r0npjzPERGyLCOmEALOOdI0JcsyYsrzHBEhyzJi8BhjLnpXXLGUr33tA7RMTMwwM5PT338dLX19V7J79+c4U88++yrvfvflPPTQR8kyz8lkmWfz5tVs3rwaY4wxsH37foaHxzjevn2HWb16G0ND/QwM9HC8F188yt///Q4mJmZo2bfvMH/yJ48wMrKW7u5OztRrr81x//3/xsTEDAuNjx9lcHAHExMzLLR16x4OHZpl48Z+Tsfu3a+wfv2jHO/rX3+aW265nO7uTlrm5go2bRpjdPQALfv2HWbDhh1s2bKWjo4MY4x5K3iMMeY43d2dfO1rHyCGgYEeBgZ6MMYYc2Z2736F4eExSkND/QwM9NCyfft+hofH+PrXn+aWWy6nu7uTlomJGf7qr/4fhob6GRjoodRoFGzaNMbo6AG+8Y2n2bixnyzznIl/+IenWLfuVrZt+zAtjUbBN77xNBMTMzz44Ifo67uSUqNRsGnTGKOjB3jPe65iYKCHxx77BLt3v8L69Y+ybt2tDA6uomV8/Ch/8zf/RmndulsZHFxFy+OP/5Lj/d3f/W/WrbuV3bs/R2l8/CiDgzvYt+8wY2O/YmCgh8HBVdx7bx+bNo2xd++rjIyspbu7k4W2b9/P8PAYpzI01M/AQA/GGHMqHmOMMcYYc87Ztes3lIaG+hkY6GGhgYEeXnrpdbZu3cOzz75Kd3cnCw0N9TMw0ENLlnn+8i/v5ODBafbufZWJiRm6uzs5E2vWXM+99/ax0HPPHWZ09ABDQ/309V1JS5Z5PvvZ29i791Veeul1TuWxx/5fJiZmGBrqZ2Cgh4X+x//4XY63Zs313HtvHy3d3Z3ce+9tDA+P8dJLr3O6BgZ6GBjowRhjYvEYY4wxxphzytRUg5/97BV6e1fQ338db+SOO65h69Y9vPTS6yzU1bWMW265nON1dGSsXHklW7fu4ciRObq7OzkT73nPVWSZZ6Fdu35DaXh4jOHhMd7IoUOzNBoFWeZ5I41GwaFDs/T2rqC//zpOx3vecxVZ5lno6qsvwRhj3moJxhhjjDHmvHPppTW6upZxvms0Cg4enOZsXXppja6uZRhjzFvJY4wxxhhjzjtHjswxMTHD6Wo0Cg4dmqWraxmXXlojpgcf/BB9fVdyvtm+fT/Dw2OcytBQPwMDPRhjzKl4jDHGGGPMOaWjI2PlyivZunUPY2O/YmCgh+Pt2vUbStdeu5yFJiZmOHJkju7uThaamJhh795XueyyGp2dNWK49trllHbt+g19fVfy28gyz9VXX8Lo6AHGxn7FwEAPb5aBgR4GBnowxphYEowxxhhjzDnnjjuuoTQ8PMb27ftZaPv2/Wzduofe3hX091/H8davf5Tdu1+hZWqqwf33/xsTEzOsXHklHR0ZMfT3X0dv7wq2bt3DyMiTLDQ11eDzn/8XxsePcjJZ5rnnnhsoDQ+PsX37fhZ6/PFfMj5+lLMxMTHDkSNzGGPMYvMYY4wxxphzTl/flQwN9TM8PMbw8BjDw2Ms1NW1jPvvv4uOjoyFurqW8Sd/cgvr1z/K8dasuZ577+0jlo6OjM9/fhXr1z/K1q172Lp1Dwt1dS3jdPT1Xcm6dbeydesehofHGB4eo6WraxkjI2v5bWSZ54orllJav/5RSuvW3crg4CoudqpKyTmHMSaeBGOMMcYYc04aGOjhoYc+SlfXMhZas+Z6Hnroo3R3d/JGVq26igcf/BALrVt3K5s3rybLPDH19V3Jzp2fprd3BQv19q7gO9+5h+7uTk7H4OAqHnroo3R1LWOhe++9je7uTn5b997bx5o112OgKAqOHTvGAw88wIYNGzDGxOcxxhhzQZidnWXp0qUYYy4s3d2dPPbYJziVLPNs3ryalu7uTnbv/hxna2Cgh4GBHk6moyNj27YPcyp9fVeye/fnOJHu7k4ee+wTnMjAQA8DAz28ke7uTh577BMcL8s8mzevZvPm1SyGjo6Mbds+zLlKRPjZz37Gv/7rv/Lss8/yi1/8gmazyc0334wxJj6PMcaY85KI0Gg0ePnll3n44Ye59NJLWb9+PcYYYy5eqsrrr7/Ob37zG3784x+zc+dODh8+jDHmzeExxhhzXpmfn+cnP/kJO3fuZP/+/bzyyis0m00+9alPYYwx5uL1zDPP8PDDD/PMM89w5MgR5ufnMca8uTzGGGPOeYcOHeLXv/41jz/+ODt37uT111/HGGPMxe3IkSM8//zzPPnkk/zHf/wHL730EsaYt5bHGGPMOeuJJ57gu9/9Li+++CL1eh0RwRhjztbUVIMNG3awb99hTqS3dwVbtqyloyPDnDtEhF/+8pc8+OCD7Ny5k9+WqiIiJEnCmVJVVBVVJSZVRVVRVVSV0+Wcw5hzhceYC5SqUhQFIQSKoiCEQFEUhBAoioKiKAghUBQFIQSKoqAoCkIIFEXBxMQExryZVJWDBw/y3HPP8dOf/pSnn36a1157DWOMia2jI2Pbtg9jzh/j4+N86Utf4rnnnuOll17ibL344ot86lOfwjnHmRIRSkmSEJOqIiIkSYJzjtNx2WWXMTw8zPLlyzHmXOAx5k0SQmDfvn3s37+foihoNps0m02azSbNZpOiKGg2mzSbTYqiYH5+nqIoaDabNJtNiqKg2WzSbDZpNps0m02azSbz8/OEEGg2mzSbTZrNJkVRICIYc65rNpscO3aMn/70p3z3u9/l2Wef5beV5znT09O8kTzPERGazSbHU1XOlKpSEhGmp6cpNRoNTpeqcip5niMiNBoNWlSV34aq0qKqHDt2jLa2Nrz3nIqqcrryPEdVybIMVeWNqCqqSouqUlJVVJUWEaGkqoQQOHLkCNPT01SrVVSVkqpSUlVUFVWlpKqoKi2qiqqiqrSoKqrK/Pw8IkK1WqWkqpRUFVVFVSmpKiVVpaSqlFQVVaUkIrSoKnNzc6RpSpIktKgqqoqqoqq0qCqqiqpSUlVKqkpJVVFVVJWiKBAR0jRFVSmpKiVVRVVRVUqqSouqoqqoKi2qiqqiqogIMzMz1Go1vPeUVBVVRVUpqSolVUVVUVVKP//5zzFmMdXrdSYnJ3n99deJYW5ujv3793MheOihh/jMZz6DMecCjzFvkn379vGFL3yB+fl5jDGwb98+/uzP/oyXXnqJI0eOcLYeffRRnnjiCVpUlRZVpeScQ1VZSFU5nqryRlSVhVQVVaXknKOkqhxPVTmeqnI8VaVFVSk551BVFlJVFlJV3oiqcjxV5XiqykKqyvFUleOpKsdTVd6IqmKMMb+t3t5e7rvvPiYnJ3nuuef42te+xsTEBAampqYw5lzhMeZNMjY2xvz8PIspSRKSJCFJEpIkwTlHpVLBOUeSJCRJQpIkJEmCc45KpYJzjiRJSJKEJElIkgTnHK+99hpTU1MYc744duwYx44dwxhjzIWpra2Nq666iquuuop3vvOdTE5OsnfvXvbu3csLL7zA5OQkp+ud73wnX/nKV3DOcabm5+cREbIsIyZVZW5ujra2NiqVCiezfft2vvWtb2HMucbneU4sIQRUlTzPiUlVUVWKoiDPc2IKIaCq5HnOYiiKghACJxJCoCWEQJ7nnEoIAVUlz3NiUlVUlaIoyPOcmEIIqCotH/vYx1i2bBlpmuK9J01TvPekaUqaplQqFarVKpVKhWq1SqVSoVqt4r3He0+apnjvSdOUUq1WI01TkiThdDjnOJWRkRG+//3vY8xiueGGG/jzP/9z6vU6u3fv5ktf+hIXI+cczjlKzjlKzjmcc7Q453DO4Zyj5Jyj5Jyj5JzDOYdzDlXFOYdzDuccJeccJeccJecczjmcc6gqzjmcczjnKDnnKDnnKDnncM7hnENVcc7hnMM5R8k5R4tzDucczjmcc7Q453DOUXLOUXLOUXLO4ZzDOUeLcw7nHCXnHCEEKpUKzjmcczjncM7R4pyjlCQJJeccJeccJecczjmcc6gqzjmcc7QkSULJOUfJOYdzjhbnHM45nHOUnHOUnHOUnHM452hxzqGqJEmCcw7nHCXnHCXnHM45WpxzOOdwzlFyzlFyzlFyzlFyzqGqlCqVCs45Ss45Ss45Ss45SkmS0OKcwzlHyTlHyTlHyTlHaX5+nmq1SpIkOOdwzuGco+Sco8U5h3MO5xylXbt2sXfvXoxZLCEE8jynpauri66uLm6++WY++clPEkLgP//zP/nWt77Fc889x6mkaUpXVxfOOc5UCAFVxXtPbM1mE+89zjlOpigKWkII5HnOyYQQUFXyPCcmVUVVKYqCPM85mRACLSEE8jznZEIIqCp5nrMYiqIghEBMIQRUlTzPiUlVUVWKoiDPc2IKIaCq5HlODF5EiEVVUVVEhJhEhJKIICLEpKqoKiJCbKqKiOCc40RUlRZVRUQ4FVVFVRERYhIRSiKCiBCTqrJQkiR8+tOfJoaiKKhUKjjniMk5hzGLSVVJkoRly5Zx11138aMf/YiJiQl+8YtfsGfPHvbs2cORI0c4XX/4h3/IZz7zGZxzlJxzqCrOOUSEUqVSYSHnHCXnHC3OOVqccyzknKPknKMkIszOzrJkyRLSNMU5x0LOOUrOORZyznEqIoKqUqlUiK0oCiqVCs45YhIRVJVKpUJMIsLMzAxLliwhTVNiEhFUlUqlQmxFUVCpVHDOEZOIoKpUKhViEhFmZmZYsmQJaZpyJo4ePcrevXsxZrGoKiLCiSRJwp133skdd9zByy+/zH/913+xa9cunn76aV5//XXeiIjgnONMqSqqiogQm6oiIjjnOF2qiohwMqqKqiIixCQilEQEEeFkVJUWVUVEOBlVRVUREWJTVUQE5xwxqSqqiogQk4hQEhFEhJhUFVVFRIjB12o1YsnzHBGhVqsRUwiB2dlZqtUqWZYRU57niAi1Wo2YVJV6vU61WsV7z4l472nx3lOr1TiVPM8REWq1GjGFEJidnaVarZJlGTHleY5zjhbvPbVajbOlqtTrdarVKt57YkqSBGMWk/eeWq1Gy9VXX01nZye33XYbn/zkJyk98cQTfPe73+XFF1+kXq8jIpxIe3s7l19+OW8kz3NEhFqtRkwhBPI8Z8mSJWRZRkx5niMi1Go1YlJV6vU61WoV7z0x5XmOiFCr1YgphMDs7CzVapUsy4gpz3NEhFqtRkyqSr1ep1qt4r0npjzPERFqtRoxhRCYnZ2lWq2SZRlnwnuPMYvJe0+tVuN0vOMd7+B3f/d3ufPOO1m6dCm7du3iBz/4Ab/61a84evQoIkKSJNRqNZxznKk8zxERarUaMakq9XqdarWK956T8d7T4r2nVqtxMnmeIyLUajViCiEwOztLtVolyzJOxntPi/eeWq3GyeR5johQq9WISVWp1+tUq1W898SU5zkiQq1WI6YQArOzs1SrVbIsI6Y8zxERarUaMXiMMcacs973vvfxvve9j0OHDvHrX/+axx9/nJ07d/L6669jjDHGnEqlUuH9738/73//+zl8+DATExM8+uijTExMYIyJz2OMMeacd8UVV3DFFVewatUq/vIv/5Kf/OQn7Ny5k/379/PKK6/QbDYxxhhjTmbFihWsWLGCd7/73agqxpj4PMYYY84r1WqV1atX8973vpdGo8HLL7/Mww8/TK1WwxhjjDkdzjmMMfF5jDHGnJeSJGHJkiW84x3v4K//+q+ZnZ3FGGOMMca8dRKMMcZcEJYuXYoxxhhjjHnrJBhjjDHGGGOMMeasJRhjjDHGGGOMMeasJRhjjDHGGGOMMeasJRhjjDHGGGOMMeasJRhjjDHGGGOMMeasJRhjjDHGGGOMMeasJRhjjDHGGGOMMeasJRhjjDHGGGOMMeasJRhjjDHGGGOMMeasJRhjjDHGGGOMMeasJRhjjDHGGGOMMeasJRhjjDHGGGOMMeasJRhjjDHGGGOMMeasJRhjjDHGGGOMMeaseVUlNlUlJlWlpKqoKotBVYlJRCipKqrK6VBVVJXTparEpKqUVBVVZTGpKqrK2RIRSqqKqrJYjh1r8tWv/h+MOVvHjjVpUVVUlRYRoaSqqCqLQVWJSVUpqSqqymJQVWISEUqqiqqyGFSVmFSVkqqiqiwGVSUmEaGkqqgqi0FViUlVKakqqsqZUFVajh1r8tWv/h+MOVvHjjVpUVVUldOlqpRUFVVlMagqMYkIJVVFVTkZVWUhVeV0qCoxqSolVUVVORlVZSFV5XSoKjGJCCVVRVVZDKpKTKpKSVVRVRaDqhKDr9frxKSq1Ot1YlJVRIQ8zwkhEJuqUq/XiU1VyfOcPM85kWazSUuz2aRer3M6VJV6vU5MqoqIkOc5IQRiExFams0m9XqdGFSVPM/J85yYQgi0PPLI8xgTW7PZpF6vs5Cqkuc5eZ4Tm6pSr9eJSVUREfI8J4RAbKpKvV4nNlUlz3PyPCc2VaVerxOTqiIi5HlOCIHYVJV6vU5sqkqe5+R5TmyqSr1eJyZVRUTI85wQAmei2WzS8sgjz2NMbM1mk/+PPTjGsaXpyrR9R+zIrEiVcZgAgwAJHPQhDMaBw1hwGAUGNowEC4kxYJS1d6WOQifXev4uoyTU4q3363+vQt3Sc13nefLHkkRmstYiIqgmifM8qSaJtRZrLb7y69cvPv369YvzPPk9kjjPk0qSyEzWWkQEX/n16xeffv36xXme/B5JnOdJNUmstVhrUU0S53lSSRKZyVqLiKCaJM7zpMKYc1Llui4yk33fqZSZnOfJtm28vLxQ6bouMpN936kkibUW27Zxu934LbfbjU9jDOac/J7rushM9n2nUmZynifbtvHy8kKl67rovfNpjMGck2dJYq3Ftm3cbjcq/eEPf+Bf/uVfuK4Ls2rbtvGXf/mXzDn5JIm1Ftu2cbvdqHRdF5nJvu9UykzO82TbNl5eXqh0XReZyb7vVJLEWott27jdblS6rovMZN93KmUm53mybRsvLy9Uuq6LzGTfdypJYq3Ftm3cbjcqXddFZrLvO5Uyk/M82baNl5cX/k/8zd/8Df/6r//Kr1+/MKu2bRt/+Zd/yZyTP1Zmcp4n27bx8vJCpeu6yEz2faeSJNZabNvG7XbjK2MMPt1uN+acfOW6LjKTfd+plJmc58m2bby8vPCVMQafbrcbc06+cl0Xmcm+71SSxFqLbdu43W5Uuq6LzGTfdyplJud5sm0bLy8vVLqui8xk33cqjP+FKhFBa40xBpUigtYat9uNMQaVIoLWGmMMKklircXtdmOMwW/pvfOp984Yg98TEbTWGGNQKSJorXG73RhjUCki+K9674wxeJYk1lrcbjfGGFT6sz/7M/7hH/6Bf//3f6dSZvLz509eXl4YY1ApIpDEGINKkvj16xdjDHrvVIoIJDHGoFJm8vPnT15eXhhjUCkikMQYg/+//vCHP/Dnf/7n9N75JIm1FrfbjTEGlSKC1hpjDCpFBK01brcbYwwqRQStNcYYVJLEWovb7cYYg0oRQWuNMQaVIoLWGrfbjTEGlSKC1hpjDCpJYq3F7XZjjEGliKC1xhiDShFBa43b7cYYg/8Tf/EXf8E//uM/8m//9m/8dyICSYwxqCSJX79+Mcag906liEASYwwqZSY/f/7k5eWFMQaVIgJJjDGoJIlfv34xxqD3TqWIQBJjDH7LH/7wB/78z/+c3jt/rIigtcbtdmOMQaWIoLXGGINKklhrcbvdGGPwld47n3rvjDH4SkTQWmOMQaWIoLXG7XZjjMFXeu986r0zxuArEUFrjTEGlSSx1uJ2uzHGoFJE0FpjjEGliKC1xu12Y4xBpYigtcYYgwoDM/tv9d75q7/6K/72b/+WShHB29sbP378YM5JpbUWmclxHFSSxHmezDkZY1BprUVmchwHlSKCt7c3fvz4wZyTSmstMpPjODAz+9B756//+q/567/+a/47ay0yk+M4qCSJ8zyZczLGoNJai8zkOA4qRQRvb2/8+PGDOSeV1lpkJsdxUEkS53ky52SMQaW1FpnJcRyY2f/7OmZmZmZmZmb2tI6ZmZmZmZmZPa1jZmZmZmZmZk/rmJmZmZmZmdnTOmZmZmZmZmb2tI6ZmZmZmZmZPa1jZmZmZmZmZk/rmJmZmZmZmdnTOmZmZmZmZmb2tI6ZmZmZmZmZPa1jZmZmZmZmZk/rmJmZmZmZmdnTOmZmZmZmZmb2tI6ZmZmZmZmZPa1jZmZmZmZmZk/rmJmZmZmZmdnTOmZmZmZmZmb2tI6ZmZmZmZmZPW2stagSEUhirUUlSUjiui7WWlSKCCSx1uI7XNdFRPBbIoJPEcFai98TEUhirUUlSUjiui7WWlSKCCTx6bou1lpUua6LiKBSRCCJtRaVJCGJ67pYa1EpIpDEWovvcF0XEUGliEASay0qSUIS13Wx1qJSRCCJtRbf4bouIoJKEYEk1lpUkoQkrutirUWliEASay2+w3VdRASVIgJJrLWoJAlJXNfFWotKEYEk1lp8h+u6iAgqRQSSWGtRSRKSuK6LtRaVIgJJrLX4Dtd1ERFUiggksdaikiQkcV0Xay0qRQSSWGvxHa7rIiKoFBFIYq1FJUlI4rou1lpUiggksdbiO1zXRUTwleu6+BQRrLX4SkQgibUWlSQhieu6WGvxlYjgU0Sw1uIrEYEk1lp8h+u6iAgqRQSSWGtRSRKSuK6LtRaVIgJJrLWoMDKTKpKQRGZSKTP5kJlkJpUkIYnMpJokMpPWGr9FEp8kkZn8HklIIjOplJl8yEwyk0qS+N9lJhUkkZm01qgkCUlkJpUykw+ZSWZSSRKSyEyqSSIzaa1RSRKSyEy14DwaAAAgAElEQVQqZSYfMpPMpJIkJJGZVJNEZtJao5IkJJGZVMpMPmQmmUklSUgiM6kmicyktUYlSUgiM6mUmXzITDKTSpKQRGZSTRKZSWuNSpKQRGZSKTP5kJlkJpUkIYnMpJokMpPWGpUkIYnMpFJm8iEzyUwqSUISmUk1SWQmrTUqSUISmUmlzORDZpKZVJKEJDKTapLITFpr/LEkkZl8RRKSyEwqZSYfMpPM5CuS+CSJzOQrkpBEZlJNEplJa41KkpBEZlIpM/mQmWQmlSQhicykwjiOgyprLTKT4zioFBG8v7+z7ztzTiqttchMjuOgkiTO82Tfd8YY/JYxBp/GGBzHwe9Za5GZHMdBpYjg/f2dfd+Zc1JprUVrjU9jDI7j4FmSOM+Tfd8ZY1BprUVmchwHlSKC9/d39n1nzkmltRaZyXEcVJLEeZ7s+84Yg0prLTKT4zioFBG8v7+z7ztzTiqttchMjuOgkiTO82Tfd8YYVFprkZkcx0GliOD9/Z1935lzUmmtRWZyHAeVJHGeJ/u+M8ag0lqLzOQ4DipFBO/v7+z7zpyTSmstMpPjOKgkifM82fedMQaV1lpkJsdxUCkieH9/Z9935pxUWmuRmRzHQSVJnOfJvu+MMai01iIzOY6DShHB+/s7+74z56TSWovM5DgOKkniPE/2fWeMQaW1FpnJcRxUigje39/Z9505J5XWWmQmx3FQSRLnebLvO2MMvjLG4NMYg+M4+Mpai8zkOA4qRQTv7+/s+86ck6+MMfg0xuA4Dr6y1iIzOY6DSpI4z5N93xljUGmtRWZyHAeVIoL393f2fWfOSaW1FpnJcRxU6JiZmZmZmZnZ0zpmZmZmZmZm9rSOmZmZmZmZmT2tY2ZmZmZmZmZP65iZmZmZmZnZ0zpmZmZmZmZm9rSOmZmZmZmZmT2tY2ZmZmZmZmZP65iZmZmZmZnZ0zpmZmZmZmZm9rSOmZmZmZmZmT2tY2ZmZmZmZmZP65iZmZmZmZnZ0zpmZmZmZmZm9rSOmZmZmZmZmT2tY2ZmZmZmZmZP65iZmZmZmZnZ0zpmZmZmZmZm9rSOmZmZmZmZmT1tRARVJCGJiKBSZiKJzCQiqCQJSUQElSTxITOJCH6LJD5lJhHB75GEJCKCSpmJJDKTiKCSJP6rzCQieJYkPmQmEUElSUgiIqiUmUgiM4kIKklCEhFBJUl8yEwigkqSkEREUCkzkURmEhFUkoQkIoJKkviQmUQElSQhiYigUmYiicwkIqgkCUlEBJUk8SEziQgqSUISEUGlzEQSmUlEUEkSkogIKkniQ2YSEVSShCQigkqZiSQyk4igkiQkERFUksSHzCQiqCQJSUQElTITSWQmEUElSUgiIqgkiQ+ZSURQSRKSiAgqZSaSyEwigkqSkEREUEkSHzKTiOArmcknSUQEX5GEJCKCSpmJJDKTiOArmcknSUQEX5GEJCKCSpL4kJlEBJUkIYmIoFJmIonMJCKoJAlJRAQVxtvbG1W2baP3zuPxoJIkMpP7/U5rjUrbttF75/F4UKm1xpyT+/1ORPBbfv78yaefP3/y9vbG79m2jd47j8eDSpLITO73O601Km3bRkTw6efPn7y9vfGs1hpzTu73OxFBpW3b6L3zeDyoJInM5H6/01qj0rZt9N55PB5Uaq0x5+R+vxMRVNq2jd47j8eDSpLITO73O601Km3bRu+dx+NBpdYac07u9zsRQaVt2+i983g8qCSJzOR+v9Nao9K2bfTeeTweVGqtMefkfr8TEVTato3eO4/Hg0qSyEzu9zutNSpt20bvncfjQaXWGnNO7vc7EUGlbdvovfN4PKgkiczkfr/TWqPStm303nk8HlRqrTHn5H6/ExFU2raN3juPx4NKkshM7vc7rTUqbdtG753H40Gl1hpzTu73OxFBpW3b6L3zeDyoJInM5H6/01qj0rZt9N55PB5Uaq0x5+R+vxMRfOXnz598+vnzJ29vb3xl2zZ67zweDypJIjO53++01vjKz58/+fTz50/e3t74yrZt9N55PB5Uaq0x5+R+vxMRVNq2jd47j8eDSpLITO73O601Km3bRu+dx+NBhfHjxw+qZCaSmHNSKTO53++8vr6ybRuVMhNJzDmpdl0Xr6+vtNb4LS8vL3x6eXnhx48f/J7MRBJzTiplJvf7ndfXV7Zto1Jm0nvn08vLCz9+/KDCdV28vr7SWqNSZiKJOSeVMpP7/c7r6yvbtlEpM5HEnJNq13Xx+vpKa41KmYkk5pxUykzu9zuvr69s20alzEQSc06qXdfF6+srrTUqZSaSmHNSKTO53++8vr6ybRuVMhNJzDmpdl0Xr6+vtNaolJlIYs5Jpczkfr/z+vrKtm1UykwkMeek2nVdvL6+0lqjUmYiiTknlTKT+/3O6+sr27ZRKTORxJyTatd18fr6SmuNSpmJJOacVMpM7vc7r6+vbNtGpcxEEnNOql3XxevrK601KmUmkphzUikzud/vvL6+sm0blTITScw5qXZdF6+vr7TW+MrLywufXl5e+PHjB1/JTCQx56RSZnK/33l9fWXbNr7y8vLCp5eXF378+MFXMhNJzDmpdl0Xr6+vtNaolJlIYs5Jpczkfr/z+vrKtm1UykwkMeekwphzUmWtRWYy56RSRNBaY9s25pxUWmuRmcw5qSSJ67rYto0xBr/ldrvxaYzBnJPfs9YiM5lzUikiaK2xbRtzTiqttWit8WmMwZyTZ0niui62bWOMQaW1FpnJnJNKEUFrjW3bmHNSaa1FZjLnpJIkruti2zbGGFRaa5GZzDmpFBG01ti2jTknldZaZCZzTipJ4routm1jjEGltRaZyZyTShFBa41t25hzUmmtRWYy56SSJK7rYts2xhhUWmuRmcw5qRQRtNbYto05J5XWWmQmc04qSeK6LrZtY4xBpbUWmcmck0oRQWuNbduYc1JprUVmMuekkiSu62LbNsYYVFprkZnMOakUEbTW2LaNOSeV1lpkJnNOKkniui62bWOMQaW1FpnJnJNKEUFrjW3bmHNSaa1FZjLnpJIkruti2zbGGHxljMGn2+3GnJOvrLXITOacVIoIWmts28ack6+MMfh0u92Yc/KVtRaZyZyTSpK4rott2xhjUGmtRWYy56RSRNBaY9s25pxUWmuRmcw5qdAxMzMzMzMzs6d1zMzMzMzMzOxpHTMzMzMzMzN7WsfMzMzMzMzMntYxMzMzMzMzs6d1zMzMzMzMzOxpHTMzMzMzMzN7WsfMzMzMzMzMntYxMzMzMzMzs6d1zMzMzMzMzOxpHTMzMzMzMzN7WsfMzMzMzMzMntYxMzMzMzMzs6d1zMzMzMzMzOxpHTMzMzMzMzN7WsfMzMzMzMzMntYxMzMzMzMzs6d1zMzMzMzMzOxpHTMzMzMzMzN72lhrUSUikMRai0qSkMR1Xay1qBQRSGKtxXe4rouI4LdEBJ8igrUWvycikMRai0qSkMR1Xay1qBQRSOLTdV2stahyXRcRQaWIQBJrLSpJQhLXdbHWolJEIIm1Ft/hui4igkoRgSTWWlSShCSu62KtRaWIQBJrLb7DdV1EBJUiAkmstagkCUlc18Vai0oRgSTWWnyH67qICCpFBJJYa1FJEpK4rou1FpUiAkmstfgO13UREVSKCCSx1qKSJCRxXRdrLSpFBJJYa/EdrusiIqgUEUhirUUlSUjiui7WWlSKCCSx1uI7XNdFRFApIpDEWotKkpDEdV2stagUEUhircV3uK6LiOAr13XxKSJYa/GViEASay0qSUIS13Wx1uIrEcGniGCtxVciAkmstfgO13UREVSKCCSx1qKSJCRxXRdrLSpFBJJYa1FhZCZVJCGJzKRSZvIhM8lMKklCEplJNUlkJq01foskPkkiM/k9kpBEZlIpM/mQmWQmlSTxv8tMKkgiM2mtUUkSkshMKmUmHzKTzKSSJCSRmVSTRGbSWqOSJCSRmVTKTD5kJplJJUlIIjOpJonMpLVGJUlIIjOplJl8yEwyk0qSkERmUk0SmUlrjUqSkERmUikz+ZCZZCaVJCGJzKSaJDKT1hqVJCGJzKRSZvIhM8lMKklCEplJNUlkJq01KklCEplJpczkQ2aSmVSShCQyk2qSyExaa1SShCQyk0qZyYfMJDOpJAlJZCbVJJGZtNb4Y0kiM/mKJCSRmVTKTD5kJpnJVyTxSRKZyVckIYnMpJokMpPWGpUkIYnMpFJm8iEzyUwqSUISmUmFcRwHVdZaZCbHcVApInh/f2ffd+acVFprkZkcx0ElSZznyb7vjDH4LWMMPo0xOI6D37PWIjM5joNKEcH7+zv7vjPnpNJai9Yan8YYHMfBsyRxnif7vjPGoNJai8zkOA4qRQTv7+/s+86ck0prLTKT4zioJInzPNn3nTEGldZaZCbHcVApInh/f2ffd+acVFprkZkcx0ElSZznyb7vjDGotNYiMzmOg0oRwfv7O/u+M+ek0lqLzOQ4DipJ4jxP9n1njEGltRaZyXEcVIoI3t/f2fedOSeV1lpkJsdxUEkS53my7ztjDCqttchMjuOgUkTw/v7Ovu/MOam01iIzOY6DSpI4z5N93xljUGmtRWZyHAeVIoL393f2fWfOSaW1FpnJcRxUksR5nuz7zhiDSmstMpPjOKgUEby/v7PvO3NOKq21yEyO46CSJM7zZN93xhh8ZYzBpzEGx3HwlbUWmclxHFSKCN7f39n3nTknXxlj8GmMwXEcfGWtRWZyHAeVJHGeJ/u+M8ag0lqLzOQ4DipFBO/v7+z7zpyTSmstMpPjOKjQMTMzMzMzM7OndczMzMzMzMzsaR0zMzMzMzMze1rHzMzMzMzMzJ7WMTMzMzMzM7OndczMzMzMzMzsaR0zMzMzMzMze1rHzMzMzMzMzJ7WMTMzMzMzM7OndczMzMzMzMzsaR0zMzMzMzMze1rHzMzMzMzMzJ7WMTMzMzMzM7OndczMzMzMzMzsaR0zMzMzMzMze1rHzMzMzMzMzJ7WMTMzMzMzM7OndczMzMzMzMzsaR0zMzMzMzMze9qQRDVJVJLEB0lI4jtIolJm8kESkvhjSEISfyxJVJLEB0lI4jtJQhLPykw+SEIS30ESlSTxQRKS+A6SqJSZfJCEJL6DJCpJ4oMkJPEdJFEpM/kgCUl8B0lUksQHSUjiO0iiUmbyQRKS+A6SqCSJD5KQxHeQRKXM5IMkJPEdJFFJEh8kIYnvIIlKmckHSUjiO0iikiQ+SEIS30ESlTKTD5KQxHeQRCVJfJCEJL6DJCplJh8kIYmvSOK/ksQfQxKVJPFBEpL4iiT+K0n8MSRRKTP5IAlJfAdJVJLEB0lI4jtIosI4z5NKkjjPk0qSyEzWWkQE1SRxnifVJLHWYq3Fb/n16xeffv36xXme/DEkcZ4nlSSRmay1iAiqZSaffv36xXmeVJDEWou1FtUkcZ4nlSSRmay1iAiqSeI8T6pJYq3FWotqkjjPk0qSyEzWWkQE1SRxnifVJLHWYq1FNUmc50klSWQmay0igmqSOM+TapJYa7HWopokzvOkkiQyk7UWEUE1SZznSTVJrLVYa1FNEud5UkkSmclai4igmiTO86SaJNZarLWoJonzPKkkicxkrUVEUE0S53lSTRJrLdZaVJPEeZ5UkkRmstYiIqgmifM8qSaJtRZrLb7y69cvPv369YvzPPk9kjjPk0qSyEzWWkQEX/n16xeffv36xXme/B5JnOdJNUmstVhrUU0S53lSSRKZyVqLiKCaJM7zpMKYc1Llui4yk33fqZSZnOfJtm28vLxQ6bouMpN936kkibUW27Zxu934LbfbjU9jDOac/J7rushM9n2nUmZynifbtvHy8kKl67rovfNpjMGck2dJYq3Ftm3cbjcqXddFZrLvO5Uyk/M82baNl5cXKl3XRWay7zuVJLHWYts2brcbla7rIjPZ951Kmcl5nmzbxsvLC5Wu6yIz2fedSpJYa7FtG7fbjUrXdZGZ7PtOpczkPE+2bePl5YVK13WRmez7TiVJrLXYto3b7Ual67rITPZ9p1Jmcp4n27bx8vJCpeu6yEz2faeSJNZabNvG7Xaj0nVdZCb7vlMpMznPk23beHl5odJ1XWQm+75TSRJrLbZt43a7Uem6LjKTfd+plJmc58m2bby8vFDpui4yk33fqSSJtRbbtnG73ah0XReZyb7vVMpMzvNk2zZeXl6odF0Xmcm+71SSxFqLbdu43W58ZYzBp9vtxpyTr1zXRWay7zuVMpPzPNm2jZeXF74yxuDT7XZjzslXrusiM9n3nUqSWGuxbRu3241K13WRmez7TqXM5DxPtm3j5eWFStd1kZns+06F8b9QJSJorTHGoFJE0FrjdrsxxqBSRNBaY4xBJUmstbjdbowx+C29dz713hlj8HsigtYaYwwqRQStNW63G2MMKkUE/9U///M/88///M+YmZmZmT2j984Yg69EBK01xhhUighaa9xuN8YYfKX3zqfeO2MMvhIRtNYYY1BJEmstbrcbYwwqRQStNcYYVIoIWmvcbjfGGFSKCFprjDGo0DEzMzMzMzOzpw3M/of83d/9Hf/xH//Bf/7nf1JJEq01voMkWmtUy0x673wHSbTWqCaJ1hrfQRKtNaplJr13voMkWmtUk0Rrje8gidYa1TKT3jvfQRKtNapJorXGd5BEa41qmUnvne8gidYa1STRWuM7SKK1RrXMpPfOd5BEa41qkmit8R0k0VqjWmbSe+c7SKK1RjVJtNb4DpJorVEtM+m98x0k0VqjmiRaa/yx/vRP/5S///u/x+z/FgOz/yF/8id/wj/90z8hiSqSOM+TOSdjDCqttchMjuOgUkTw9vbGjx8/mHNSaa1FZnIcB5UkcZ4nc07GGFRaa5GZHMdBpYjg7e2NHz9+MOek0lqLzOQ4DipJ4jxP5pyMMai01iIzOY6DShHB29sbP378YM5JpbUWmclxHFSSxHmezDkZY1BprUVmchwHlSKCt7c3fvz4wZyTSmstMpPjOKgkifM8mXMyxqDSWovM5DgOKkUEb29v/PjxgzknldZaZCbHcVBJEud5MudkjEGltRaZyXEcVIoI3t7e+PHjB3NOKq21yEyO46CSJM7zZM7JGINKay0yk+M4qBQRvL298ePHD+acVFprkZkcx0ElSZznyZyTMQZ/jNYarTXM/m8xMPsf1FqjtUYVSfTe6b3Te6dS750PvXcqSaL3Tu+d3juVeu986L1TSRK9d3rv9N6p1HvnQ++dSpLovdN7p/dOpd47H3rvVJJE753eO713KvXe+dB7p5Ikeu/03um9U6n3zofeO5Uk0Xun907vnUq9dz703qkkid47vXd671TqvfOh904lSfTe6b3Te6dS750PvXcqSaL3Tu+d3juVeu986L1TSRK9d3rv9N6p1HvnQ++dSpLovdN7p/dOpd47H3rvVJJE753eO713KvXe+dB7p5Ikeu/03um9U6n3zofeO5Uk0Xun907vHbP/F3XMzMzMzMzM7GkdMzMzMzMzM3tax8zMzMzMzMye1jEzMzMzMzOzp3XMzMzMzMzM7GkdMzMzMzMzM3tax8zMzMzMzMye1jEzMzMzMzOzp3XMzMzMzMzM7GkdMzMzMzMzM3tax8zMzMzMzMye1jEzMzMzMzOzp3XMzMzMzMzM7GkdMzMzMzMzM3tax8zMzMzMzMyeNtZaVIkIJLHWopIkJHFdF2stKkUEklhr8R2u6yIi+C0RwaeIYK3F74kIJLHWopIkJHFdF2stKkUEklhr8R2u6yIiqBQRSGKtRSVJSOK6LtZaVIoIJLHW4jtc10VEUCkikMRai0qSkMR1Xay1qBQRSGKtxXe4rouIoFJEIIm1FpUkIYnrulhrUSkikMRai+9wXRcRQaWIQBJrLSpJQhLXdbHWolJEIIm1Ft/hui4igkoRgSTWWlSShCSu62KtRaWIQBJrLb7DdV1EBJUiAkmstagkCUlc18Vai0oRgSTWWnyH67qICCpFBJJYa1FJEpK4rou1FpUiAkmstfgO13UREVSKCCSx1qKSJCRxXRdrLb4SEXyKCNZafCUikMRai+9wXRcRQaWIQBJrLSpJQhLXdbHWolJEIIm1FhVGZlJFEpLITCplJh8yk8ykkiQkkZlUk0Rm0lrjt0jikyQyk98jCUlkJpUykw+ZSWZSSRKSyEyqSSIzaa1RSRKSyEwqZSYfMpPMpJIkJJGZVJNEZtJao5IkJJGZVMpMPmQmmUklSUgiM6kmicyktUYlSUgiM6mUmXzITDKTSpKQRGZSTRKZSWuNSpKQRGZSKTP5kJlkJpUkIYnMpJokMpPWGpUkIYnMpFJm8iEzyUwqSUISmUk1SWQmrTUqSUISmUmlzORDZpKZVJKEJDKTapLITFprVJKEJDKTSpnJh8wkM6kkCUlkJtUkkZm01qgkCUlkJpUykw+ZSWbyFUl8kkRm8hVJSCIzqSaJzKS1RiVJSCIzqZSZfMhMMpNKkpBEZlJhHMdBlbUWmclxHFSKCN7f39n3nTknldZaZCbHcVBJEud5su87Ywx+yxiDT2MMjuPg96y1yEyO46BSRPD+/s6+78w5qbTWIjM5joNKkjjPk33fGWNQaa1FZnIcB5Uigvf3d/Z9Z85JpbUWmclxHFSSxHme7PvOGINKay0yk+M4qBQRvL+/s+87c04qrbXITI7joJIkzvNk33fGGFRaa5GZHMdBpYjg/f2dfd+Zc1JprUVmchwHlSRxnif7vjPGoNJai8zkOA4qRQTv7+/s+86ck0prLTKT4zioJInzPNn3nTEGldZaZCbHcVApInh/f2ffd+acVFprkZkcx0ElSZznyb7vjDGotNYiMzmOg0oRwfv7O/u+M+ek0lqLzOQ4DipJ4jxP9n1njEGltRaZyXEcVIoI3t/f2fedOSeV1lpkJsdxUEkS53my7ztjDCqttchMjuOgUkTw/v7Ovu/MOfnKGINPYwyO4+Aray0yk+M4qCSJ8zzZ950xBpXWWmQmx3FQKSJ4f39n33fmnFRaa5GZHMdBhY6ZmZmZmZmZPa1jZmZmZmZmZk/rmJmZmZmZmdnTOmZmZmZmZmb2tI6ZmZmZmZmZPa1jZmZmZmZmZk/rmJmZmZmZmdnTOmZmZmZmZmb2tI6ZmZmZmZmZPa1jZmZmZmZmZk/rmJmZmZmZmdnTOmZmZmZmZmb2tI6ZmZmZmZmZPa1jZmZmZmZmZk/rmJmZmZmZmdnTOmZmZmZmZmb2tI6ZmZmZmZmZPa1jZmZmZmZmZk/rmJmZmZmZmdnTRkRQRRKSiAgqZSaSyEwigkqSkEREUEkSHzKTiOC3SOJTZhIR/B5JSCIiqJSZSCIziQgqSUISEUElSXzITCKCSpKQRERQKTORRGYSEVSShCQigkqS+JCZRASVJCGJiKBSZiKJzCQiqCQJSUQElSTxITOJCCpJQhIRQaXMRBKZSURQSRKSiAgqSeJDZhIRVJKEJCKCSpmJJDKTiKCSJCQREVSSxIfMJCKoJAlJRASVMhNJZCYRQSVJSCIiqCSJD5lJRFBJEpKICCplJpLITCKCSpKQRERQSRIfMpOIoJIkJBERVMpMJJGZRASVJCGJiKCSJD5kJhFBJUlIIiKolJlIIjOJCL6SmXySRETwFUlIIiKoJIkPmUlEUEkSkogIKmUmkshMIoJKkpBERFBhvL29UWXbNnrvPB4PKkkiM7nf77TWqLRtG713Ho8HlVprzDm53+9EBL/l58+ffPr58ydvb2/8nm3b6L3zeDyoJInM5H6/01qj0rZt9N55PB5Uaq0x5+R+vxMRVNq2jd47j8eDSpLITO73O601Km3bRu+dx+NBpdYac07u9zsRQaVt2+i983g8qCSJzOR+v9Nao9K2bfTeeTweVGqtMefkfr8TEVTato3eO4/Hg0qSyEzu9zutNSpt20bvncfjQaXWGnNO7vc7EUGlbdvovfN4PKgkiczkfr/TWqPStm303nk8HlRqrTHn5H6/ExFU2raN3juPx4NKkshM7vc7rTUqbdtG753H40Gl1hpzTu73OxFBpW3b6L3zeDyoJInM5H6/01qj0rZt9N55PB5Uaq0x5+R+vxMRVNq2jd47j8eDSpLITO73O601Kv1/7cExcmRNcqXRL/LFi4xXEKBT6AWQe6DI9XEXFLgi7qEkINMKbhVxLwdCm/0C2d0zcBg5bX7OeZ7cbjfe39/J1Fpjzsnb2xt7bzKd58ntduP9/Z1MtpHE29sbrTX+kl+/fvFnv3794ufPn/wl53lyu914f38nU2uNOSdvb2/svcl0nie3243393cy2UYSb29vtNbIdJ4nt9uN9/d3MvTX11eySMI2c04ySeLt7Y2XlxfO8ySTJGwz5yTbWouXlxdaa/x37vc7f3a/33l9feWvkYRt5pxkksTb2xsvLy+c50kmSdhmzkm2tRYvLy+01sgkCdvMOckkibe3N15eXjjPk0ySsM2ck2xrLV5eXmitkUkStplzkkkSb29vvLy8cJ4nmSRhmzkn2dZavLy80FojkyRsM+ckkyTe3t54eXnhPE8yScI2c06yrbV4eXmhtUYmSdhmzkkmSby9vfHy8sJ5nmSShG3mnGRba/Hy8kJrjUySsM2ck0ySeHt74+XlhfM8ySQJ28w5ybbW4uXlhdYamSRhmzknmSTx9vbGy8sL53mSSRK2mXOSba3Fy8sLrTUyScI2c04ySeLt7Y2XlxfO8ySTJGwz5yTbWouXlxdaa2SShG3mnGSSxNvbGy8vL5znyV9yv9/5s/v9zuvrK3+JJGwz5yTbWouXlxdaa2SShG3mnGSSxNvbGy8vL5znSSZJ2GbOSYY+5yRLRCCJOSeZ9t601jjPkzknmSICScw5yWSbtRbnedJ7579zHAd/1ntnzslfExFIYs5Jpr03rTXO82TOSaaIQBJzTjLZZq3FeZ703skUEUhizkmmvTeyz9oAABO4SURBVDetNc7zZM5JpohAEnNOMtlmrcV5nvTeyRQRSGLOSaa9N601zvNkzkmmiEASc04y2WatxXme9N7JFBFIYs5Jpr03rTXO82TOSaaIQBJzTjLZZq3FeZ703skUEUhizkmmvTetNc7zZM5JpohAEnNOMtlmrcV5nvTeyRQRSGLOSaa9N601zvNkzkmmiEASc04y2WatxXme9N7JFBFIYs5Jpr03rTXO82TOSaaIQBJzTjLZZq3FeZ703skUEUhizkmmvTetNc7zZM5JpohAEnNOMtlmrcV5nvTeyRQRSGLOSaa9N601zvNkzslf0nvnz47jYM7JXxIRSGLOSSbbrLU4z5PeO5kiAknMOcm096a1xnmezDnJFBFIYs5Jhk75X+Pj44N//dd/5a/Ze2Ob3juZbPPr1y/u9zvHcZBp741teu9k+/37N8dxcLvdyLT3xja9dzLZ5tevX9zvd47jINPeG9v03sn2+/dvjuPgdruRae+NbXrvZLLNr1+/uN/vHMdBpr03tum9k+33798cx8HtdiPT3hvb9N7JZJtfv35xv985joNMe29s03sn2+/fvzmOg9vtRqa9N7bpvfP/orWGbf6otYYkPj4+GGNwHAd/1lrDNv+V1hq2+aPWGrb5o703tjnPE9v8UWsN27TWsM0ftdawzV/y+/dvjuPgdrvxf6O1hm3+K6011lrYpvfOX9NawzZ/C9v8+vWL+/3OcRxk2ntjm9472X7//s1xHNxuNzLtvbFN751Mtvn16xf3+53jOMi098Y2vXey/f79m+M4uN1uZNp7Y5veO5ls8+vXL+73O8dx8FWtNWzzae+NbXrvfGqtYZu/VWsN2/xXfv/+zXEc3G43/hatNWzzR601bPNHe29sc54ntvmj1hq2aa1hmz9qrWGbP2qtYZtPtvn16xf3+53eO7b5o9Yatmmt8fHxQfn71yn/a/z7v/87pZRSSimllFL+/3Sj/I/6l3/5F+aclFJKKaWUUv7+/fjxg3/+53+m/H3qlP9R//RP/8S//du/8R//8R/8rdZaSGKMQSZJvL+/8+PHD87zJNNaC0mMMcj28fHBGIPb7UamtRaSGGOQSRLv7+/8+PGD8zzJtNZCEmMMsn18fDDG4Ha7kWmthSTGGGSSxPv7Oz9+/OA8TzKttZDEGINsHx8fjDG43W5kWmshiTEGmSTx/v7Ojx8/OM+TTGstJDHGINvHxwdjDG63G5nWWkhijEEmSby/v/Pjxw/O8yTTWgtJjDHI9vHxwRiD2+1GprUWkhhjkEkS7+/v/Pjxg/M8ybTWQhJjDLJ9fHwwxuB2u5FprYUkxhhkksT7+zs/fvzgPE8yrbWQxBiDbB8fH4wxuN1uZFprIYkxBpkk8f7+zo8fPzjPk0xrLSQxxiDbx8cHYwxutxuZ1lpIYoxBJkm8v7/z48cPzvPkb/GP//iP/MM//APl71On/I9qrfGnP/2JP/3pT/ytIgJJXNdFpr03P3/+5PX1lTknmSICSVzXRSbbPJ9P5pz03skUEUjiui4y7b35+fMnr6+vzDnJFBFI4rouMtnm+Xwy56T3TqaIQBLXdZFp783Pnz95fX1lzkmmiEAS13WRyTbP55M5J713MkUEkriui0x7b37+/Mnr6ytzTjJFBJK4rotMtnk+n8w56b2TKSKQxHVdZNp78/PnT15fX5lzkikikMR1XWSyzfP5ZM5J751MEYEkrusi096bnz9/8vr6ypyTTBGBJK7rIpNtns8nc05672SKCCRxXReZ9t78/PmT19dX5pxkiggkcV0XmWzzfD6Zc9J7J1NEIInrusi09+bnz5+8vr4y5yRTRCCJ67rIZJvn88mck947mSICSVzXRaa9Nz9//uT19ZU5J6XcKKWUUkoppZRSypfdKKWUUkoppZRSypfdKKWUUkoppZRSypfdKKWUUkoppZRSypfdKKWUUkoppZRSypfdKKWUUkoppZRSypfdKKWUUkoppZRSypfdKKWUUkoppZRSypfdKKWUUkoppZRSypfdKKWUUkoppZRSypfdKKWUUkoppZRSypfdKKWUUkoppZRSypfdKKWUUkoppZRSypfdKKWUUkoppZRSypf1iCDL3hvbRASZbGObtRYRQaa9N7aJCL7DWou9N5n23tgmIshkG9ustYgIMu29sU1E8B3WWuy9ybT3xjYRQSbb2GatRUSQae+NbSKC77DWYu9Npr03tokIMtnGNmstIoJMe29sExF8h7UWe28y7b2xTUSQyTa2WWsREWTae2ObiOA7rLXYe5Np741tIoJMtrHNWouIINPeG9tEBN9hrcXem0x7b2wTEWSyjW3WWkQEmfbe2CYi+A5rLfbeZNp7Y5uIIJNtbLPWIiLItPfGNhHBd1hrsfcm094b20QEmWxjm7UWEUGmvTe2iQi+w1qLvTeZ9t7YJiLIZBvbrLWICDLtvbFNRPAd1lrsvcm098Y2EUEm29hmrUVEkGnvjW0iggxdEllsYxtJZJLEJ0lIIpNtbCOJbLaRRGuNTLaxjSQySeKTJCSRyTa2kUQ220iitUYm29hGEpkk8UkSkshkG9tIIpttJNFaI5NtbCOJTJL4JAlJZLKNbSSRzTaSaK2RyTa2kUQmSXyShCQy2cY2kshmG0m01shkG9tIIpMkPklCEplsYxtJZLONJFprZLKNbSSRSRKfJCGJTLaxjSSy2UYSrTUy2cY2ksgkiU+SkEQm29hGEtlsI4nWGplsYxtJZJLEJ0lIIpNtbCOJbLaRRGuNTLaxjSQySeKTJCSRyTa2kUQ220iitUYm29hGEpkk8UkSkshkG9tIIkO/rossEYEkrusi096bx+PBGIM5J5kiAklc10Um2zyfT8YY9N7JFBFI4rouMu29eTwejDGYc5IpIpDEdV1kss3z+WSMQe+dTBGBJK7rItPem8fjwRiDOSeZIgJJXNdFJts8n0/GGPTeyRQRSOK6LjLtvXk8HowxmHOSKSKQxHVdZLLN8/lkjEHvnUwRgSSu6yLT3pvH48EYgzknmSICSVzXRSbbPJ9Pxhj03skUEUjiui4y7b15PB6MMZhzkikikMR1XWSyzfP5ZIxB751MEYEkrusi096bx+PBGIM5J5kiAklc10Um2zyfT8YY9N7JFBFI4rouMu29eTwejDGYc5IpIpDEdV1kss3z+WSMQe+dTBGBJK7rItPem8fjwRiDOSeZIgJJXNdFJts8n0/GGPTeyRQRSOK6LjLtvXk8HowxmHOSKSKQxHVdZLLN8/lkjEHvnUwRgSSu6yLT3pvH48EYgzknmSICSVzXRYYbpZRSSimllFJK+bIbpZRSSimllFJK+bIbpZRSSimllFJK+bIbpZRSSimllFJK+bIbpZRSSimllFJK+bIbpZRSSimllFJK+bIbpZRSSimllFJK+bIbpZRSSimllFJK+bIbpZRSSimllFJK+bIbpZRSSimllFJK+bIbpZRSSimllFJK+bIbpZRSSimllFJK+bIbpZRSSimllFJK+bIbpZRSSimllFJK+bIbpZRSSimllFJK+bIbpZRSSimllFJK+bIbpZRSSimllFJK+bIbpZRSSimllFJK+bIbpZRSSimllFJK+bJum2y2yWSbT7axzXewTSZJfLKNbb6DbTLZ5pNtbPMdbJNJEp9sY5vvYJtMtvlkG9t8B9tkksQn29jmO9gmk20+2cY238E2mSTxyTa2+Q62yWSbT7axzXewTSZJfLKNbb6DbTLZ5pNtbPMdbJNJEp9sY5vvYJtMtvlkG9t8B9tkksQn29jmO9gmk20+2cY238E2mSTxyTa2+Q62yWSbT7axzXewTSZJfLKNbb6DbTLZ5pNtbPMdbJNJEp9sY5vvYJtMtvlkG9t8B9tkaO/v7yaRbVprZLLN4/Hgui5672SzTWuNbLZprfEdbNNaI5NtHo8H13XReyebbVprZLNNa43vYJvWGpls83g8uK6L3jvZbNNaI5ttWmt8B9u01shkm8fjwXVd9N7JZpvWGtls01rjO9imtUYm2zweD67rovdONtu01shmm9Ya38E2rTUy2ebxeHBdF713stmmtUY227TW+A62aa2RyTaPx4Pruui9k802rTWy2aa1xnewTWuNTLZ5PB5c10XvnWy2aa2RzTatNb6DbVprZLLN4/Hgui5672SzTWuNbLZprfEdbNNaI5NtHo8H13XReyeb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) + +第二个链表 **只存储 可能是循环引用的对象**。 + +维护两个链表的作用是,在python内部某种情况下,会去扫描`可能存在循环引用的链表` 中的每个元素,在循环一个列表的元素时,由于内部还有子元素 ,如果存在循环引用(v1 = [1,2,3,v2]和v2 = [4,5,6,v1]),比如从v1的子元素中找到了v2,又从v2的子元素中找到了v1,那么就检查到循环引用,如果有循环引用,就让双方的引用计数器各自-1,如果是0则垃圾回收。 + +### 2.3标记清除算法 + +【标记清除(Mark—Sweep)】算法是一种基于追踪回收(tracing GC)技术实现的垃圾回收算法。它分为两个阶段:第一阶段是标记阶段,GC会把所有的『活动对象』打上标记,第二阶段是把那些没有标记的对象『非活动对象』进行回收。那么GC又是如何判断哪些是活动对象哪些是非活动对象的呢? + +对象之间通过引用(指针)连在一起,构成一个有向图,**对象构成这个有向图的节点,而引用关系构成这个有向图的边**。从根对象(root object)出发,沿着有向边遍历对象,可达的(reachable)对象标记为活动对象,**不可达的对象就是要被清除的非活动对象**。根对象就是全局变量、调用栈、寄存器。 + +![图片](data:image/png;base64,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) + + +在上图中,我们把小黑点视为全局变量,也就是把它作为root object,从小黑点出发,对象1可直达,那么它将被标记,对象2、3可间接到达也会被标记,而4和5不可达,那么1、2、3就是活动对象,4和5是非活动对象会被GC回收。 + +1. 寻找跟对象(root object)的集合作为垃圾检测动作的起点,跟对象也就是一些全局引用和函数栈中的引用,这些引用所指向的对象是不可被删除的。 + +2. 从root object集合出发,沿着root object集合中的每一个引用,如果能够到达某个对象,则说明这个对象是可达的,那么就不会被删除,这个过程就是垃圾检测阶段。 + +3. 当检测阶段结束以后,所有的对象就分成可达和不可达两部分,所有的可达对象都进行保留,其它的不可达对象所占用的内存将会被回收,这就是垃圾回收阶段。(底层采用的是**链表**将这些集合的对象连接在一起)。 + + + +## 三、分代回收 + +### 3.1引入目的 + +问题: + +* 什么时候扫描去检测循环引用? +* **标记和清除的过程效率不高**。清除非活动的对象前它必须顺序扫描整个堆内存,哪怕只剩下小部分活动对象也要扫描所有对象。 + 为了解决上述的问题,python又引入了分代回收。 + +### 3.2原理 + +将第二个链表(可能存在循环引用的链表),维护成3个环状双向的链表: + +* 0代: 0代中对象个数达到700个,扫描一次。 +* 1代: 0代扫描10次,则1代扫描1次。 +* 2代: 1代扫描10次,则2代扫描1次。 + ![图片](data:image/png;base64,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) + +```c +// 分代的C源码 +##define NUM_GENERATIONS 3 +struct gc_generation generations[NUM_GENERATIONS] = { + /* PyGC_Head, threshold, count */ + {{(uintptr_t)_GEN_HEAD(0), (uintptr_t)_GEN_HEAD(0)}, 700, 0}, // 0代 + {{(uintptr_t)_GEN_HEAD(1), (uintptr_t)_GEN_HEAD(1)}, 10, 0}, // 1代 + {{(uintptr_t)_GEN_HEAD(2), (uintptr_t)_GEN_HEAD(2)}, 10, 0}, // 2代 +}; +``` + +例: +![图片](data:image/png;base64,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lBI15ZwxM/q+pyZJTCYTuq4jxkhNOWfMjL7vqamUwng8pus6UkrUlHPGzOj7npokMZlM6LqOGCM15ZwxM/q+p6ZSCuPxmK7rSClRU84ZM6Pve2qSxGQyoes6YozUlHPGzOj7nppKKYzHY7quI6VETTlnzIy+76lJEpPJhK7riDFSU84ZM6Pve2oqpTAej+m6jpQSNeWcMTP6vqcmSUwmE7quI8ZITTlnzIy+76mplMJ4PKbrOlJK1JRzxszo+55Xo8E555xzzjnnnHPObbkG55xzzjnnnHPOObflGpxzzjnnnHPOOefclmtwzjnnnHPOOeecc1uuwTnnnHPOOeecc85tuQbnnHPOOeecc845t+UanHPOOeecc84559yWa3DOOeecc84555xzW67BOeecc84555xzzm25Buecc84555xzzjm35Rqcc84555xzzjnn3JZrcM4555xzzjnnnHNbrsE555xzzjnnnHPObbkG55xzzjnnnHPOObflGpxzzjnnnHPOOefclmtwzjnnnHPOOeecc1uuwTnnnHPOOeecc85tuQbnnHPOuf8PbGxscOedd3L06FEuWF1dZc+ePXz729/mxY4ePcqdd97JxsYGr8TGxgZ33nknf/EXf8HGxgbOOeecc7U0OOecc+5/hZWVFXbv3s3q6iovtr6+zm233cbDDz/MxsYGf/mXf8nq6ipbYX19ndtuu40777yTjY0NXq61tTWeeOIJ3vCGN3DB6173Oq644gr+9V//lYttbGxw+vRprrrqKlJKOOecc879NIilFC7HzJCEmVFKoSZJSKKUQk2SmDIzSinUJAlJlFKoycyQhJlRSqEmSUiilEJNkpgyM0op1CQJSZRSqMnMkISZUUqhJklIopRCTZKYMjNKKdQkCUmUUqjJzJCEmVFKoSZJSKKUQk2SmDIzSinUJAlJlFKoycyQhJlRSqEmSUiilEJNkpgyM0op1CQJSZRSqMnMkISZUUqhJklIopTC1Pr6OrfffjtPPfUUL7Zjxw6Wl5e5++67WVtb4yf5yEc+wk033UQphQvMjKlSCqUULlZKQRJmxne+8x0eeughHnroIT73uc9x/fXXs76+zu23385TTz3FpezYsYNbbrmFj33sY1zOjh07+MxnPsP8/DwXMzMkYWb8+7//O08++SQ33XQTbdtSSuHlOHPmDGtra/ziL/4i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+tKXePLJJ5l64IEHWF1d5WI7duxg165dfPOb32TPnj3Mz8/zch0+fJjFxUUWFxdZXFxkcXGRw4cP82ptbGxw5513sri4yOLiIouLixw7doyTJ0/ytre9jcXFRXbv3s3q6ioXW11d5ZZbbuHJJ59k3759LCwsMLVjxw6mvvvd77K+vs5tt93GI488wkMPPcTb3vY25ufncc4555x7JSLOOeec+6l17Ngx9u/fz80338yjjz7K3r17WVpa4lLm5+fZs2cPhw8f5s1vfjMrKyvccMMNLC0t8VL+5V/+heeee47du3czlVJiz549fPzjH2f37t0sLCzwYidOnODYsWMcOnSI6667juXlZU6cOMHy8jIXrK2t8cQTTzD1wAMPcN1117GwsMDLcejQIZaWlni1vva1r3H11VdzQUqJI0eOcOTIES44evQop0+f5uDBg6SUeLGHH36Yw4cPc8H27du5IKXEe9/7Xj7ykY+wtrbGrl27+PznP09KCeecc865/4kG55xzzv1Uefjhh7n55ptZW1vj937v9/j617/O9773Pa688kpuvfVWLucd73gHu3bt4nOf+xx/9Ed/xPLyMi9ldXWVBx54gH379rGwsMAFO3bsYOfOnTz44INsbGxwsRMnTvDJT36SvXv3srS0xMLCAvv27ePYsWOsrKwwtbKyws0338y+fft49NFH2blzJ3fddRfr6+tczmtf+1oeeOABlpaWeLVWVlb40pe+xOte9zr+J1ZXV9m9ezeHDx9m7969PPTQQ2zbto0X+z//5/9w6NAhtm3bxvve9z5SSjjnnHPO/U81OOecc+6nwvr6OrfddhtTKysrrKyssLS0xMbGBtu3b+euu+5ifn6ey0kp8e53v5tf+7Vf43LW19e56667eMc73sHS0hIXSylxxx138Oyzz/LAAw9wwdGjR/nEJz7BRz/6UZaXl7ngHe94B3v37uXqq6/m6NGj7N+/n/vvv5+lpSVSStxxxx1MHThwgPX1dTbbyZMnuf/++7n33nuZn5/nq1/9KqdPn+b48eNsbGzwkzz88MPcfPPN7Nu3j5WVFZaXl7mU1dVVPvKRj/Arv/IrHD16lOXlZR5++GGcc8455/6nGpxzzjn3U2F+fp4vfvGLLC0tcbGrrrqKI0eOsLCwwMuxuLjIBz/4Qebn57mUF154gU9/+tNs376dffv2cSnz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) + +当我们创建一个对象val = 19,那么它只会加到refchain链表中。 + +当我们创建一个对象v1 = [11,22],除了加到refchain,那么它会加到0代链表中去。 + +如果再创建一个对象v2 = [33,44],那么它还是往0代添加。 + +直到0代中的个数达到700之后,就会对0代中的所有元素进行一次扫描,扫描时如果检测出是循环引用那么引用计数器就自动-1,然后判断引用计数器是否为0,如果为0,则为垃圾就进行回收。不是垃圾的话,就对该数据进行升级,从0代升级到1代,这个时候0代就是空,1代就会记录一下0代已经扫描1次,然后再往0代中添加对象直到700再进行一次扫描,不停反复,直到0代扫描了10次,才会对1代进行1次扫描。 + +分代回收解决了标记清楚时什么时候扫描的问题,并且将扫描的对象分成了3级,以及降低扫描的工作量,提高效率。 + +### 3.3弱代假说 + +为什么要按一定要求进行分代扫描? + +这种算法的根源来自于**弱代假说**(weak generational hypothesis)。 + +这个假说由两个观点构成:**首先是年轻的对象通常死得也快,而老对象则很有可能存活更长的时间。** + +假定现在我用Python创建一个新对象 n1="ABC" + +根据假说,我的代码很可能仅仅会使用ABC很短的时间。这个对象也许仅仅只是一个方法中的中间结果,并且随着方法的返回这个对象就将变成垃圾了。大部分的新对象都是如此般地很快变成垃圾。然而,偶尔程序会创建一些很重要的,存活时间比较长的对象,例如web应用中的session变量或是配置项。 + + 频繁的处理零代链表中的新对象,可以将让Python的**垃圾收集器把时间花在更有意义的地方**:它处理那些很快就可能变成垃圾的新对象。同时只在很少的时候,当满足一定的条件,收集器才回去处理那些老变量。 + +## 四、总结 + +将上面三个点学习之后,基本上应付面试没有太大问题了。 + +在python中维护了refchain的双向环状链表,这个链表中存储创建的所有对象,而每种类型的对象中,都有一个ob_refcnt引用计数器的值,它维护者引用的个数+1,-1,最后当引用计数器变为0时,则进行垃圾回收(对象销毁、refchain中移除)。 + +但是,在python中对于那些可以有多个元素组成的对象,可能会存在循环引用的问题,并且为了解决这个问题,python又引入了标记清除和分代回收,在其内部维护了4个链表,分别是: + +* refchain +* 2代,10次 +* 1代,10次 +* 0代,700个 + 在源码内部,当达到各自的条件阈值时,就会触发扫描链表进行标记清除的动作(如果有循环引用,引用计数器就各自-1)。 + +到这里我们只需要把这些给面试官说完就可以了。 + +———————————————— + +但是,源码内部在上述的流程中提出了优化机制,就是缓存机制。 + +## 五、缓存机制 + +缓存在python中分为两大类 + +### 5.1池 + +在python中为了避免重复创建和销毁一些常见对象,维护池。 + +例: + +```python +v1 = 7 +v2 = 9 +v3 = 9 + +## 按理说在python中会创建3个对象,都加入refchain中。 +``` + +然而python在启动解释器时,python认为-5、-4、….. 、256,bool、一定规则的字符串,这些值都是常用的值,所以就会在内存中帮你先把这些值先创建好,接下来进行验证: + +```python +## 启动解释器时,python内部帮我们创建-5、-4、...255、256的整数和一定规则的字符串 +v1 = 9 # 内部不会开辟内存,直接去池中获取 +v2 = 9 # 同上,都是去数据池里直接拿9,所以v1和v2指向的内存地址是一样的 +print(id(v1),id(v2)) + +v3 = 256 # 内部不会开辟内存,直接去池中获取 +v4 = 256 # 同上,都是去数据池里直接拿256,所以v3和v4指向的内存地址是一样的 +print(id(v3),id(4)) + +v5 = 257 +v6 = 257 +print(id(v5),id(v6)) +``` + +排查原因:版本不同,小数据池扩大。 +在交互模式下返回得结果符合预期,文件模式的情况下 + +问题:为什么交互模式和命令模式结果有区别? + +答:因为代码块的缓存机制。 + +* 什么是代码块? + 一个模块、一个函数、一个类、一个文件等都是一个代码块;交互式命令下,一行就是一个代码块。 + +* 同一个代码块内的缓存机制(字符串驻留机制) +* - 机制内容:Python在执行同一个代码块的初始化对象的命令时,会检查是否其值是否已经存在,如果存在,会将其重用,即将两个变量指向同一个对象。换句话说:执行同一个代码块时,遇到初始化对象的命令时,他会将初始化的这个变量与值存储在一个字典中,在遇到新的变量时,会先在字典中查询记录,如果有同样的记录那么它会重复使用这个字典中的之前的这个值。所以在用命令模式执行时(同一个代码块)会把i1、i2两个变量指向同一个对象,满足缓存机制则他们在内存中只存在一个,即:id相同。 +* - 适用对象: int(float),str,bool。 +* - 对象的具体细则:(了解) + +- - int(float):**任何数字**在同一代码块下都会复用。 + +* * bool:True和False在字典中会以**1,0**方式存在,并且复用。 + * str:**几乎所有的字符串**都会符合字符串驻留机制 + +```python +## 同一个代码块内的缓存机制————任何数字在同一代码块下都会复用 +i1 = 1000 +i2 = 1000 +print(id(i1)) +print(id(i2)) +输出结果: + + + +## 同一个代码块内的缓存机制————几乎所有的字符串都会符合缓存机制 +s1 = 'hfdjka6757fdslslgaj@!#fkdjlsafjdskl;fjds中国' +s2 = 'hfdjka6757fdslslgaj@!#fkdjlsafjdskl;fjds中国' +print(id(s1)) +print(id(s2)) +输出结果: + + + +## 同一个代码块内的缓存机制————非数字、str、bool类型数据,指向的内存地址一定不同 +t1 = (1,2,3) +t2 = (1,2,3) +l1 = [1,2,3] +l2 = [1,2,3] +print(id(t1)) +print(id(t2)) +print(id(l1)) +print(id(l2)) +输出结果: +``` + +* 不同代码块间的缓存机制(小数据池、小整数缓存机制、小整数驻留机制) + +- 适用对象: int(float),str,bool + +* * 具体细则:**-5~256数字,bool,满足一定规则的字符串**。 + * 优点:提升性能,节省内存。 + * Python自动将-5~256的整数进行了缓存,当你将这些整数赋值给变量时,并不会重新创建对象,而是使用已经创建好的缓存对象。 + * python会将一定规则的字符串在字符串驻留池中,创建一份,当你将这些字符串赋值给变量时,并不会重新创建对象, 而是使用在字符串驻留池中创建好的对象。 + * 其实,无论是缓存还是字符串驻留池,都是python做的一个优化,就是将~5-256的整数,和一定规则的字符串,放在一个‘池’(容器,或者字典)中,无论程序中那些变量指向这些范围内的整数或者字符串,那么他直接在这个‘池’中引用,言外之意,就是内存中之创建一个。 + +```python +## 创建文件1: file1 +def A(): + b = 1 + print(id(b)) + + + +## 创建文件2: file2 +from file1 import A +a = 1 +print(id(a)) +A() +``` + +总结一下就是,**同一个代码块中(交互模式中的)**因为字符串驻留机制,int(float),str,bool这些数据类型,只要对象相同,那么内存地址共享。 +而不同代码块中只有引用对象为**-5~256整数,bool,满足一定规则的字符串,**才会有内存共享,即id相同。 + +并且这些python编辑器初始化的数据,他们的引用计数器永远不会为0,在初始化的时候就会将引用计数器默认设置为1。 + +### 5.2 free_list + +当一个对象的引用计数器为0的时候,按理说应该回收,但是在python内部为了优化,不会去回收,而是将对象添加到free_list链表中当作缓存。以后再去创建对象时就不再重新开辟内存,而是直接使用free_list。 + +```python +v1 = 3.14 # 创建float型对象,加入refchain,并且引用计数器的值为1 +del v1 #refchain中移除,按理说应该销毁,但是python会将对象添加到free_list中。 + +v2 = 9.999 # 就不会重新开辟内存,去free_list中获取对象,对象内部数据初始化,再放到refchain中。 +``` + +但是free_list也是有容量的,不是无限收纳, 假设默认数量为80,只有当free_list满的时候,才会直接去销毁。 +代表性的有float/list/tuple/dict,这些数据类型都是以free_list方式来进行回收的。 + +缓存列表对象的创建源码: + +总结一下,就是引用计数器为0的时候,有的是直接销毁,而有些需要先加入缓存当中的。 + +每个数据类型的缓存链表源码详见:[[https://pythonav.com/wiki/detail/6/88/#2.4%20int%E7%B1%BB%E5%9E%8B](https://pythonav.com/wiki/detail/6/88/#2.4](https://pythonav.com/wiki/detail/6/88/#2.4%20int%E7%B1%BB%E5%9E%8B](https://pythonav.com/wiki/detail/6/88/#2.4) int类型) + +## C源码分析 + +`arena`是 CPython 的内存管理结构之一。代码在`Python/pyarena.c`中其中包含了 C 的内存分配和解除分配的方法。 + +[https://github.com/python/cpython/blob/master/Python/pyarena.c](https://github.com/python/cpython/blob/master/Python/pyarena.c) + +`Modules/gcmodule.c`,该文件包含垃圾收集器算法的实现。 + +[https://github.com/python/cpython/blob/master/Modules/gcmodule.c](https://github.com/python/cpython/blob/master/Modules/gcmodule.c) + diff --git a/02.面向对象/01.初识面向对象.md b/02.面向对象/01.初识面向对象.md new file mode 100644 index 0000000..fb530b1 --- /dev/null +++ b/02.面向对象/01.初识面向对象.md @@ -0,0 +1,310 @@ +# 初识面向对象 + +## 面向对象 + +### 面向过程编程vs函数式编程 + +```python +# 面向过程编程 +s1 = 'fjdsklafsjda' +count = 0 +for i in s1: + count += 1 + + +l1 = [1,2,3,4] +count = 0 +for i in l1: + count += 1 +``` + +```python +# 函数式编程 +def func(s): + count = 0 + for i in s: + count += 1 + return count +func('fdsafdsa') +func([1,2,3,4]) +``` + +通过对比可知:函数编程较之面向过程编程最明显的两个特点: + +1. 减少代码的重用性。 + +2. 增强代码的可读性。 + +### 函数式编程vs面向对象编程 + +```python +# 函数式编程 + +# auth 认证相关 +def login(): + pass + +def regisgter(): + pass + +# account 账户相关 +def func1(): + pass + +def func2(): + pass + + +# 购物车相关 +def shopping(username,money): + pass +def check_paidgoods(username,money): + pass +def check_unpaidgoods(username,money): + pass +def save(username,money): + pass +``` + +```python +class LoginHandler: + def login(self): + pass + + def regisgter(self): + pass + +class Account: + def func1(self): + pass + + def func2(self): + pass + +class ShoppingCar: + def shopping(username,money): + pass + def check_paidgoods(username,money): + pass + def check_unpaidgoods(username,money): + pass + def save(username,money): + pass +``` + +1. 面向对象编程:是一类相似功能函数的集合,使你的代码更清晰化,更合理化。 +2. 面向对象,要拥有上帝的视角看问题,类其实就是一个公共模板(厂房),对象就从具体的模板实例化出来。 + +### 类的结构 + +```python +class Human: + """ + 此类主要是构建人类 + """ + mind = '有思想' # 第一部分:静态属性 属性 静态变量 静态字段 + dic = {} + l1 = [] + def work(self): # 第二部分:方法 函数 动态属性 + print('人类会工作') +``` + +class 是关键字与def用法相同,定义一个类。 +Human是此类的类名,类名使用驼峰(CamelCase)命名风格,首字母大写,私有类可用一个下划线开头。 +类的结构从大方向来说就分为两部分: + +- 静态变量 +- 动态方法 + +## 从类名的角度研究类 + +### 类名操作静态属性 + +**查看类中的所有内容:类名.__dict__方式。** + +```python +class Human: + mind = '有思想' + dic = {} + l1 = [] + def work(self): + print('会工作') + +print(Human.__dict__) +print(Human.__dict__['mind']) +Human.__dict__['mind'] = '高智慧' +print(Human.__dict__) +# 通过这种方式只能查询,不能增删改 +``` + +**万能的点.** + +```python +class Human: + mind = '有思想' + dic = {} + l1 = [] + def work(self): + print('会工作') + +print(Human.mind) +Human.mind = '高智慧' +print(Human.mind) + +del Human.mind +Human.walk = '用脚走' +print(Human.walk) +# 通过万能的点 可以增删改查类中的单个属性 +``` + +**对以上两种做一个总结:如果想查询类中的所有内容,通过 第一种__dict__方法,如果只是操作单个属性则用万能的点的方式。** + +### 类名操作动态方法 + +```python +class Human: + mind = '有思想' + dic = {} + l1 = [] + def work(self): + print(self,'会工作') + +Human.work('chensong') +Human.__dict__['work']('chensong') +``` + +## 从对象的角度研究类 + +### 对象 + +对象是从类中出来的,只要是**类名加上()**,这就是一个实例化过程,这个就会实例化一个对象。 + +```python +class Human: + mind = '有思想' + dic = {} + l1 = [] + def work(self): + print(self,'会工作') + +obj = Human() +# 只要实例化对象,它会自动执行__init__方法 +print(obj) +``` + +其实实例化一个对象总共发生了三件事: + +1. 在内存中开辟了一个对象空间。 + +2. 自动执行类中的__init__方法,并将这个对象空间(内存地址)传给了__init__方法的第一个位置参数self。 + +3. 在__init__ 方法中通过self给对象空间添加属性。 + +```python +class Human: + mind = '有思想' + work = '用两只腿走' + def __init__(self,name,sex,age,hobby): + self.n = name + self.s = sex + self.a = age + self.h = hobby + +obj = Human('chensong','男','18','男') +``` + +### 对象操作对象空间属性 + +**对象查询对象中所有属性。 `对象.__dict__`** + +```python +class Human: + + mind = '有思想' + language = '实用语言' + def __init__(self,name,sex,age,hobby): + # self 和 obj 指向的是同一个内存地址同一个空间,下面就是通过self给这个对象空间封装四个属性。 + self.n = name + self.s = sex + self.a = age + self.h = hobby + +obj = Human('chensong','男',18,'男') +print(obj.__dict__) +``` + +**对象操作对象中的单个属性。 万能的点.** + +```python +class Human: + + mind = '有思想' + language = '实用语言' + def __init__(self,name,sex,age,hobby): + # self 和 obj 指向的是同一个内存地址同一个空间,下面就是通过self给这个对象空间封装四个属性。 + self.n = name + self.s = sex + self.a = age + self.h = hobby + +obj = Human('chensong','男',18,'男') +obj.job = 'IT' +del obj.n +obj.s = '女' +print(obj.s) +print(obj.__dict__) +``` + +### 对象查看类中的属性 + +```python +class Human: + + mind = '有思想' + language = '实用语言' + def __init__(self,name,sex,age,hobby): + # self 和 obj 指向的是同一个内存地址同一个空间,下面就是通过self给这个对象空间封装四个属性。 + self.n = name + self.s = sex + self.a = age + self.h = hobby + +obj = Human('chensong','男',18,'男') +print(obj.mind) +print(obj.language) +obj.a = 666 +print(obj.a) +``` + +### 对象操作类中的方法 + +```python +class Human: + + mind = '有思想' + language = '实用语言' + def __init__(self,name,sex,age,hobby): + # self 和 obj 指向的是同一个内存地址同一个空间,下面就是通过self给这个对象空间封装四个属性。 + self.n = name + self.s = sex + self.a = age + self.h = hobby + + def work(self): + print(self) + print(self.n,'会工作') + + def tools(self): + print(self.n,'会使用工具') + +obj = Human('chensong','男',18,'男') +obj.work() +obj.tools() +``` + +**类中的方法一般都是通过对象执行的(出去类方法,静态方法外),并且对象执行这些方法都会自动将对象空间传给方法中的第一个参数self.** + +*self其实就是类中方法(函数)的第一个位置参数,只不过解释器会自动将调用这个函数的对象传给self。所以咱们把类中的方法的第一个参数约定俗成设置成self, 代表这个就是对象。* + +**一个类可以实例化多个对象** + diff --git a/02.面向对象/02.类空间与类之间的关系.md b/02.面向对象/02.类空间与类之间的关系.md new file mode 100644 index 0000000..b2f2ba0 --- /dev/null +++ b/02.面向对象/02.类空间与类之间的关系.md @@ -0,0 +1,314 @@ +# 类空间与类之间的关系 + +## 类的空间问题 + +### 添加对象属性 + +```python +class A: + def __init__(self,name): + self.name = name + + def func(self,sex): + self.sex = sex +``` + +在类外部添加 + +```python +class A: + def __init__(self,name): + self.name = name + + def func(self,sex): + self.sex = sexa + +obj = A('chensong') +obj.age = 18 +print(obj.__dict__) +``` + +类的内部添加 + +```python +class A: + def __init__(self,name): + self.name = name + + def func(self,sex): + self.sex = sex + +obj = A('chensong') +obj.func('男') +print(obj.__dict__) +``` + +**总结:对象的属性不仅可以在__init__里面添加,还可以在类的其他方法或者类的外面添加。** + +### 添加类的静态属性 + +```python +class A: + def __init__(self,name): + self.name = name + + def func(self,sex): + self.sex = sex + + def func1(self): + A.bbb = self + +A.aaa = 'test' # 类的外部添加 +print(A.__dict__) + +A.func1('123') # 类的内部添加 +print(A.__dict__) +``` + +**总结:类的属性不仅可以在类内部添加,还可以在类的外部添加** + +## 对象如何找到类的属性 + +对象空间 + +1. 产生这个对象空间,并有一个类对象指针 +2. 执行`__init__`方法,给对象封装属性 + +对象查找属性的顺序:先从对象空间找 ------> 类空间找 ------> 父类空间找 ------->..... + +类名查找属性的顺序:先从本类空间找 -------> 父类空间找--------> ........ + +上面的顺序都是单向不可逆,类名不可能找到对象的属性。 + +## 类与类之间的关系 + +类与类中存在以下关系: + +1. 依赖关系 +2. 关联关系 +3. 组合关系 +4. 聚合关系 +5. 实现关系 +6. 继承关系(类的三大特性之一:继承。) + +### 依赖关系 + +例:将大象装进冰箱,需要两个类, ⼀个是⼤象类, ⼀个是冰箱类 + +```python +class Elphant: + def __init__(self,name): + self.name = name + + def open(self): + ''' + 开门 + ''' + pass + + def close(self): + ''' + 关门 + ''' + pass + +class Refrigerator: + def open_door(self): + print('冰箱门打开了') + + def open_door(self): + print('冰箱门关上了') +``` + +将大象类和冰箱类进行依赖 + +```python +class Elphant: + def __init__(self,name): + self.name = name + + def open(self,obj1): + ''' + 开门 + ''' + print(self.name,'要开门了') + obj1.open_door() + + def close(self): + ''' + 关门 + ''' + pass + +class Refrigerator: + def open_door(self): + print('冰箱门打开了') + + def close_door(self): + print('冰箱门关上了') + +elphant1 = Elphant('大象') +haier = Refrigerator() +elphant1.open(haier) +``` + +### 关联,聚合,组合关系 + +其实这三个在代码上写法是⼀样的. 但是, 从含义上是不⼀样的. + +1. 关联关系. 两种事物必须是互相关联的. 但是在某些特殊情况下是可以更改和更换的. + +2. 聚合关系. 属于关联关系中的⼀种特例. 侧重点是xxx和xxx聚合成xxx. 各⾃有各⾃的声明周期. 比如电脑. 电脑⾥有CPU, 硬盘, 内存等等. 电脑挂了. CPU还是好的. 还是完整的个体 + +3. 组合关系. 属于关联关系中的⼀种特例. 写法上差不多. 组合关系比聚合还要紧密. 比如⼈的⼤脑, ⼼脏, 各个器官. 这些器官组合成⼀个⼈. 这时. ⼈如果挂了. 其他的东⻄也跟着挂了 + +**关联关系** + +```python +class Boy: + def __init__(self,name,girlFirend=None): + self.name = name + self.girlFriend = girlFirend + + def have_a_dinner(self): + if self.girlFriend: + print('%s 和 %s 一起晚饭'%(self.name,self.girlFriend.name)) + else: + print('单身狗,吃什么饭') + +class Girl: + def __init__(self,name): + self.name = name + +b = Boy('日天') +b.have_a_dinner() + +b.girlFriend = Girl('如花') +b.have_a_dinner() + +gg = Girl('花花') +bb = Boy('songsong',gg) +bb.have_a_dinner() +``` + +注意. 此时Boy和Girl两个类之间就是关联关系. 两个类的对象紧密联系着. 其中⼀个没有了. 另⼀个就孤单的不得了. 关联关系, 其实就是 我需要你. 你也属于我 + +学校和老师之间的关系 + +```python +class School: + + def __init__(self,name,address): + self.name = name + self.address = address + + +class Teacher: + + def __init__(self,name,school): + self.name = name + self.school = school + +s1 = School('北京校区','北京') +s2 = School('上海校区','上海') +s3 = School('深圳校区','深圳') + +t1 = Teacher('T1',s1) +t2 = Teacher('T2',s2) +t3 = Teacher('T3',s3) + +print(t1.school.name) +print(t2.school.name) +print(t3.school.name) +``` + +但是学校也是依赖于老师的,所以老师学校应该互相依赖。 + +```python +class School: + + def __init__(self,name,address): + self.name = name + self.address = address + self.teacher_list = [] + def append_teacher(self,teacher): + self.teacher_list.append(teacher) + + +class Teacher: + + def __init__(self,name,school): + self.name = name + self.school = school + +s1 = School('北京校区','北京') +s2 = School('上海校区','上海') +s3 = School('深圳校区','深圳') + +t1 = Teacher('T1',s1) +t2 = Teacher('T2',s2) +t3 = Teacher('T3',s3) + +s1.append_teacher(t1.name) +s1.append_teacher(t2.name) +s1.append_teacher(t3.name) + +print(s1.teacher_list) +``` + +**组合:将一个类的对象封装到另一个类的对象的属性中,就叫组合。** + +例:设计一个游戏,让游戏里面的人物互殴 + +```python +class Gamerole: + def __init__(self,name,ad,hp): + self.name = name + self.ad = ad + self.hp = hp + + def attack(self,p1): + p1.hp -= self.ad + print('%s攻击%s,%s掉了%s血,还剩%s'%(self.name,p1.name,p1.name,self.ad,p1.hp)) + +man = Gamerole('人',10,100) +dog = Gamerole('狗',50,100) + +dog.attack(man) +man.attack(dog) +``` + +加上一个武器类,让人使用武器攻击 + +```python +class Gamerole: + def __init__(self,name,ad,hp): + self.name = name + self.ad = ad + self.hp = hp + + def attack(self,p1): + p1.hp -= self.ad + print('%s攻击%s,%s掉了%s血,还剩%s'%(self.name,p1.name,p1.name,self.ad,p1.hp)) + + def equip_weapon(self,wea): + self.wea = wea + +class Weapon: + def __init__(self,name,ad): + self.name = name + self.ad = ad + def weapon_attack(self,p1,p2): + p2.hp = p2.hp - self.ad - p1.ad + print('%s利用%s攻击了%s,%s还剩%s血'%(p1.name,self.name,p2.name,p2.name,p2.hp)) + + + +man = Gamerole('人',10,100) +dog = Gamerole('狗',50,100) +stick = Weapon('木棍',40) + +man.equip_weapon(stick) +man.wea.weapon_attack(man,dog) +# 人利用木棍攻击了狗,狗还剩50血 +``` \ No newline at end of file diff --git a/02.面向对象/03.类的继承.md b/02.面向对象/03.类的继承.md new file mode 100644 index 0000000..ad6cb5f --- /dev/null +++ b/02.面向对象/03.类的继承.md @@ -0,0 +1,422 @@ +# 类的继承 + +## 面向对象的继承 + +不用继承创建对象 + +```python +class Person: + def __init__(self,name,sex,age): + self.name = name + self.age = age + self.sex = sex + +class Cat: + def __init__(self,name,sex,age): + self.name = name + self.age = age + self.sex = sex + +class Dog: + def __init__(self,name,sex,age): + self.name = name + self.age = age + self.sex = sex +``` + +使用继承的方式 + +```python +class Aniaml(object): + def __init__(self,name,sex,age): + self.name = name + self.age = age + self.sex = sex + +class Person(Aniaml): + pass + +class Cat(Aniaml): + pass + +class Dog(Aniaml): + pass +``` + +继承的有点也是显而易见的: + +1. 增加了类的耦合性(耦合性不宜多,宜精)。 + +2. 减少了重复代码。 + +3. 使得代码更加规范化,合理化。 + +## 继承的分类 + +上面的那个例子: + +- Aminal 叫做父类,基类,超类。 +- Person Cat Dog: 子类,派生类。 + +继承:可以分**单继承,多继承**。 + +这里需要补充一下python中类的种类(继承需要): + +在python2x版本中存在两种类.: + +- ⼀个叫**经典类**. 在python2.2之前. ⼀直使⽤的是经典类. 经典类在基类的根如果什么都不写. +- ⼀个叫**新式类**. 在python2.2之后出现了新式类. 新式类的特点是基类的根是object类。 + python3x版本中只有一种类: + python3中使⽤的都是**新式类**. 如果基类谁都不继承. 那这个类会默认继承 object + +## 单继承 + +### 类名,对象执行父类方法 + +```python +class Aniaml(object): + type_name = '动物类' + + def __init__(self,name,sex,age): + self.name = name + self.age = age + self.sex = sex + + def eat(self): + print('吃',self) + +class Person(Aniaml): + pass + +class Cat(Aniaml): + pass + +class Dog(Aniaml): + pass + +print(Person.type_name) +Person.eat('东西') +print(Person.type_name) + +p1 = Person('aaron','男',18) +print(p1.__dict__) +print(p1.type_name) +p1.type_name = '666' +print(p1) +p1.eat() +``` + +### 执行顺序 + +```python +class Aniaml(object): + type_name = '动物类' + + def __init__(self,name,sex,age): + self.name = name + self.age = age + self.sex = sex + + def eat(self): + print('吃',self) + +class Person(Aniaml): + + def eat(self): + print('%s 用筷子吃饭'%self.name) + +class Cat(Aniaml): + pass + +class Dog(Aniaml): + pass + +p1 = Person('eagle','男',18) +p1.eat() +``` + +### 同时执行类以及父类方法 + +方法一:如果想执行父类的func方法,这个方法并且子类中夜用,那么就在子类的方法中写上:父类.func(对象,其他参数) + +```python +class Aniaml(object): + type_name = '动物类' + def __init__(self,name,sex,age): + self.name = name + self.age = age + self.sex = sex + + def eat(self): + print('吃东西') + +class Person(Aniaml): + def __init__(self,name,sex,age,mind): + Aniaml.__init__(self,name,sex,age) + self.mind = mind + + def eat(self): + Aniaml.eat(111) + print('%s 吃饭'%self.name) +class Cat(Aniaml): + pass + +class Dog(Aniaml): + pass + +p1 = Person('aaron','男',18,'想吃东西') +p1.eat() +``` + +方法二:利用super,super().func(参数) + +```python +class Aniaml(object): + type_name = '动物类' + def __init__(self,name,sex,age): + self.name = name + self.age = age + self.sex = sex + + def eat(self): + print('吃东西') + +class Person(Aniaml): + def __init__(self,name,sex,age,mind): + # super(Person,self).__init__(name,sex,age) + super().__init__(name,sex,age) + self.mind = mind + + def eat(self): + super().eat() + print('%s 吃饭'%self.name) +class Cat(Aniaml): + pass + +class Dog(Aniaml): + pass + +p1 = Person('aaron','男',18,'想吃东西') +p1.eat() +``` + +单继承练习题 + +```python +class Base: + def __init__(self,num): + self.num = num + def func1(self): + print(self.num) + +class Foo(Base): + pass + +obj = Foo(123) +obj.func1() +# 运⾏的是Base中的func1 +``` + +```python +class Base: + def __init__(self,num): + self.num = num + def func1(self): + print(self.num) + +class Foo(Base): + def func1(self): + print("Foo.func1",self.num) + +obj = Foo(123) +obj.func1() +# 运⾏的是Foo中的func1 +``` + +```python +class Base: + def __init__(self, num): + self.num = num + def func1(self): + print(self.num) + self.func2() + def func2(self): + print("Base.func2") +class Foo(Base): + def func2(self): + print("Foo.func2") + +obj = Foo(123) +obj.func1() +# func1是Base中的 func2是⼦类中的 +``` + +```python +class Base: + def __init__(self, num): + self.num = num + def func1(self): + print(self.num) + self.func2() + def func2(self): + print(111, self.num) +class Foo(Base): + def func2(self): + print(222, self.num) + +lst = [Base(1), Base(2), Foo(3)] +for obj in lst: + obj.func2() +``` + +```python +class Base: + def __init__(self, num): + self.num = num + def func1(self): + print(self.num) + self.func2() + def func2(self): + print(111, self.num) +class Foo(Base): + def func2(self): + print(222, self.num) + +lst = [Base(1), Base(2), Foo(3)] +for obj in lst: + obj.func1() +``` + +## 多继承 + +```python +class ShenXian: # 神仙 + def fei(self): + print("神仙都会⻜") +class Monkey: # 猴 + def chitao(self): + print("猴⼦喜欢吃桃⼦") +class SunWukong(ShenXian, Monkey): # 孙悟空是神仙, 同时也是⼀只猴 + pass + +sxz = SunWukong() # 孙悟空 +sxz.chitao() # 会吃桃⼦ +sxz.fei() # 会⻜ +``` + +### 经典类的多继承 + +```python +class A: + pass +class B(A): + pass +class C(A): + pass +class D(B, C): + pass +class E: + pass +class F(D, E): + pass +class G(F, D): + pass +class H: + pass +class Foo(H, G): + pass +``` + +画图 + +![image-20210725220109579](03.%E7%B1%BB%E7%9A%84%E7%BB%A7%E6%89%BF/image-20210725220109579.png) + +在经典类中采⽤的是深度优先,遍历⽅案. 什么是深度优先. 就是⼀条路走到头. 然后再回来. 继续找下⼀个. + +类的MRO(method resolution order): Foo-> H -> G -> F -> E -> D -> B -> A -> C. + +### 新式类的多继承 + +#### mro序列 + +MRO是一个有序列表L,在类被创建时就计算出来。 + +通用计算公式为: + + mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), mro(Base2), [ Base1, Base2] )(其中Child继承自Base1, Base2) + +如果继承至一个基类:class B(A) +这时B的mro序列为 + + mro( B ) = mro( B(A) ) + = [B] + merge( mro(A) + [A] ) + = [B] + merge( [A] + [A] ) + = [B,A] + +如果继承至多个基类:class B(A1, A2, A3 …) +这时B的mro序列 + + mro(B) = mro( B(A1, A2, A3 …) ) + = [B] + merge( mro(A1), mro(A2), mro(A3) ..., [A1, A2, A3] ) + = ... + +计算结果为列表,列表中至少有一个元素即类自己,如上述示例[A1,A2,A3]。merge操作是C3算法的核心。 + +#### 表头和表尾 + +表头:列表的第一个元素 + +表尾:列表中表头以外的元素集合(可以为空) + +示例:列表:[A, B, C] 表头是A,表尾是B和C + +#### 列表之间的+操作 + +[A] + [B] = [A, B] + +merge操作示例: + +如计算merge( [E,O], [C,E,F,O], [C] ) +有三个列表 : ① ② ③ + + 1 merge不为空,取出第一个列表列表①的表头E,进行判断 + 各个列表的表尾分别是[O], [E,F,O],E在这些表尾的集合中,因而跳过当前当前列表 + 2 取出列表②的表头C,进行判断 + C不在各个列表的集合中,因而将C拿出到merge外,并从所有表头删除 + merge( [E,O], [C,E,F,O], [C]) = [C] + merge( [E,O], [E,F,O] ) + 3 进行下一次新的merge操作 ...... + --------------------- + +![image-20210725220122519](03.%E7%B1%BB%E7%9A%84%E7%BB%A7%E6%89%BF/image-20210725220122519.png) + +计算mro(A)方式: + + mro(A) = mro( A(B,C) ) + + 原式= [A] + merge( mro(B),mro(C),[B,C] ) + + mro(B) = mro( B(D,E) ) + = [B] + merge( mro(D), mro(E), [D,E] ) # 多继承 + = [B] + merge( [D,O] , [E,O] , [D,E] ) # 单继承mro(D(O))=[D,O] + = [B,D] + merge( [O] , [E,O] , [E] ) # 拿出并删除D + = [B,D,E] + merge([O] , [O]) + = [B,D,E,O] + + mro(C) = mro( C(E,F) ) + = [C] + merge( mro(E), mro(F), [E,F] ) + = [C] + merge( [E,O] , [F,O] , [E,F] ) + = [C,E] + merge( [O] , [F,O] , [F] ) # 跳过O,拿出并删除 + = [C,E,F] + merge([O] , [O]) + = [C,E,F,O] + + 原式= [A] + merge( [B,D,E,O], [C,E,F,O], [B,C]) + = [A,B] + merge( [D,E,O], [C,E,F,O], [C]) + = [A,B,D] + merge( [E,O], [C,E,F,O], [C]) # 跳过E + = [A,B,D,C] + merge([E,O], [E,F,O]) + = [A,B,D,C,E] + merge([O], [F,O]) # 跳过O + = [A,B,D,C,E,F] + merge([O], [O]) + = [A,B,D,C,E,F,O] + +那既然python提供了. 为什么我们还要如此⿇烦的计算MRO呢? 因为笔 +试.......你在笔试的时候, 是没有电脑的. 所以这个算法要知道. 并且简单的计算要会. 正式项⽬ +开发的时候很少有⼈这么去写代码. \ No newline at end of file diff --git a/02.面向对象/03.类的继承/image-20210725220109579.png b/02.面向对象/03.类的继承/image-20210725220109579.png new file mode 100644 index 0000000..c288544 Binary files /dev/null and b/02.面向对象/03.类的继承/image-20210725220109579.png differ diff --git a/02.面向对象/03.类的继承/image-20210725220122519.png b/02.面向对象/03.类的继承/image-20210725220122519.png new file mode 100644 index 0000000..5754f1a Binary files /dev/null and b/02.面向对象/03.类的继承/image-20210725220122519.png differ diff --git a/02.面向对象/04.封装与多态.md b/02.面向对象/04.封装与多态.md new file mode 100644 index 0000000..900c0fe --- /dev/null +++ b/02.面向对象/04.封装与多态.md @@ -0,0 +1,313 @@ +# 封装与多态 + +python面向对象的三大特性:继承,封装,多态。 + +1. **封装**: 把很多数据封装到⼀个对象中. 把固定功能的代码封装到⼀个代码块, 函数, 对象, 打包成模块. 这都属于封装的思想. 具体的情况具体分析. 比如. 你写了⼀个很⽜B的函数. 那这个也可以被称为封装. 在⾯向对象思想中. 是把⼀些看似⽆关紧要的内容组合到⼀起统⼀进⾏存储和使⽤. 这就是封装. + +2. **继承**: ⼦类可以⾃动拥有⽗类中除了私有属性外的其他所有内容. 说⽩了, ⼉⼦可以随便⽤爹的东⻄. 但是朋友们, ⼀定要认清楚⼀个事情. 必须先有爹, 后有⼉⼦. 顺序不能乱, 在python中实现继承非常简单. 在声明类的时候, 在类名后⾯添加⼀个⼩括号,就可以完成继承关系. 那么什么情况可以使⽤继承呢? 单纯的从代码层⾯上来看. 两个类具有相同的功能或者特征的时候. 可以采⽤继承的形式. 提取⼀个⽗类, 这个⽗类中编写着两个类相同的部分. 然后两个类分别取继承这个类就可以了. 这样写的好处是我们可以避免写很多重复的功能和代码. 如果从语义中去分析的话. 会简单很多. 如果语境中出现了x是⼀种y. 这时, y是⼀种泛化的概念. x比y更加具体. 那这时x就是y的⼦类. 比如. 猫是⼀种动物. 猫继承动物. 动物能动. 猫也能动. 这时猫在创建的时候就有了动物的"动"这个属性. 再比如, ⽩骨精是⼀个妖怪. 妖怪天⽣就有⼀个比较不好的功能叫"吃⼈", ⽩骨精⼀出⽣就知道如何"吃⼈". 此时 ⽩骨精继承妖精. +3. **多态**: 同⼀个对象, 多种形态. 这个在python中其实是很不容易说明⽩的. 因为我们⼀直在⽤. 只是没有具体的说. 比如. 我们创建⼀个变量a = 10 , 我们知道此时a是整数类型. 但是我们可以通过程序让a = "hello", 这时, a⼜变成了字符串类型. 这是我们都知道的. 但是, 我要告诉你的是. 这个就是多态性. 同⼀个变量a可以是多种形态。 + +## 封装 + +第一步:将内容封装到某处 + +```python +class Foo: + def __init__(self,name,age): + self.name = name + self.age = age + +obj1 = Foo('chensong',18) +obj2 = Foo('aaron',16) +``` + +第二步:从某处调用被封装的内容 + +```python +class Foo: + def __init__(self,name,age): + self.name = name + self.age = age + + def detail(self): + print(self.name) + print(self.age) + +obj1 = Foo('chensong',18) +obj2 = Foo('aaron',16) + +print(obj1.name) +print(obj2.age) +# 通过对象直接调用被封装的内容 + +obj1.detail() +obj2.detail() +# 通过self间接调用被封装的内容 +``` + +## 多态 + +多态,同一个对象,多种形态。python默认支持多态。 + +python中有一句谚语说的好,你看起来像鸭子,那么你就是鸭子。 +对于代码上的解释其实很简答: + +```python +class A: + def f1(self): + print('in A f1') + + def f2(self): + print('in A f2') + + +class B: + def f1(self): + print('in B f1') + + def f2(self): + print('in B f2') + +obj = A() +obj.f1() +obj.f2() + +obj2 = B() +obj2.f1() +obj2.f2() +# A 和 B两个类完全没有耦合性,但是在某种意义上他们却统一了一个标准。 +# 对相同的功能设定了相同的名字,这样方便开发,这两个方法就可以互成为鸭子类型。 + +# 这样的例子比比皆是:str tuple list 都有 index方法,这就是统一了规范。 +# str bytes 等等 这就是互称为鸭子类型。 +``` + +## 类的约束 + +写一个支付功能 + +```python +class QQpay: + def pay(self,money): + print('使用qq支付%s元' % money) + +class Alipay: + def pay(self,money): + print('使用阿里支付%s元' % money) + +a = Alipay() +a.pay(100) + +b = QQpay() +b.pay(200) +``` + +统一一下付款方式 + +```python +class QQpay: + def pay(self,money): + print('使用qq支付%s元' % money) + +class Alipay: + def pay(self,money): + print('使用阿里支付%s元' % money) + +def pay(obj,money): + obj.pay(money) + + +a = Alipay() +b = QQpay() + +pay(a,100) +pay(b,200) +``` + +如果后期添加微信支付,但是没有统一标准,换个程序员就可能写成这样 + +```python +class QQpay: + def pay(self,money): + print('使用qq支付%s元' % money) + +class Alipay: + def pay(self,money): + print('使用阿里支付%s元' % money) + +class Wechatpay: + def fuqian(self,money): + print('使用微信支付%s元' % money) + +def pay(obj,money): + obj.pay(money) + + +a = Alipay() +b = QQpay() + +pay(a,100) +pay(b,200) + +c = Wechatpay() +c.fuqian(300) +``` + +所以此时我们要用到对类的约束,对类的约束有两种: + +1. 提取⽗类. 然后在⽗类中定义好⽅法. 在这个⽅法中什么都不⽤⼲. 就抛⼀个异常就可以了. 这样所有的⼦类都必须重写这个⽅法. 否则. 访问的时候就会报错. + +2. 使⽤元类来描述⽗类. 在元类中给出⼀个抽象⽅法. 这样⼦类就不得不给出抽象⽅法的具体实现. 也可以起到约束的效果. + +- 先用第一种方法解决问题 + +```python +class Payment: + """ + 此类什么都不做,就是制定一个标准,谁继承我,必须定义我里面的方法。 + """ + def pay(self,money): + raise Exception("你没有实现pay方法") + +class QQpay(Payment): + def pay(self,money): + print('使用qq支付%s元' % money) + +class Alipay(Payment): + def pay(self,money): + print('使用阿里支付%s元' % money) + +class Wechatpay(Payment): + def fuqian(self,money): + print('使用微信支付%s元' % money) + + +def pay(obj,money): + obj.pay(money) + +a = Alipay() +b = QQpay() +c = Wechatpay() +pay(a,100) +pay(b,200) +pay(c,300) +``` + +- 引入抽象类的概念处理 + +```python +from abc import ABCMeta,abstractmethod +class Payment(metaclass=ABCMeta): # 抽象类 接口类 规范和约束 metaclass指定的是一个元类 + @abstractmethod + def pay(self):pass # 抽象方法 + +class Alipay(Payment): + def pay(self,money): + print('使用支付宝支付了%s元'%money) + +class QQpay(Payment): + def pay(self,money): + print('使用qq支付了%s元'%money) + +class Wechatpay(Payment): + # def pay(self,money): + # print('使用微信支付了%s元'%money) + def recharge(self):pass + +def pay(a,money): + a.pay(money) + +a = Alipay() +a.pay(100) +pay(a,100) # 归一化设计:不管是哪一个类的对象,都调用同一个函数去完成相似的功能 +q = QQpay() +q.pay(100) +pay(q,100) +w = Wechatpay() +pay(w,100) # 到用的时候才会报错 + + + +# 抽象类和接口类做的事情 :建立规范 +# 制定一个类的metaclass是ABCMeta, +# 那么这个类就变成了一个抽象类(接口类) +# 这个类的主要功能就是建立一个规范 +``` + +总结: 约束. 其实就是⽗类对⼦类进⾏约束. ⼦类必须要写xxx⽅法. 在python中约束的⽅式和⽅法有两种: + +1. 使⽤抽象类和抽象⽅法, 由于该⽅案来源是java和c#. 所以使⽤频率还是很少的 + +2. 使⽤⼈为抛出异常的⽅案. 并且尽量抛出的是NotImplementError. 这样比较专业, ⽽且错误比较明确.(推荐) + +## super()深入了解 + +**super是严格按照类的继承顺序执行!!!** + +```python +class A: + def f1(self): + print('in A f1') + + def f2(self): + print('in A f2') + + +class Foo(A): + def f1(self): + super().f2() + print('in A Foo') + + +obj = Foo() +obj.f1() +``` + +```python +class A: + def f1(self): + print('in A') + +class Foo(A): + def f1(self): + super().f1() + print('in Foo') + +class Bar(A): + def f1(self): + print('in Bar') + +class Info(Foo,Bar): + def f1(self): + super().f1() + print('in Info f1') + +obj = Info() +obj.f1() + +print(Info.mro()) +``` + +```python +class A: + def f1(self): + print('in A') + +class Foo(A): + def f1(self): + super().f1() + print('in Foo') + +class Bar(A): + def f1(self): + print('in Bar') + +class Info(Foo,Bar): + def f1(self): + super(Foo,self).f1() + print('in Info f1') + +obj = Info() +obj.f1() +``` + diff --git a/02.面向对象/05.类的成员.md b/02.面向对象/05.类的成员.md new file mode 100644 index 0000000..653b653 --- /dev/null +++ b/02.面向对象/05.类的成员.md @@ -0,0 +1,497 @@ +# 类的成员 + +## 细分类的组成成员 + +之前咱们讲过类大致分两块区域 + +```python +class A: + name = '陈松' + +# 第一部分:静态字段(静态变量)部分 + + def __init__(self): + pass + def func(self): + pass + +# 第二部分:方法部分 +``` + +每个区域详细划分 + +```python +class A: + + company_name = '陈松' # 静态变量(静态字段) + __iphone = '132333xxxx' # 私有静态变量(私有静态字段) + + def __init__(self,name,age): #特殊方法 + self.name = name #对象属性(普通字段) + self.__age = age # 私有对象属性(私有普通字段) + + def func1(self): # 普通方法 + pass + + def __func(self): #私有方法 + print(666) + + @classmethod # 类方法 + def class_func(cls): + """ 定义类方法,至少有一个cls参数 """ + print('类方法') + + @staticmethod #静态方法 + def static_func(): + """ 定义静态方法 ,无默认参数""" + print('静态方法') + + @property # 属性 + def prop(self): + pass +``` + +## 类的私有成员 + +对于每一个类的成员而言都有两种形式: + +- 公有成员,在任何地方都能访问 +- 私有成员,只有在类的内部才能方法 + +**私有成员和公有成员的访问限制不同:** + +静态字段(静态属性) + +- 公有静态字段:类可以访问;类内部可以访问;派生类中可以访问 +- 私有静态字段:仅类内部可以访问; + +```python +class C: + + name = "公有静态字段" + + def func(self): + print (C.name) + +class D(C): + + def show(self): + print (C.name) + + +print(C.name) # 类访问 + +obj = C() +obj.func() # 类内部可以访问 + +obj_son = D() +obj_son.show() # 派生类中可以访问 +``` + +```python +class C: + + __name = "私有静态字段" + + def func(self): + print (C.__name) + +class D(C): + + def show(self): + print (C.__name) + + +print(C.__name) # 不可在外部访问 + +obj = C() +print(C.__name) # 不可在外部访问 +obj.func() # 类内部可以访问 + +obj_son = D() +obj_son.show() #不可在派生类中可以访问 +``` + +普通字段(对象属性) + +公有普通字段:对象可以访问;类内部可以访问;派生类中可以访问 +私有普通字段:仅类内部可以访问; + +```python +class C: + + def __init__(self): + self.foo = "公有字段" + + def func(self): + print(self.foo) # 类内部访问 + +class D(C): + + def show(self): + print(self.foo) # 派生类中访问 + +obj = C() + +obj.foo # 通过对象访问 +obj.func() # 类内部访问 + +obj_son = D(); +obj_son.show() # 派生类中访问 +``` + +```python +class C: + + def __init__(self): + self.__foo = "私有字段" + + def func(self): + print self.foo  # 类内部访问 + +class D(C): + + def show(self): + print self.foo # 派生类中访问 + +obj = C() + +obj.__foo # 通过对象访问 ==> 错误 +obj.func() # 类内部访问 ==> 正确 + +obj_son = D(); +obj_son.show() # 派生类中访问 ==> 错误 +``` + +```python +class C: + + def __init__(self): + self.__foo = "私有字段" + + def func(self): + print(self.__foo) # 类内部访问 + +class D(C): + + def show(self): + print(self.__foo) # 派生类中访问 + +obj = C() + +print(obj.__foo) # 通过对象访问 ==> 错误 +obj.func() # 类内部访问 ==> 正确 + +obj_son = D() +obj_son.show() # 派生类中访问 ==> 错误 +``` + +方法: + +公有方法:对象可以访问;类内部可以访问;派生类中可以访问 +私有方法:仅类内部可以访问; + +```python +class C: + + def __init__(self): + pass + + def add(self): + print('in C') + + +class D(C): + + def show(self): + print('in D') + + def func(self): + self.show() + + +obj = D() +obj.show() # 通过对象访问 +obj.func() # 类内部访问 +obj.add() # 派生类中访问 +``` + +```python +class C: + + def __init__(self): + pass + + def __add(self): + print('in C') + +class D(C): + + def __show(self): + print('in D') + + def func(self): + self.__show() +obj = D() +obj.__show() # 通过不能对象访问 +obj.func() # 类内部可以访问 +obj.__add() # 派生类中不能访问 +``` + +总结: + +对于这些私有成员来说,他们只能在类的内部使用,不能再类的外部以及派生类中使用. + +**ps:非要访问私有成员的话,可以通过 对象._类__属性名,但是绝对不允许!!!** + +为什么可以通过._类__私有成员名访问呢?因为类在创建时,如果遇到了私有成员(包括私有静态字段,私有普通字段,私有方法)它会将其保存在内存时自动在前面加上_类名. + +## 类的其他成员 + +这里的其他成员主要就是类方法: + +方法包括:普通方法、静态方法和类方法,三种方法在**内存中都归属于类**,区别在于调用方式不同。 + +**实例方法** + + 定义:第一个参数必须是实例对象,该参数名一般约定为“self”,通过它来传递实例的属性和方法(也可以传类的属性和方法); + + 调用:只能由实例对象调用。 + +**类方法** + + 定义:使用装饰器@classmethod。第一个参数必须是当前类对象,该参数名一般约定为“cls”,通过它来传递类的属性和方法(不能传实例的属性和方法); + + 调用:实例对象和类对象都可以调用。 + +**静态方法** + + 定义:使用装饰器@staticmethod。参数随意,没有“self”和“cls”参数,但是方法体中不能使用类或实例的任何属性和方法; + + 调用:实例对象和类对象都可以调用。 + +**双下方法(后面会讲到)** + + 定义:双下方法是特殊方法,他是解释器提供的 由爽下划线加方法名加爽下划线 __方法名__的具有特殊意义的方法,双下方法主要是python源码程序员使用的, + +    我们在开发中尽量不要使用双下方法,但是深入研究双下方法,更有益于我们阅读源码。 + + 调用:不同的双下方法有不同的触发方式,就好比盗墓时触发的机关一样,不知不觉就触发了双下方法,例如:__init__ + +### 类方法 + +使用装饰器@classmethod。 + +原则上,类方法是将类本身作为对象进行操作的方法。假设有个方法,且这个方法在逻辑上采用类本身作为对象来调用更合理,那么这个方法就可以定义为类方法。另外,如果需要继承,也可以定义为类方法。 + +如下场景: + +假设我有一个学生类和一个班级类,想要实现的功能为: + 执行班级人数增加的操作、获得班级的总人数; + 学生类继承自班级类,每实例化一个学生,班级人数都能增加; + 最后,我想定义一些学生,获得班级中的总人数。 + +**思考**:这个问题用类方法做比较合适,为什么?因为我实例化的是学生,但是如果我从学生这一个实例中获得班级总人数,在逻辑上显然是不合理的。同时,如果想要获得班级总人数,如果生成一个班级的实例也是没有必要的。 + +```python +class Student: + __num = 0 + + def __init__(self, name, age): + self.name = name + self.age = age + Student.addNum() # 写在__new__方法中比较合适,但是现在还没有学,暂且放到这里 + + @classmethod + def addNum(cls): + cls.__num += 1 + + @classmethod + def getNum(cls): + return cls.__num + + +Student('陈松', 18) +Student('阿松', 36) +Student('松松', 73) +print(Student.getNum()) +``` + +### 静态方法 + +使用装饰器@staticmethod。 + +静态方法是类中的函数,不需要实例。静态方法主要是用来存放逻辑性的代码,逻辑上属于类,但是和类本身没有关系,也就是说在静态方法中,不会涉及到类中的属性和方法的操作。可以理解为,静态方法是个**独立的、单纯的**函数,它仅仅托管于某个类的名称空间中,便于使用和维护。 + +譬如,我想定义一个关于时间操作的类,其中有一个获取当前时间的函数。 + +```python +import time + +class TimeTest(object): + def __init__(self, hour, minute, second): + self.hour = hour + self.minute = minute + self.second = second + + @staticmethod + def showTime(): + return time.strftime("%H:%M:%S", time.localtime()) + + +print(TimeTest.showTime()) +t = TimeTest(2, 10, 10) +nowTime = t.showTime() +print(nowTime) +``` + +### 属性 + +property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值 + + 例一:BMI指数(bmi是计算而来的,但很明显它听起来像是一个属性而非方法,如果我们将其做成一个属性,更便于理解) + + 成人的BMI数值: + 过轻:低于18.5 + 正常:18.5-23.9 + 过重:24-27 + 肥胖:28-32 + 非常肥胖, 高于32 +   体质指数(BMI)=体重(kg)÷身高^2(m) +   EX:70kg÷(1.75×1.75)=22.86 + +```python +class People: + def __init__(self,name,weight,height): + self.name=name + self.weight=weight + self.height=height + @property + def bmi(self): + return self.weight / (self.height**2) + +p1=People('陈松',75,1.85) +print(p1.bmi) +``` + +将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了**统一访问的原则** + +由于新式类中具有三种访问方式,我们可以根据他们几个属性的访问特点,分别将三个方法定义为对同一个属性:获取、修改、删除 + +```python +class Foo: + @property + def AAA(self): + print('get的时候运行我啊') + + @AAA.setter + def AAA(self,value): + print('set的时候运行我啊') + + @AAA.deleter + def AAA(self): + print('delete的时候运行我啊') + +#只有在属性AAA定义property后才能定义AAA.setter,AAA.deleter +f1=Foo() +f1.AAA +f1.AAA='aaa' +del f1.AAA +``` + +或者 + +```python +class Foo: + def get_AAA(self): + print('get的时候运行我啊') + + def set_AAA(self,value): + print('set的时候运行我啊') + + def delete_AAA(self): + print('delete的时候运行我啊') + AAA=property(get_AAA,set_AAA,delete_AAA) #内置property三个参数与get,set,delete一一对应 + +f1=Foo() +f1.AAA +f1.AAA='aaa' +del f1.AAA +``` + +商品的例子 + +```python +class Goods(object): + + def __init__(self): + # 原价 + self.original_price = 100 + # 折扣 + self.discount = 0.8 + + @property + def price(self): + # 实际价格 = 原价 * 折扣 + new_price = self.original_price * self.discount + return new_price + + @price.setter + def price(self, value): + self.original_price = value + + @price.deleter + def price(self): + del self.original_price + +obj = Goods() +print(obj.price) # 获取商品价格 +obj.price = 200 # 修改商品原价 +print(obj.price) +del obj.price # 删除商品原价 +``` + +## isinstace 与 issubclass + +isinstance(a,b):判断a是否是b类(或者b类的派生类)实例化的对象 + +```python +class A: + pass + +class B(A): + pass + +obj = B() + +print(isinstance(obj,B)) +print(isinstance(obj,A)) +``` + +issubclass(a,b): 判断a类是否是b类(或者b的派生类)的派生类 + +```python +class A: + pass + +class B(A): + pass + +class C(B): + pass + +print(issubclass(B,A)) +print(issubclass(C,A)) +``` + +思考:那么 list str tuple dict等这些类与 Iterble类 的关系是什么? + +```python +from collections import Iterable + +print(isinstance([1,2,3], list)) # True +print(isinstance([1,2,3], Iterable)) # True +print(issubclass(list,Iterable)) # True + +# 由上面的例子可得,这些可迭代的数据类型,list str tuple dict等 都是 Iterable的子类。 +``` \ No newline at end of file diff --git a/02.面向对象/06.反射与双下方法.md b/02.面向对象/06.反射与双下方法.md new file mode 100644 index 0000000..7392f35 --- /dev/null +++ b/02.面向对象/06.反射与双下方法.md @@ -0,0 +1,639 @@ +# 反射与双下方法 + +## 反射 + +python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射) + +四个可以实现自省的函数 + +下列方法适用于类和对象(一切皆对象,类本身也是一个对象) + +**对对象的反射** + +```python +class Foo: + f = '类的静态变量' + def __init__(self,name,age): + self.name=name + self.age=age + + def say_hi(self): + print('hi,%s'%self.name) + +obj=Foo('陈松',73) + +# 检测是否含有某属性 +print(hasattr(obj,'name')) +print(hasattr(obj,'say_hi')) + +# 获取属性 +n=getattr(obj,'name') +print(n) +func=getattr(obj,'say_hi') +func() + +print(getattr(obj,'aaaaaaaa','不存在啊')) # 报错 + +# 设置属性 +setattr(obj,'sb',True) +setattr(obj,'show_name',lambda self:self.name+'sb') +print(obj.__dict__) +print(obj.show_name(obj)) + +# 删除属性 +delattr(obj,'age') +delattr(obj,'show_name') +# delattr(obj,'show_name111') # 不存在,则报错 + +print(obj.__dict__) +``` + +**对类的反射** + +```python +class Foo(object): + staticField = "test" + + def __init__(self): + self.name = '陈松' + + def func(self): + return 'func' + + @staticmethod + def bar(): + return 'bar' + + +print(getattr(Foo, 'staticField')) +print(getattr(Foo, 'func')) +print(getattr(Foo, 'bar')) +``` + +当前模块的反射 + +```python +import sys + +def s1(): + print('s1') + +def s2(): + print('s2') + +this_module = sys.modules[__name__] + +print(hasattr(this_module, 's1')) +print(getattr(this_module, 's2')) +``` + +其他模块的反射 + + 程序目录: + module_test.py + test.py + + 当前文件: + test.py + +```python +import module_test as obj + +obj.test() + +print(hasattr(obj,'test')) + +getattr(obj,'test')() +``` + +举例: + +使用反射前 + +```python +class User: + def login(self): + print('欢迎来到登录页面') + + def register(self): + print('欢迎来到注册页面') + + def save(self): + print('欢迎来到存储页面') + + +while 1: + choose = input('>>>').strip() + if choose == 'login': + obj = User() + obj.login() + + elif choose == 'register': + obj = User() + obj.register() + + elif choose == 'save': + obj = User() + obj.save() +``` + +用了反射之后 + +```python +class User: + def login(self): + print('欢迎来到登录页面') + + def register(self): + print('欢迎来到注册页面') + + def save(self): + print('欢迎来到存储页面') + + +user = User() +while 1: + choose = input('>>>').strip() + if hasattr(user, choose): + func = getattr(user, choose) + func() + else: + print('输入错误。。。。') +``` + +## 函数 vs 方法 + +### 通过打印函数(方法)名确定 + +```python +def func(): + pass + +print(func) + +class A: + def func(self): + pass + +print(A.func) +obj = A() +print(obj.func) +``` + +### 通过types模块验证 + +```python +from types import FunctionType +from types import MethodType + +def func(): + pass + +class A: + def func(self): + pass + +obj = A() + +print(isinstance(func,FunctionType)) +print(isinstance(A.func,FunctionType)) +print(isinstance(obj.func,FunctionType)) +print(isinstance(obj.func,MethodType)) +``` + +### 静态方法是函数 + +```python +from types import FunctionType +from types import MethodType + + +class A: + + def func(self): + pass + + @classmethod + def func1(self): + pass + + @staticmethod + def func2(self): + pass + + +obj = A() + +# 静态方法其实是函数 +print(isinstance(A.func2,FunctionType)) +print(isinstance(obj.func2,FunctionType)) +``` + +### 函数与方法的区别 + +那么,函数和方法除了上述的不同之处,我们还总结了一下几点区别。 + +1. 函数的是显式传递数据的。如我们要指明为len()函数传递一些要处理数据。 + +2. 函数则跟对象无关。 + +3. 方法中的数据则是隐式传递的。 + +4. 方法可以操作类内部的数据。 + +5. 方法跟对象是关联的。如我们在用strip()方法是,是不是都是要通过str对象调用,比如我们有字符串s,然后s.strip()这样调用。是的,strip()方法属于str对象。 + +我们或许在日常中会口语化称呼函数和方法时不严谨,但是我们心中要知道二者之间的区别。 + +在其他语言中,如Java中只有方法,C中只有函数,C++么,则取决于是否在类中 + +## 双下方法 + +### `__len__` + +```python +class B: + def __len__(self): + return 666 + +b = B() +print(len(b)) # len 一个对象就会触发 __len__方法。 + +class A: + def __init__(self): + self.a = 1 + self.b = 2 + + def __len__(self): + return len(self.__dict__) +a = A() +print(len(a)) +``` + +### `__hash__` + +```python +class A: + def __init__(self): + self.a = 1 + self.b = 2 + + def __hash__(self): + return hash(str(self.a)+str(self.b)) +a = A() +print(hash(a)) +``` + +### `__str__` + +如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。 + +```python +class A: + def __init__(self): + pass + def __str__(self): + return '陈松' +a = A() +print(a) +print('%s' % a) +``` + +### `__repr__` + +如果一个类中定义了__repr__方法,那么在repr(对象) 时,默认输出该方法的返回值。 + +```python +class A: + def __init__(self): + pass + def __repr__(self): + return '陈松' +a = A() +print(repr(a)) +print('%r'%a) +``` + +### `__call__` + +对象后面加括号,触发执行。 + +注:构造方法__new__的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()() + +```python +class Foo: + + def __init__(self): + print('__init__') + + def __call__(self, *args, **kwargs): + print('__call__') + + +obj = Foo() # 执行 __init__ +obj() # 执行 __call__ +``` + +### `__eq__` + +```python +class A: + def __init__(self): + self.a = 1 + self.b = 2 + + def __eq__(self,obj): + if self.a == obj.a and self.b == obj.b: + return True +a = A() +b = A() +print(a == b) +``` + +### `__del__` + +析构方法,当对象在内存中被释放时,自动触发执行。 + +注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。 + +### `__new__` + +- `__new__()` 方法是在类准备将自身实例化时调用。 +- `__new__()` 方法始终都是类的静态方法,即使没有被加上静态方法装饰器。 +- 通常来说,新式类开始实例化时,`__new__()`方法会返回cls(cls指代当前类)的实例,然后该类的`__init__()`方法作为构造方法会接收这个实例(即self)作为自己的第一个参数,然后依次传入`__new__()`方法中接收的位置参数和命名参数。 + +```python +class A: + def __init__(self): + self.x = 1 + print('in init function') + def __new__(cls, *args, **kwargs): + print('in new function') + return object.__new__(A, *args, **kwargs) + +a = A() +print(a.x) +``` + +单例模式 + +```python +class A: + __instance = None + def __new__(cls, *args, **kwargs): + if cls.__instance is None: + obj = object.__new__(cls) + cls.__instance = obj + return cls.__instance +``` + +单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。 +**【采用单例模式动机、原因】** +对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。如在Windows中就只能打开一个任务管理器。如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪一个才是真实的状态。因此有时确保系统中某个对象的唯一性即一个类只能有一个实例非常重要。 +如何保证一个类只有一个实例并且这个实例易于被访问呢?定义一个全局变量可以确保对象随时都可以被访问,但不能防止我们实例化多个对象。一个更好的解决办法是让类自身负责保存它的唯一实例。这个类可以保证没有其他实例被创建,并且它可以提供一个访问该实例的方法。这就是单例模式的模式动机。 +**【单例模式优缺点】** +**【优点】** +一、实例控制 +单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。 +二、灵活性 +因为类控制了实例化过程,所以类可以灵活更改实例化过程。 +**【缺点】** +一、开销 +虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销。可以通过使用静态初始化解决此问题。 +二、可能的开发混淆 +使用单例对象(尤其在类库中定义的对象)时,开发人员必须记住自己不能使用new关键字实例化对象。因为可能无法访问库源代码,因此应用程序开发人员可能会意外发现自己无法直接实例化此类。 +三、对象生存期 +不能解决删除单个对象的问题。在提供内存管理的语言中(例如基于.NET Framework的语言),只有单例类能够导致实例被取消分配,因为它包含对该实例的私有引用。在某些语言中(如 C++),其他类可以删除对象实例,但这样会导致单例类中出现悬浮引用 + +### `__item__`系列 + +```python +class Foo: + def __init__(self,name): + self.name=name + + def __getitem__(self, item): + print(self.__dict__[item]) + + def __setitem__(self, key, value): + self.__dict__[key]=value + print('赋值成功') + + def __delitem__(self, key): + print('del obj[key]时,我执行') + self.__dict__.pop(key) + + def __delattr__(self, item): + print('del obj.key时,我执行') + self.__dict__.pop(item) + +f1=Foo('sb') +f1['age']=18 +f1['age1']=19 +del f1.age1 +del f1['age'] +f1['name']='mingzi' +print(f1.__dict__) +``` + +### 上下文管理器相关 + +`__enter__` `__exit__` + +```python +class A: + + def __init__(self, text): + self.text = text + + def __enter__(self): # 开启上下文管理器对象时触发此方法 + self.text = self.text + '您来啦' + return self # 将实例化的对象返回f1 + + def __exit__(self, exc_type, exc_val, exc_tb): # 执行完上下文管理器对象f1时触发此方法 + self.text = self.text + '这就走啦' + + +with A('大爷') as f1: + print(f1.text) +print(f1.text) +``` + +自定义文件管理器 + +```python +class Diycontextor: + def __init__(self, name, mode): + self.name = name + self.mode = mode + + def __enter__(self): + print("Hi enter here!!") + self.filehander = open(self.name, self.mode) + return self.filehander + + def __exit__(self,*args): + print("Hi exit here") + self.filehander.close() + + +with Diycontextor('config', 'r') as f: + for i in f: + print(i.strip()) +``` + +案例 + +```python +class StarkConfig: + def __init__(self, num): + self.num = num + + def run(self): + self() + + def __call__(self, *args, **kwargs): + print(self.num) + + +class RoleConfig(StarkConfig): + def __call__(self, *args, **kwargs): + print(345) + + def __getitem__(self, item): + return self.num[item] + + +v1 = RoleConfig('abcedf') +v2 = StarkConfig('2333') +print(v1[3]) +## print(v2[2]) +v1.run() +``` + +```python +class UserInfo: + pass + + +class Department: + pass + + +class StarkConfig: + def __init__(self, num): + self.num = num + + def changelist(self, request): + print(self.num, request) + + def run(self): + self.changelist(999) + + +class RoleConfig(StarkConfig): + def changelist(self, request): + print(666, self.num) + + +class AdminSite: + + def __init__(self): + self._registry = {} + + def register(self, k, v): + self._registry[k] = v + + +site = AdminSite() +site.register(UserInfo, StarkConfig) +# 1 +obj = site._registry[UserInfo]() + +# 2 +# obj = site._registry[UserInfo](100) +obj.run() +``` + +```python +class UserInfo: + pass + +class Department: + pass + +class StarkConfig: + def __init__(self,num): + self.num = num + + def changelist(self,request): + print(self.num,request) + + def run(self): + self.changelist(999) + +class RoleConfig(StarkConfig): + def changelist(self,request): + print(666,self.num) + + +class AdminSite: + + def __init__(self): + self._registry = {} + + def register(self,k,v): + self._registry[k] = v(k) + +site = AdminSite() +site.register(UserInfo,StarkConfig) +site.register(Department,RoleConfig) + +for k,row in site._registry.items(): + row.run() +``` + +```python +class A: + list_display = [] + + def get_list(self): + self.list_display.insert(0, 33) + return self.list_display + + +s1 = A() +print(s1.get_list()) +``` + +```python +class A: + list_display = [1, 2, 3] + def __init__(self): + self.list_display = [] + def get_list(self): + self.list_display.insert(0, 33) + return self.list_display + + +s1 = A() +print(s1.get_list()) +``` + +```python +class A: + list_display = [] + + def get_list(self): + self.list_display.insert(0,33) + return self.list_display + +class B(A): + list_display = [11,22] + + +s1 = A() +s2 = B() +print(s1.get_list()) +print(s2.get_list()) +``` \ No newline at end of file diff --git a/03.网络编程与并发/01.网络编程基础.md b/03.网络编程与并发/01.网络编程基础.md new file mode 100644 index 0000000..a72bd71 --- /dev/null +++ b/03.网络编程与并发/01.网络编程基础.md @@ -0,0 +1,849 @@ +# 网络编程基础 + +## 操作系统基础 + +操作系统:(Operating System,简称OS)是管理和控制计算机硬件与软件资源的计算机程序,是直接运行在“裸机”上的最基本的系统软件,任何其他软件都必须在操作系统的支持下才能运行。 + +![image-20210725220525763](01.%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80/image-20210725220525763.png) + +操作系统应该分成两部分功能 + +1. 隐藏了丑陋的硬件调用接口(键盘、鼠标、音箱等等怎么实现的,就不需要你管了),为应用程序员提供调用硬件资源的更好,更简单,更清晰的模型(系统调用接口)。应用程序员有了这些接口后,就不用再考虑操作硬件的细节,专心开发自己的应用程序即可。 + 例如:操作系统提供了文件这个抽象概念,对文件的操作就是对磁盘的操作,有了文件我们无需再去考虑关于磁盘的读写控制(比如控制磁盘转动,移动磁头读写数据等细节), + +2. 将应用程序对硬件资源的竞态请求变得有序化 + 例如:很多应用软件其实是共享一套计算机硬件,比方说有可能有三个应用程序同时需要申请打印机来输出内容,那么a程序竞争到了打印机资源就打印,然后可能是b竞争到打印机资源,也可能是c,这就导致了无序,打印机可能打印一段a的内容然后又去打印c...,操作系统的一个功能就是将这种无序变得有序。 + +## socket + +回顾一下五层通讯流程 + +![image-20210725220535013](01.%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80/image-20210725220535013.png) + +但实际上从传输层开始以及以下,都是操作系统帮咱们完成的,下面的各种包头封装的过程 + +![image-20210725220541285](01.%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80/image-20210725220541285.png) + +Socket又称为套接字,它是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。当我们使用不同的协议进行通信时就得使用不同的接口,还得处理不同协议的各种细节,这就增加了开发的难度,软件也不易于扩展(就像我们开发一套公司管理系统一样,报账、会议预定、请假等功能不需要单独写系统,而是一个系统上多个功能接口,不需要知道每个功能如何去实现的)。于是UNIX BSD就发明了socket这种东西,socket屏蔽了各个协议的通信细节,使得程序员无需关注协议本身,直接使用socket提供的接口来进行互联的不同主机间的进程的通信。这就好比操作系统给我们提供了使用底层硬件功能的系统调用,通过系统调用我们可以方便的使用磁盘(文件操作),使用内存,而无需自己去进行磁盘读写,内存管理。socket其实也是一样的东西,就是提供了tcp/ip协议的抽象,对外提供了一套接口,同过这个接口就可以统一、方便的使用tcp/ip协议的功能了。 + +其实站在你的角度上看,socket就是一个模块。我们通过调用模块中已经实现的方法建立两个进程之间的连接和通信。也有人将socket说成ip+port,因为ip是用来标识互联网中的一台主机的位置,而port是用来标识这台机器上的一个应用程序。 所以我们只要确立了ip和port就能找到一个应用程序,并且使用socket模块来与之通信。 + +## 套接字家族 + +套接字起源于 20 世纪 70 年代加利福尼亚大学伯克利分校版本的 Unix,即人们所说的 BSD Unix。 因此,有时人们也把套接字称为“伯克利套接字”或“BSD 套接字”。一开始,套接字被设计用在同 一台主机上多个应用程序之间的通讯。这也被称进程间通讯,或 IPC。套接字有两种(或者称为有两个种族),分别是基于文件型的和基于网络型的。 + +### 基于文件类型的套接字家族 + +套接字家族的名字:AF_UNIX + +unix一切皆文件,基于文件的套接字调用的就是底层的文件系统来取数据,两个套接字进程运行在同一机器,可以通过访问同一个文件系统间接完成通信 + +### 基于网络类型的套接字家族 + +套接字家族的名字:AF_INET + +(还有AF_INET6被用于ipv6,还有一些其他的地址家族,不过,他们要么是只用于某个平台,要么就是已经被废弃,或者是很少被使用,或者是根本没有实现,所有地址家族中,AF_INET是使用最广泛的一个,python支持很多种地址家族,但是由于我们只关心网络编程,所以大部分时候我么只使用AF_INET) + +## 套接字的工作流程(基于TCP和 UDP两个协议) + +### TCP和UDP对比 + +- TCP(Transmission Control Protocol) + - 可靠的、面向连接的协议(eg:打电话)、传输效率低全双工通信(发送缓存&接收缓存)、面向字节流。使用TCP的应用:Web浏览器;文件传输程序。 + +- UDP(User Datagram Protocol) + - 不可靠的、无连接的服务,传输效率高(发送前时延小),一对一、一对多、多对一、多对多、面向报文(数据包),尽最大努力服务,无拥塞控制。使用UDP的应用:域名系统 (DNS);视频流;IP语音(VoIP)。 + +### TCP协议下的socket + +![image-20210725220552513](01.%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80/image-20210725220552513.png) + +服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束 + +```python +import socket +socket.socket(socket_family,socket_type,protocal=0) +# socket_family 可以是 AF_UNIX 或 AF_INET。socket_type 可以是 SOCK_STREAM 或 SOCK_DGRAM。protocol 一般不填,默认值为 0。 + +# 获取tcp/ip套接字 +tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + +# 获取udp/ip套接字 +udpSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + +# 由于 socket 模块中有太多的属性。我们在这里破例使用了'from module import *'语句。使用 'from socket import *',我们就把 socket 模块里的所有属性都带到我们的命名空间里了,这样能 大幅减短我们的代码。 +# 例如 +tcpSock = socket(AF_INET, SOCK_STREAM) +``` + +服务端套接字函数 + +| s.bind() | 绑定(主机,端口号)到套接字 | +| ---------- | -------------------------------------------- | +| s.listen() | 开始TCP监听 | +| s.accept() | 被动接受TCP客户的连接,(阻塞式)等待连接的到来 | + +客户端套接字函数 + +| s.connect() | 主动初始化TCP服务器连接 | +| -------------- | ------------------------------------------------------- | +| s.connect_ex() | connect()函数的扩展版本,出错时返回出错码,而不是抛出异常 | + +公共用途的套接字函数 + +| s.recv() | 接收TCP数据 | +| --------------- | ------------------------------------------------------------ | +| s.send() | 发送TCP数据(send在待发送数据量大于己端缓存区剩余空间时,数据丢失,不会发完) | +| s.sendall() | 发送完整的TCP数据(本质就是循环调用send,sendall在待发送数据量大于己端缓存区剩余空间时,数据不丢失,循环调用send直到发完) | +| s.recvfrom() | 接收UDP数据 | +| s.sendto() | 发送UDP数据 | +| s.getpeername() | 连接到当前套接字的远端的地址 | +| s.getsockname() | 当前套接字的地址 | +| s.getsockopt() | 返回指定套接字的参数 | +| s.setsockopt() | 设置指定套接字的参数 | +| s.close() | 关闭套接字 | + +面向锁的套接字方法 + +| s.setblocking() | 设置套接字的阻塞与非阻塞模式 | +| --------------- | ---------------------------- | +| s.settimeout() | 设置阻塞套接字操作的超时时间 | +| s.gettimeout() | 得到阻塞套接字操作的超时时间 | + +面向文件的套接字的函数 + +| s.fileno() | 套接字的文件描述符 | +| ------------ | ---------------------------- | +| s.makefile() | 创建一个与该套接字相关的文件 | + +第一版,单个客户端与服务端通信 + +服务端 + +```python +import socket + +phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 买电话 + +phone.bind(('127.0.0.1',8080)) # 0 ~ 65535 1024之前系统分配好的端口 绑定电话卡 + +phone.listen(5) # 同一时刻有5个请求,但是可以有N多个链接。 开机。 + + +conn, client_addr = phone.accept() # 接电话 +print(conn, client_addr, sep='\n') + +from_client_data = conn.recv(1024) # 一次接收的最大限制 bytes +print(from_client_data.decode('utf-8')) + +conn.send(from_client_data.upper()) + +conn.close() # 挂电话 + +phone.close() # 关机 +``` + +客户端 + +```python +import socket + +phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 买电话 + +phone.connect(('127.0.0.1',8080)) # 与客户端建立连接, 拨号 + +phone.send('hello'.encode('utf-8')) + +from_server_data = phone.recv(1024) + +print(from_server_data) + +phone.close() # 挂电话 +``` + +第二版,通信循环 + +服务端 + +```python +import socket + +phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) +phone.bind(('127.0.0.1',8080)) +phone.listen(5) + +conn,client_addr = phone.accept() +print(conn,client_addr,sep='\n') + +while 1: + try: + from_client_data = conn.recv(1024) + print(from_client_data.decode('utf-8')) + + conn.send(from_client_data.upper()) + except ConnectionResetError: + break + +conn.close() +phone.close() +``` + +客户端 + +```python +import socket + +phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) +phone.connect(('127.0.0.1',8080)) + +while 1: + client_data = input('>>> ') + phone.send(client_data.encode('utf-8')) + + from_server_data = phone.recv(1024) + print(from_server_data.decode('utf-8')) + +phone.close() +``` + +第三版, 通信,连接循环 + +服务端 + +```python +import socket + +phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) +phone.bind(('127.0.0.1',8080)) +phone.listen(5) + +while 1: + conn,client_addr = phone.accept() + print(conn,client_addr,sep='\n') + + while 1: + try: + from_client_data = conn.recv(1024) + print(from_client_data.decode('utf-8')) + + conn.send(from_client_data.upper()) + except: + break + +conn.close() +phone.close() +``` + +客户端 + +```python +import socket + +phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) +phone.connect(('127.0.0.1',8080)) + +while 1: + client_data = input('>>> ') + phone.send(client_data.encode('utf-8')) + if client_data == 'q':break + + from_server_data = phone.recv(1024) + print(from_server_data.decode('utf-8')) + +phone.close() +``` + +远程执行命令的示例: + +```python +import socket +import subprocess + +phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + +phone.bind(('127.0.0.1', 8080)) + +phone.listen(5) + +while 1: # 循环连接客户端 + conn, client_addr = phone.accept() + print(client_addr) + + while 1: + try: + cmd = conn.recv(1024) + ret = subprocess.Popen(cmd.decode('utf-8'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + correct_msg = ret.stdout.read() + error_msg = ret.stderr.read() + conn.send(correct_msg + error_msg) + except ConnectionResetError: + break + +conn.close() +phone.close() +``` + +客户端 + +```python +import socket + +phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 买电话 + +phone.connect(('127.0.0.1', 8080)) # 与客户端建立连接, 拨号 + +while 1: + cmd = input('>>>') + phone.send(cmd.encode('utf-8')) + + from_server_data = phone.recv(1024) + + print(from_server_data.decode('gbk')) + +phone.close() # 挂电话 +``` + +### UDP协议下的socket + +**udp是无链接的,先启动哪一端都不会报错** + +![image-20210725220708133](01.%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80/image-20210725220708133.png) + +服务器端先初始化Socket,然后与端口绑定(bind),recvform接收消息,这个消息有两项,消息内容和对方客户端的地址,然后回复消息时也要带着你收到的这个客户端的地址,发送回去,最后关闭连接,一次交互结束 + +服务端 + +```python +import socket +udp_sk = socket.socket(type=socket.SOCK_DGRAM) #创建一个服务器的套接字 +udp_sk.bind(('127.0.0.1',9000)) #绑定服务器套接字 +msg,addr = udp_sk.recvfrom(1024) +print(msg) +udp_sk.sendto(b'hi',addr) # 对话(接收与发送) +udp_sk.close() # 关闭服务器套接字 +``` + +客户端 + +```python +import socket +ip_port=('127.0.0.1',9000) +udp_sk=socket.socket(type=socket.SOCK_DGRAM) +udp_sk.sendto(b'hello',ip_port) +back_msg,addr=udp_sk.recvfrom(1024) +print(back_msg.decode('utf-8'),addr) +``` + +类似于qq聊天的代码示例 + +服务端 + +```python +import socket +ip_port=('127.0.0.1',8081) +udp_server_sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) #DGRAM:datagram 数据报文的意思,象征着UDP协议的通信方式 +udp_server_sock.bind(ip_port)#你对外提供服务的端口就是这一个,所有的客户端都是通过这个端口和你进行通信的 + +while True: + qq_msg,addr=udp_server_sock.recvfrom(1024)# 阻塞状态,等待接收消息 + print('来自[%s:%s]的一条消息:\033[1;34;43m%s\033[0m' %(addr[0],addr[1],qq_msg.decode('utf-8'))) + back_msg=input('回复消息: ').strip() + + udp_server_sock.sendto(back_msg.encode('utf-8'),addr) +``` + +客户端 + +```python +import socket +BUFSIZE=1024 +udp_client_socket=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) + +qq_name_dic={ + 'taibai':('127.0.0.1',8081), + 'Jedan':('127.0.0.1',8081), + 'Jack':('127.0.0.1',8081), + 'John':('127.0.0.1',8081), +} + + +while True: + while 1: + qq_name=input('请选择聊天对象: ').strip() + if qq_name not in qq_name_dic: + print('没有这个聊天对象') + continue + break + while True: + msg='发给'+ qq_name + ': ' + input('请输入消息,回车发送,输入q结束和他的聊天: ').strip() + if msg == 'q':break + if not msg:continue + udp_client_socket.sendto(msg.encode('utf-8'),qq_name_dic[qq_name])# 必须带着自己的地址,这就是UDP不一样的地方,不需要建立连接,但是要带着自己的地址给服务端,否则服务端无法判断是谁给我发的消息,并且不知道该把消息回复到什么地方,因为我们之间没有建立连接通道 + + back_msg,addr=udp_client_socket.recvfrom(BUFSIZE)# 同样也是阻塞状态,等待接收消息 + print('来自[%s:%s]的一条消息:\033[1;34;43m%s\033[0m' %(addr[0],addr[1],back_msg.decode('utf-8'))) + +udp_client_socket.close() +``` + +自制时间服务器 + +服务端 + +```python +from socket import * +from time import strftime +import time +ip_port = ('127.0.0.1', 9000) +bufsize = 1024 + +tcp_server = socket(AF_INET, SOCK_DGRAM) +tcp_server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) +tcp_server.bind(ip_port) + +while True: + msg, addr = tcp_server.recvfrom(bufsize) + print('===>', msg.decode('utf-8')) + stru_time = time.localtime() #当前的结构化时间 + if not msg: + time_fmt = '%Y-%m-%d %X' + else: + time_fmt = msg.decode('utf-8') + back_msg = strftime(time_fmt,stru_time) + print(back_msg,type(back_msg)) + tcp_server.sendto(back_msg.encode('utf-8'), addr) + +tcp_server.close() +``` + +客户端 + +```python +from socket import * +ip_port=('127.0.0.1',9000) +bufsize=1024 + +tcp_client=socket(AF_INET,SOCK_DGRAM) + +while True: + msg=input('请输入时间格式(例%Y %m %d)>>: ').strip() + tcp_client.sendto(msg.encode('utf-8'),ip_port) + + data=tcp_client.recv(bufsize) + print('当前日期:',str(data,encoding='utf-8')) +``` + +## 粘包 + + ![image-20210725220726010](01.%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80/image-20210725220726010.png) + +每个 socket 被创建后,都会分配两个缓冲区,输入缓冲区和输出缓冲区。 + +write()/send() 并不立即向网络中传输数据,而是先将数据写入缓冲区中,再由TCP协议将数据从缓冲区发送到目标机器。一旦将数据写入到缓冲区,函数就可以成功返回,不管它们有没有到达目标机器,也不管它们何时被发送到网络,这些都是TCP协议负责的事情。 + +TCP协议独立于 write()/send() 函数,数据有可能刚被写入缓冲区就发送到网络,也可能在缓冲区中不断积压,多次写入的数据被一次性发送到网络,这取决于当时的网络情况、当前线程是否空闲等诸多因素,不由程序员控制。 + +read()/recv() 函数也是如此,也从输入缓冲区中读取数据,而不是直接从网络中读取。 + +这些I/O缓冲区特性可整理如下: + +1. I/O缓冲区在每个TCP套接字中单独存在; +2. I/O缓冲区在创建套接字时自动生成; +3. 即使关闭套接字也会继续传送输出缓冲区中遗留的数据; +4. 关闭套接字将丢失输入缓冲区中的数据。 + +## 两种情况下会发生粘包 + +1. 接收方没有及时接收缓冲区的包,造成多个包接收(客户端发送了一段数据,服务端只收了一小部分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包) + +服务端 + +```python +import socket +import subprocess + +phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + +phone.bind(('127.0.0.1', 8080)) + +phone.listen(5) + +while 1: # 循环连接客户端 + conn, client_addr = phone.accept() + print(client_addr) + + while 1: + try: + cmd = conn.recv(1024) + ret = subprocess.Popen(cmd.decode('utf-8'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + correct_msg = ret.stdout.read() + error_msg = ret.stderr.read() + conn.send(correct_msg + error_msg) + except ConnectionResetError: + break + +conn.close() +phone.close() +``` + +客户端 + +```python +import socket + +phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 买电话 + +phone.connect(('127.0.0.1',8080)) # 与客户端建立连接, 拨号 + + +while 1: + cmd = input('>>>') + phone.send(cmd.encode('utf-8')) + + from_server_data = phone.recv(1024) + + print(from_server_data.decode('gbk')) + +phone.close() +``` + +2. 发送端需要等缓冲区满才发送出去,造成粘包(发送数据时间间隔很短,数据也很小,会合到一起,产生粘包) + +服务端 + +```python +import socket + + +phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + +phone.bind(('127.0.0.1', 8080)) + +phone.listen(5) + +conn, client_addr = phone.accept() + +frist_data = conn.recv(1024) +print('1:',frist_data.decode('utf-8')) # 1: helloworld +second_data = conn.recv(1024) +print('2:',second_data.decode('utf-8')) + + +conn.close() +phone.close() +``` + +客户端 + +```python +import socket + +phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + +phone.connect(('127.0.0.1', 8080)) + +phone.send(b'hello') +phone.send(b'world') + +phone.close() +``` + +## 粘包的解决方案 + +### struct模块 + +该模块可以把一个类型,如数字,转成固定长度的bytes + +![image-20210725220750620](01.%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80/image-20210725220750620.png) + +```python +import struct +# 将一个数字转化成等长度的bytes类型。 +ret = struct.pack('i', 183346) +print(ret, type(ret), len(ret)) + +# 通过unpack反解回来 +ret1 = struct.unpack('i',ret)[0] +print(ret1, type(ret1), len(ret1)) + +# 但是通过struct 处理不能处理太大 +``` + +方案一: + +```python +import socket +import subprocess +import struct + +phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + +phone.bind(('127.0.0.1', 8080)) + +phone.listen(5) + +while 1: + conn, client_addr = phone.accept() + print(client_addr) + + while 1: + try: + cmd = conn.recv(1024) + ret = subprocess.Popen(cmd.decode('utf-8'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + correct_msg = ret.stdout.read() + error_msg = ret.stderr.read() + + # 1 制作固定报头 + total_size = len(correct_msg) + len(error_msg) + header = struct.pack('i', total_size) + + # 2 发送报头 + conn.send(header) + + # 发送真实数据: + conn.send(correct_msg) + conn.send(error_msg) + except ConnectionResetError: + break + +conn.close() +phone.close() + +## 但是low版本有问题: +## 1,报头不只有总数据大小,而是还应该有MD5数据,文件名等等一些数据。 +## 2,通过struct模块直接数据处理,不能处理太大。 +``` + +客户端 + +```python +import socket +import struct + +phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + +phone.connect(('127.0.0.1', 8080)) + +while 1: + cmd = input('>>>').strip() + if not cmd: continue + phone.send(cmd.encode('utf-8')) + + # 1,接收固定报头 + header = phone.recv(4) + + # 2,解析报头 + total_size = struct.unpack('i', header)[0] + + # 3,根据报头信息,接收真实数据 + recv_size = 0 + res = b'' + + while recv_size < total_size: + recv_data = phone.recv(1024) + res += recv_data + recv_size += len(recv_data) + + print(res.decode('gbk')) + +phone.close() +``` + +方案二:可自定制报头 + + 整个流程的大致解释: + 我们可以把报头做成字典,字典里包含将要发送的真实数据的描述信息(大小啊之类的),然后json序列化,然后用struck将序列化后的数据长度打包成4个字节。 + 我们在网络上传输的所有数据 都叫做数据包,数据包里的所有数据都叫做报文,报文里面不止有你的数据,还有ip地址、mac地址、端口号等等,其实所有的报文都有报头,这个报头是协议规定的,看一下 + + 发送时: + 先发报头长度 + 再编码报头内容然后发送 + 最后发真实内容 + + 接收时: + 先手报头长度,用struct取出来 + 根据取出的长度收取报头内容,然后解码,反序列化 + 从反序列化的结果中取出待取数据的描述信息,然后去取真实的数据内容 + +服务端 + +```python +import socket +import subprocess +import struct +import json + +phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + +phone.bind(('127.0.0.1', 8080)) + +phone.listen(5) + +while 1: + conn, client_addr = phone.accept() + print(client_addr) + + while 1: + try: + cmd = conn.recv(1024) + ret = subprocess.Popen(cmd.decode('utf-8'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + correct_msg = ret.stdout.read() + error_msg = ret.stderr.read() + + # 1 制作固定报头 + total_size = len(correct_msg) + len(error_msg) + + header_dict = { + 'md5': 'fdsaf2143254f', + 'file_name': 'f1.txt', + 'total_size': total_size, + } + + header_dict_json = json.dumps(header_dict) # str + bytes_headers = header_dict_json.encode('utf-8') + + header_size = len(bytes_headers) + + header = struct.pack('i', header_size) + + # 2 发送报头长度 + conn.send(header) + + # 3 发送报头 + conn.send(bytes_headers) + + # 4 发送真实数据: + conn.send(correct_msg) + conn.send(error_msg) + except ConnectionResetError: + break + +conn.close() +phone.close() +``` + +客户端 + +```python +import socket +import struct +import json + +phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + +phone.connect(('127.0.0.1', 8080)) + +while 1: + cmd = input('>>>').strip() + if not cmd: continue + phone.send(cmd.encode('utf-8')) + + # 1,接收固定报头 + header_size = struct.unpack('i', phone.recv(4))[0] + + # 2,解析报头长度 + header_bytes = phone.recv(header_size) + + header_dict = json.loads(header_bytes.decode('utf-8')) + + # 3,收取报头 + total_size = header_dict['total_size'] + + # 3,根据报头信息,接收真实数据 + recv_size = 0 + res = b'' + + while recv_size < total_size: + recv_data = phone.recv(1024) + res += recv_data + recv_size += len(recv_data) + + print(res.decode('gbk')) + +phone.close() +``` + +FTP上传下载文件的代码(简单版) + +服务端 + +```python +import socket +import struct +import json +sk = socket.socket() +## buffer = 4096 # 当双方的这个接收发送的大小比较大的时候,就像这个4096,就会丢数据,这个等我查一下再告诉大家,改小了就ok的,在linux上也是ok的。 +buffer = 1024 #每次接收数据的大小 +sk.bind(('127.0.0.1',8090)) +sk.listen() + +conn,addr = sk.accept() +#接收 +head_len = conn.recv(4) +head_len = struct.unpack('i',head_len)[0] #解包 +json_head = conn.recv(head_len).decode('utf-8') #反序列化 +head = json.loads(json_head) +filesize = head['filesize'] +with open(head['filename'],'wb') as f: + while filesize: + if filesize >= buffer: #>=是因为如果刚好等于的情况出现也是可以的。 + content = conn.recv(buffer) + f.write(content) + filesize -= buffer + else: + content = conn.recv(buffer) + f.write(content) + break + +conn.close() +sk.close() +``` + +客户端 + +```python +import os +import json +import socket +import struct +sk = socket.socket() +sk.connect(('127.0.0.1',8090)) +buffer = 1024 #读取文件的时候,每次读取的大小 +head = { + 'filepath':r'C:\Users\Aaron\Desktop\新建文件夹', #需要下载的文件路径,也就是文件所在的文件夹 + 'filename':'config', #改成上面filepath下的一个文件 + 'filesize':None, + } + +file_path = os.path.join(head['filepath'],head['filename']) +filesize = os.path.getsize(file_path) +head['filesize'] = filesize +# json_head = json.dumps(head,ensure_ascii=False) #字典转换成字符串 +json_head = json.dumps(head) #字典转换成字符串 +bytes_head = json_head.encode('utf-8') #字符串转换成bytes类型 +print(json_head) +print(bytes_head) + +#计算head的长度,因为接收端先接收我们自己定制的报头,对吧 +head_len = len(bytes_head) #报头长度 +pack_len = struct.pack('i',head_len) +print(head_len) +print(pack_len) +sk.send(pack_len) #先发送报头长度 +sk.send(bytes_head) #再发送bytes类型的报头 + +#即便是视频文件,也是可以按行来读取的,也可以readline,也可以for循环,但是读取出来的数据大小就不固定了,影响效率,有可能读的比较小,也可能很大,像视频文件一般都是一行的二进制字节流。 +#所有我们可以用read,设定一个一次读取内容的大小,一边读一边发,一边收一边写 +with open(file_path,'rb') as f: + while filesize: + if filesize >= buffer: #>=是因为如果刚好等于的情况出现也是可以的。 + content = f.read(buffer) #每次读取出来的内容 + sk.send(content) + filesize -= buffer #每次减去读取的大小 + else: #那么说明剩余的不够一次读取的大小了,那么只要把剩下的读取出来发送过去就行了 + content = f.read(filesize) + sk.send(content) + break + +sk.close() +``` \ No newline at end of file diff --git a/03.网络编程与并发/01.网络编程基础/image-20210725220525763.png b/03.网络编程与并发/01.网络编程基础/image-20210725220525763.png new file mode 100644 index 0000000..7496561 Binary files /dev/null and b/03.网络编程与并发/01.网络编程基础/image-20210725220525763.png differ diff --git a/03.网络编程与并发/01.网络编程基础/image-20210725220535013.png b/03.网络编程与并发/01.网络编程基础/image-20210725220535013.png new file mode 100644 index 0000000..efb21c1 Binary files /dev/null and b/03.网络编程与并发/01.网络编程基础/image-20210725220535013.png differ diff --git a/03.网络编程与并发/01.网络编程基础/image-20210725220541285.png b/03.网络编程与并发/01.网络编程基础/image-20210725220541285.png new file mode 100644 index 0000000..d8d3d9c Binary files /dev/null and b/03.网络编程与并发/01.网络编程基础/image-20210725220541285.png differ diff --git a/03.网络编程与并发/01.网络编程基础/image-20210725220552513.png b/03.网络编程与并发/01.网络编程基础/image-20210725220552513.png new file mode 100644 index 0000000..fc6c3c2 Binary files /dev/null and b/03.网络编程与并发/01.网络编程基础/image-20210725220552513.png differ diff --git a/03.网络编程与并发/01.网络编程基础/image-20210725220612103.png b/03.网络编程与并发/01.网络编程基础/image-20210725220612103.png new file mode 100644 index 0000000..71ad8f5 Binary files /dev/null and b/03.网络编程与并发/01.网络编程基础/image-20210725220612103.png differ diff --git a/03.网络编程与并发/01.网络编程基础/image-20210725220622753.png b/03.网络编程与并发/01.网络编程基础/image-20210725220622753.png new file mode 100644 index 0000000..4de7d37 Binary files /dev/null and b/03.网络编程与并发/01.网络编程基础/image-20210725220622753.png differ diff --git a/03.网络编程与并发/01.网络编程基础/image-20210725220635963.png b/03.网络编程与并发/01.网络编程基础/image-20210725220635963.png new file mode 100644 index 0000000..e0356b0 Binary files /dev/null and b/03.网络编程与并发/01.网络编程基础/image-20210725220635963.png differ diff --git a/03.网络编程与并发/01.网络编程基础/image-20210725220641602.png b/03.网络编程与并发/01.网络编程基础/image-20210725220641602.png new file mode 100644 index 0000000..e0356b0 Binary files /dev/null and b/03.网络编程与并发/01.网络编程基础/image-20210725220641602.png differ diff --git a/03.网络编程与并发/01.网络编程基础/image-20210725220708133.png b/03.网络编程与并发/01.网络编程基础/image-20210725220708133.png new file mode 100644 index 0000000..71ad8f5 Binary files /dev/null and b/03.网络编程与并发/01.网络编程基础/image-20210725220708133.png differ diff --git a/03.网络编程与并发/01.网络编程基础/image-20210725220726010.png b/03.网络编程与并发/01.网络编程基础/image-20210725220726010.png new file mode 100644 index 0000000..4de7d37 Binary files /dev/null and b/03.网络编程与并发/01.网络编程基础/image-20210725220726010.png differ diff --git a/03.网络编程与并发/01.网络编程基础/image-20210725220750620.png b/03.网络编程与并发/01.网络编程基础/image-20210725220750620.png new file mode 100644 index 0000000..e0356b0 Binary files /dev/null and b/03.网络编程与并发/01.网络编程基础/image-20210725220750620.png differ diff --git a/03.网络编程与并发/02.操作系统发展史.md b/03.网络编程与并发/02.操作系统发展史.md new file mode 100644 index 0000000..7b1bd0f --- /dev/null +++ b/03.网络编程与并发/02.操作系统发展史.md @@ -0,0 +1,174 @@ +# 操作系统发展史 + +## 手工操作 —— 穿孔卡片 + +1946年第一台计算机诞生--20世纪50年代中期,计算机工作还在采用手工操作方式。此时还没有操作系统的概念。 + +![image-20210725220908985](02.%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%8F%91%E5%B1%95%E5%8F%B2/image-20210725220908985.png) + +![image-20210725220917981](02.%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%8F%91%E5%B1%95%E5%8F%B2/image-20210725220917981.png) + +程序员将对应于程序和数据的已穿孔的纸带(或卡片)装入输入机,然后启动输入机把程序和数据输入计算机内存,接着通过控制台开关启动程序针对数据运行;计算完毕,打印机输出计算结果;用户取走结果并卸下纸带(或卡片)后,才让下一个用户上机。 + +手工操作方式两个特点: + +1. 用户独占全机。不会出现因资源已被其他用户占用而等待的现象,但资源的利用率低。 +2. CPU 等待手工操作。CPU的利用不充分。 + +20世纪50年代后期,出现人机矛盾:手工操作的慢速度和计算机的高速度之间形成了尖锐矛盾,手工操作方式已严重损害了系统资源的利用率(使资源利用率降为百分之几,甚至更低),不能容忍。唯一的解决办法:只有摆脱人的手工操作,实现作业的自动过渡。这样就出现了成批处理。 + +## 批处理 —— 磁带存储 + +批处理系统:加载在计算机上的一个系统软件,在它的控制下,计算机能够自动地、成批地处理一个或多个用户的作业(这作业包括程序、数据和命令)。 + +### 联机批处理系统 + +首先出现的是联机批处理系统,即作业的输入/输出由CPU来处理。 + +![image-20210725220928953](02.%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%8F%91%E5%B1%95%E5%8F%B2/image-20210725220928953.png) + +主机与输入机之间增加一个存储设备——磁带,在运行于主机上的监督程序的自动控制下,计算机可自动完成:成批地把输入机上的用户作业读入磁带,依次把磁带上的用户作业读入主机内存并执行并把计算结果向输出机输出。完成了上一批作业后,监督程序又从输入机上输入另一批作业,保存在磁带上,并按上述步骤重复处理。 +监督程序不停地处理各个作业,从而实现了作业到作业的自动转接,减少了作业建立时间和手工操作时间,有效克服了人机矛盾,提高了计算机的利用率。 +但是,在作业输入和结果输出时,主机的高速CPU仍处于空闲状态,等待慢速的输入/输出设备完成工作: 主机处于“忙等”状态。 + +### 脱机批处理系统 + +为克服与缓解:高速主机与慢速外设的矛盾,提高CPU的利用率,又引入了脱机批处理系统,即输入/输出脱离主机控制。 + +![image-20210725220936340](02.%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%8F%91%E5%B1%95%E5%8F%B2/image-20210725220936340.png) + +卫星机:一台不与主机直接相连而专门用于与输入/输出设备打交道的。 + +1. 从输入机上读取用户作业并放到输入磁带上。 +2. 从输出磁带上读取执行结果并传给输出机 + +不足:每次主机内存中仅存放一道作业,每当它运行期间发出输入/输出(I/O)请求后,高速的CPU便处于等待低速的I/O完成状态,致使CPU空闲。 + +## 多道程序系统 + +### 多道程序设计技术 + +所谓多道程序设计技术,就是指允许多个程序同时进入内存并运行。即同时把多个程序放入内存,并允许它们交替在CPU中运行,它们共享系统中的各种硬、软件资源。当一道程序因I/O请求而暂停运行时,CPU便立即转去运行另一道程序。 + +![image-20210725220944897](02.%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%8F%91%E5%B1%95%E5%8F%B2/image-20210725220944897.png) + +在A程序计算时,I/O空闲, A程序I/O操作时,CPU空闲(B程序也是同样);必须A工作完成后,B才能进入内存中开始工作,两者是串行的,全部完成共需时间=T1+T2。 + +![image-20210725220951109](02.%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%8F%91%E5%B1%95%E5%8F%B2/image-20210725220951109.png) + +将A、B两道程序同时存放在内存中,它们在系统的控制下,可相互穿插、交替地在CPU上运行:当A程序因请求I/O操作而放弃CPU时,B程序就可占用CPU运行,这样 CPU不再空闲,而正进行A I/O操作的I/O设备也不空闲,显然,CPU和I/O设备都处于“忙”状态,大大提高了资源的利用率,从而也提高了系统的效率,A、B全部完成所需时间<注意:在Windows操作系统中由于没有fork(linux操作系统中创建进程的机制),在创建子进程的时候会自动 import 启动它的这个文件,而在 import 的时候又执行了整个文件。因此如果将process()直接写在文件中就会无限递归创建子进程报错。所以必须把创建子进程的部分使用`if __name__ =='__main__'` 判断保护起来,import 的时候 ,就不会递归运行了。 + +### 使用process模块创建进程 + +在一个python进程中开启子进程,start方法和并发效果。 + +```python +import time +from multiprocessing import Process + +def f(name): + print('hello',name) + print('子进程') + +if __name__ == '__main__': + p = Process(target=f,args=('aaron',)) + p.start() + time.sleep(1) + print('主程序') +``` + +使用join方法 + +```python +import time +from multiprocessing import Process + +def f(name): + print('hello',name) + time.sleep(1) + print('子进程') + +if __name__ == '__main__': + p = Process(target=f,args=('aaron',)) + p.start() + p.join() + print('主程序') +``` + +查看进程号 + +```python +import os +from multiprocessing import Process + +def f(x): + print('子进程id:',os.getpid(),'父进程id:',os.getppid()) + return x*x + +if __name__ == '__main__': + print('主进程id: ',os.getpid()) + p_lst = [] + for i in range(5): + p = Process(target=f,args=(i,)) + p.start() +``` + +进阶,多个进程同时运行(注意,子进程的执行顺序不是根据启动顺序决定的) + +```python +import time +from multiprocessing import Process + +def f(name): + print('hello',name) + time.sleep(1) + +if __name__ == '__main__': + p_lst = [] + for i in range(5): + p = Process(target=f, args=('aaron',)) + p.start() + p_lst.append(p) +``` + +多进程同时运行使用join方法 + +```python +import time +from multiprocessing import Process + +def f(name): + print('hello',name) + time.sleep(1) + +if __name__ == '__main__': + p_lst = [] + for i in range(5): + p = Process(target=f, args=('aaron',)) + p.start() + p_lst.append(p) + p.join() + print('主进程') +``` + +```python +import time +from multiprocessing import Process + +def f(name): + print('hello',name) + time.sleep(1) + +if __name__ == '__main__': + p_lst = [] + for i in range(5): + p = Process(target=f, args=('aaron',)) + p.start() + p_lst.append(p) + [p.join() for p in p_lst] + print('主进程') +``` + +以继承Process类的形式开启进程的方式 + +```python +import os +from multiprocessing import Process + + +class MyProcess(Process): + def __init__(self,name): + super().__init__() + self.name=name + + def run(self): + print(os.getpid()) + print('%s 正在和女主播聊天' %self.name) + +if __name__ == '__main__': + p1 = MyProcess('陈松') + p2 = MyProcess('松哥') + p3 = MyProcess('松松') + + p1.start() + p2.start() + p3.start() + + p1.join() + p2.join() + p3.join() + + print('主进程') +``` + +进程之间的数据隔离问题 + +```python +from multiprocessing import Process + +def work(): + global n + n = 0 + print('子进程',n) + +if __name__ == '__main__': + n = 100 + p = Process(target=work) + p.start() + print('主进程',n) +``` + +### 守护进程 + +会随着主进程的结束而结束。 + +主进程创建守护进程 + +1. 守护进程会在主进程代码执行结束后就终止 +2. 守护进程内无法再开启子进程,否则抛出异常 + +注意:进程之间是互相独立的,主进程代码运行结束,守护进程随即终止 + +```python +import os +import time +from multiprocessing import Process + +class Myprocess(Process): + def __init__(self,person): + super().__init__() + self.person = person + def run(self): + print(os.getpid(),self.name) + print('%s正在和女主播聊天' %self.person) + +if __name__ == '__main__': + p=Myprocess('陈松') + p.daemon=True #一定要在p.start()前设置,设置p为守护进程,禁止p创建子进程,并且父进程代码执行结束,p即终止运行 + p.start() + time.sleep(10) # 在sleep时查看进程id对应的进程 + print('主') +``` + +```python +from multiprocessing import Process +import time + +def foo(): + print(123) + time.sleep(1) + print("end123") + +def bar(): + print(456) + time.sleep(3) + print("end456") + +if __name__ == '__main__': + p1=Process(target=foo) + p2=Process(target=bar) + + p1.daemon=True + p1.start() + p2.start() + time.sleep(0.1) + print("main-------") +# 打印该行则主进程代码结束,则守护进程p1应该被终止.#可能会有p1任务执行的打印信息123,因为主进程打印main----时,p1也执行了,但是随即被终止. +``` + +socket聊天并发实例 + +服务端 + +```python +from socket import * +from multiprocessing import Process + +server=socket(AF_INET,SOCK_STREAM) +server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) +server.bind(('127.0.0.1',8080)) +server.listen(5) + +def talk(conn,client_addr): + while True: + try: + msg=conn.recv(1024) + if not msg:break + conn.send(msg.upper()) + except Exception: + break + +if __name__ == '__main__': #windows下start进程一定要写到这下面 + while True: + conn,client_addr=server.accept() + print(client_addr) + p=Process(target=talk,args=(conn,client_addr)) + p.start() +``` + +```python +from socket import * + +client=socket(AF_INET,SOCK_STREAM) +client.connect(('127.0.0.1',8080)) + + +while True: + msg=input('>>: ').strip() + if not msg:continue + + client.send(msg.encode('utf-8')) + msg=client.recv(1024) + print(msg.decode('utf-8')) +``` + +### 多进程中的其他方法 + +```python +from multiprocessing import Process +import time +import random + +class Myprocess(Process): + def __init__(self,person): + self.name=person + super().__init__() + + def run(self): + print('%s正在和陈松聊天' %self.name) + time.sleep(random.randrange(1,5)) + print('%s还在和陈松聊天' %self.name) + +if __name__ == '__main__': + p1=Myprocess('陈松') + p1.start() + + p1.terminate() # 关闭进程,不会立即关闭,所以is_alive立刻查看的结果可能还是存活 + print(p1.is_alive()) # 结果为True + + print('开始') + print(p1.is_alive()) # 结果为False +``` + +```python +from multiprocessing import Process +import time +import random + +class Myprocess(Process): + def __init__(self,person): + self.name=person # name属性是Process中的属性,标示进程的名字 + super().__init__() # 执行父类的初始化方法会覆盖name属性 + #self.name = person # 在这里设置就可以修改进程名字了 + #self.person = person #如果不想覆盖进程名,就修改属性名称就可以了 + def run(self): + print('%s正在和女主播聊天' %self.name) + # print('%s正在和网红脸聊天' %self.person) + time.sleep(random.randrange(1,5)) + print('%s正在和女主播聊天' %self.name) + # print('%s正在和网红脸聊天' %self.person) + +if __name__ == '__main__': + p1=Myprocess('陈松') + p1.start() + print(p1.pid) #可以查看子进程的进程id +``` + +## 进程同步(multiprocess.Lock) + +### 锁 —— multiprocess.Lock + +当多个进程使用同一份数据资源的时候,就会引发数据安全或顺序混乱问题。 + +```python +import os +import time +import random +from multiprocessing import Process + +def work(n): + print('%s: %s is running' %(n,os.getpid())) + time.sleep(random.random()) + print('%s:%s is done' %(n,os.getpid())) + +if __name__ == '__main__': + for i in range(3): + p=Process(target=work,args=(i,)) + p.start() +``` + +```python +import os +import time +import random +from multiprocessing import Process,Lock + +def work(lock,n): + lock.acquire() + print('%s: %s is running' % (n, os.getpid())) + time.sleep(random.random()) + print('%s: %s is done' % (n, os.getpid())) + lock.release() +if __name__ == '__main__': + lock=Lock() + for i in range(3): + p=Process(target=work,args=(lock,i)) + p.start() +``` + +上面这种情况虽然使用加锁的形式实现了顺序的执行,但是程序又重新变成串行了,这样确实会浪费了时间,却保证了数据的安全。 + +写一个抢票程序 + +```python +#文件db的内容为:{"count":1} +#注意一定要用双引号,不然json无法识别 +#并发运行,效率高,但竞争写同一文件,数据写入错乱 +from multiprocessing import Process,Lock +import time,json,random +def search(): + dic=json.load(open('db')) + print('\033[43m剩余票数%s\033[0m' %dic['count']) + +def get(): + dic=json.load(open('db')) + time.sleep(0.1) #模拟读数据的网络延迟 + if dic['count'] >0: + dic['count']-=1 + time.sleep(0.2) #模拟写数据的网络延迟 + json.dump(dic,open('db','w')) + print('\033[43m购票成功\033[0m') + +def task(): + search() + get() + +if __name__ == '__main__': + for i in range(100): #模拟并发100个客户端抢票 + p=Process(target=task) + p.start() +``` + +用说来保护票 + +```python +#文件db的内容为:{"count":1} +#注意一定要用双引号,不然json无法识别 +#并发运行,效率高,但竞争写同一文件,数据写入错乱 +from multiprocessing import Process,Lock +import time,json,random +def search(): + dic=json.load(open('db')) + print('\033[43m剩余票数%s\033[0m' %dic['count']) + +def get(): + dic=json.load(open('db')) + time.sleep(0.1) #模拟读数据的网络延迟 + if dic['count'] >0: + dic['count']-=1 + time.sleep(0.2) #模拟写数据的网络延迟 + json.dump(dic,open('db','w')) + print('\033[43m购票成功\033[0m') + else: + print('\033[31m购票失败\033[0m') + +def task(lock): + search() + lock.acquire() + get() + lock.release() + +if __name__ == '__main__': + lock = Lock() + for i in range(50): #模拟并发50个客户端抢票 + p=Process(target=task,args=(lock,)) + p.start() +``` + +虽然可以用文件共享数据实现进程间通信,但问题是: + +1. 效率低(共享数据基于文件,而文件是硬盘上的数据) +2. 需要自己加锁处理 + +队列和管道都是将数据存放于内存中 +队列又是基于(管道+锁)实现的,可以让我们从复杂的锁问题中解脱出来, +我们应该尽量避免使用共享数据,尽可能使用消息传递和队列,避免处理复杂的同步和锁问题,而且在进程数目增多时,往往可以获得更好的可获展性。 + +## 进程间通信——队列(multiprocess.Queue) + +### 进程间通信 + +IPC(Inter-Process Communication) + +### 队列 + +#### 概念介绍 + +创建共享的进程队列,Queue是多进程安全的队列,可以使用Queue实现多进程之间的数据传递。 + + Queue([maxsize]) + 创建共享的进程队列。 + 参数 :maxsize是队列中允许的最大项数。如果省略此参数,则无大小限制。 + 底层队列使用管道和锁定实现。 + +队列方法介绍 + +- Queue([maxsize]) + - 创建共享的进程队列。maxsize是队列中允许的最大项数。如果省略此参数,则无大小限制。底层队列使用管道和锁定实现。另外,还需要运行支持线程以便队列中的数据传输到底层管道中。 +- Queue的实例q具有以下方法: + + - q.get( [ block [ ,timeout ] ] ) + 返回q中的一个项目。如果q为空,此方法将阻塞,直到队列中有项目可用为止。block用于控制阻塞行为,默认为True. 如果设置为False,将引发Queue.Empty异常(定义在Queue模块中)。timeout是可选超时时间,用在阻塞模式中。如果在制定的时间间隔内没有项目变为可用,将引发Queue.Empty异常。 + + - q.get_nowait( ) + 同q.get(False)方法。 + + - q.put(item [, block [,timeout ] ] ) + 将item放入队列。如果队列已满,此方法将阻塞至有空间可用为止。block控制阻塞行为,默认为True。如果设置为False,将引发Queue.Empty异常(定义在Queue库模块中)。timeout指定在阻塞模式中等待可用空间的时间长短。超时后将引发Queue.Full异常。 + + - q.qsize() + 返回队列中目前项目的正确数量。此函数的结果并不可靠,因为在返回结果和在稍后程序中使用结果之间,队列中可能添加或删除了项目。在某些系统上,此方法可能引发NotImplementedError异常。 + + - q.empty() + 如果调用此方法时 q为空,返回True。如果其他进程或线程正在往队列中添加项目,结果是不可靠的。也就是说,在返回和使用结果之间,队列中可能已经加入新的项目。 + + - q.full() + 如果q已满,返回为True. 由于线程的存在,结果也可能是不可靠的(参考q.empty()方法)。。 + +其他方法 + +- q.close() + 关闭队列,防止队列中加入更多数据。调用此方法时,后台线程将继续写入那些已入队列但尚未写入的数据,但将在此方法完成时马上关闭。如果q被垃圾收集,将自动调用此方法。关闭队列不会在队列使用者中生成任何类型的数据结束信号或异常。例如,如果某个使用者正被阻塞在get()操作上,关闭生产者中的队列不会导致get()方法返回错误。 + +- q.cancel_join_thread() + 不会再进程退出时自动连接后台线程。这可以防止join_thread()方法阻塞。 + +- q.join_thread() + 连接队列的后台线程。此方法用于在调用q.close()方法后,等待所有队列项被消耗。默认情况下,此方法由不是q的原始创建者的所有进程调用。调用q.cancel_join_thread()方法可以禁止这种行为。 + +#### 代码实例 + +```python +from multiprocessing import Queue +q=Queue(3) + +#put ,get ,put_nowait,get_nowait,full,empty +q.put(3) +q.put(3) +q.put(3) +# q.put(3) # 如果队列已经满了,程序就会停在这里,等待数据被别人取走,再将数据放入队列。 + # 如果队列中的数据一直不被取走,程序就会永远停在这里。 +try: + q.put_nowait(3) # 可以使用put_nowait,如果队列满了不会阻塞,但是会因为队列满了而报错。 +except: # 因此我们可以用一个try语句来处理这个错误。这样程序不会一直阻塞下去,但是会丢掉这个消息。 + print('队列已经满了') + +# 因此,我们再放入数据之前,可以先看一下队列的状态,如果已经满了,就不继续put了。 +print(q.full()) #满了 + +print(q.get()) +print(q.get()) +print(q.get()) +# print(q.get()) # 同put方法一样,如果队列已经空了,那么继续取就会出现阻塞。 +try: + q.get_nowait(3) # 可以使用get_nowait,如果队列满了不会阻塞,但是会因为没取到值而报错。 +except: # 因此我们可以用一个try语句来处理这个错误。这样程序不会一直阻塞下去。 + print('队列已经空了') + +print(q.empty()) #空了 +``` + +```python +import time +from multiprocessing import Process, Queue + +def f(q): + q.put([time.asctime(), 'from earth', 'hello']) #调用主函数中p进程传递过来的进程参数 put函数为向队列中添加一条数据。 + +if __name__ == '__main__': + q = Queue() #创建一个Queue对象 + p = Process(target=f, args=(q,)) #创建一个进程 + p.start() + print(q.get()) + p.join() +``` + +```python +import os +import time +import multiprocessing + +# 向queue中输入数据的函数 +def inputQ(queue): + info = str(os.getpid()) + '(put):' + str(time.asctime()) + queue.put(info) + +# 向queue中输出数据的函数 +def outputQ(queue): + info = queue.get() + print ('%s%s\033[32m%s\033[0m'%(str(os.getpid()), '(get):',info)) + +# Main +if __name__ == '__main__': + multiprocessing.freeze_support() + # 解决在Windows下运行有可能崩溃 + record1 = [] # store input processes + record2 = [] # store output processes + queue = multiprocessing.Queue(3) + + # 输入进程 + for i in range(5): + process = multiprocessing.Process(target=inputQ,args=(queue,)) + time.sleep(1) + process.start() + record1.append(process) + + # 输出进程 + for i in range(5): + process = multiprocessing.Process(target=outputQ,args=(queue,)) + process.start() + record2.append(process) + + for p in record1: + p.join() + + for p in record2: + p.join() +``` + +#### 生产者消费者模型 + +在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题。该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度。 + +**为什么要使用生产者和消费者模式** +在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程。在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个问题于是引入了生产者和消费者模式。 + +**什么是生产者消费者模式** +生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。 + +```python +from multiprocessing import Process,Queue +import time,random,os +def consumer(q): + while True: + res=q.get() + time.sleep(random.randint(1,3)) + print('%s 吃 %s' %(os.getpid(),res)) + +def producer(q): + for i in range(10): + time.sleep(random.randint(1,3)) + res='包子%s' %i + q.put(res) + print('%s 生产了 %s' %(os.getpid(),res)) + +if __name__ == '__main__': + q=Queue() + #生产者们:即厨师们 + p1=Process(target=producer,args=(q,)) + + #消费者们:即吃货们 + c1=Process(target=consumer,args=(q,)) + + #开始 + p1.start() + c1.start() + print('主') +``` + +消费者c在取空了q之后,则一直处于死循环中且卡在q.get()这一步。 + +生产者在生产完毕后,往队列中再发一个结束信号,这样消费者在接收到结束信号后就可以break出死循环。 + +```python +from multiprocessing import Process,Queue +import time,random,os +def consumer(q): + while True: + res=q.get() + if res is None:break #收到结束信号则结束 + time.sleep(random.randint(1,3)) + print('%s 吃 %s' %(os.getpid(),res)) + +def producer(q): + for i in range(10): + time.sleep(random.randint(1,3)) + res='包子%s' %i + q.put(res) + print('%s 生产了 %s' %(os.getpid(),res)) + q.put(None) #发送结束信号 +if __name__ == '__main__': + q=Queue() + #生产者们:即厨师们 + p1=Process(target=producer,args=(q,)) + + #消费者们:即吃货们 + c1=Process(target=consumer,args=(q,)) + + #开始 + p1.start() + c1.start() + print('主') +``` + +结束信号None,不一定要由生产者发,主进程里同样可以发,但主进程需要等生产者结束后才应该发送该信号 + +```python +from multiprocessing import Process,Queue +import time,random,os +def consumer(q): + while True: + res=q.get() + if res is None:break #收到结束信号则结束 + time.sleep(random.randint(1,3)) + print('%s 吃 %s' %(os.getpid(),res)) + +def producer(q): + for i in range(2): + time.sleep(random.randint(1,3)) + res='包子%s' %i + q.put(res) + print('%s 生产了 %s' %(os.getpid(),res)) + +if __name__ == '__main__': + q=Queue() + #生产者们:即厨师们 + p1=Process(target=producer,args=(q,)) + + #消费者们:即吃货们 + c1=Process(target=consumer,args=(q,)) + + #开始 + p1.start() + c1.start() + + p1.join() + q.put(None) #发送结束信号 + print('主') +``` + +有多个生产者和多个消费者时 +有几个消费者就需要发送几次结束信号 + +```python +from multiprocessing import Process,Queue +import time,random,os +def consumer(q): + while True: + res=q.get() + if res is None:break #收到结束信号则结束 + time.sleep(random.randint(1,3)) + print('%s 吃 %s' %(os.getpid(),res)) + +def producer(name,q): + for i in range(2): + time.sleep(random.randint(1,3)) + res='%s%s' %(name,i) + q.put(res) + print('%s 生产了 %s' %(os.getpid(),res)) + +if __name__ == '__main__': + q=Queue() + #生产者们:即厨师们 + p1=Process(target=producer,args=('包子',q)) + p2=Process(target=producer,args=('骨头',q)) + p3=Process(target=producer,args=('泔水',q)) + + #消费者们:即吃货们 + c1=Process(target=consumer,args=(q,)) + c2=Process(target=consumer,args=(q,)) + + #开始 + p1.start() + p2.start() + p3.start() + c1.start() + + p1.join() #必须保证生产者全部生产完毕,才应该发送结束信号 + p2.join() + p3.join() + q.put(None) #有几个消费者就应该发送几次结束信号None + q.put(None) #发送结束信号 + print('主') +``` + +**JoinableQueue([maxsize])** +创建可连接的共享进程队列。这就像是一个Queue对象,但队列允许项目的使用者通知生产者项目已经被成功处理。通知进程是使用共享的信号和条件变量来实现的。 + +- q.task_done() + 使用者使用此方法发出信号,表示q.get()返回的项目已经被处理。如果调用此方法的次数大于从队列中删除的项目数量,将引发ValueError异常。 + +- q.join() + 生产者将使用此方法进行阻塞,直到队列中所有项目均被处理。阻塞将持续到为队列中的每个项目均调用q.task_done()方法为止。 + +```python +from multiprocessing import Process, JoinableQueue +import time, random, os + + +def consumer(q): + while True: + res = q.get() + time.sleep(random.randint(1, 3)) + print('%s 吃 %s' % (os.getpid(), res)) + q.task_done() # 向q.join()发送一次信号,证明一个数据已经被取走了 + + +def producer(name, q): + for i in range(10): + time.sleep(random.randint(1, 3)) + res = '%s%s' % (name, i) + q.put(res) + print('%s 生产了 %s' % (os.getpid(), res)) + q.join() # 生产完毕,使用此方法进行阻塞,直到队列中所有项目均被处理。 + + +if __name__ == '__main__': + q = JoinableQueue() + # 生产者们:即厨师们 + p1 = Process(target=producer, args=('包子', q)) + p2 = Process(target=producer, args=('骨头', q)) + p3 = Process(target=producer, args=('泔水', q)) + + # 消费者们:即吃货们 + c1 = Process(target=consumer, args=(q,)) + c2 = Process(target=consumer, args=(q,)) + c1.daemon = True + c2.daemon = True + + # 开始 + p_l = [p1, p2, p3, c1, c2] + for p in p_l: + p.start() + + p1.join() + p2.join() + p3.join() + print('主') + + # 主进程等--->p1,p2,p3等---->c1,c2 + # p1,p2,p3结束了,证明c1,c2肯定全都收完了p1,p2,p3发到队列的数据 + # 因而c1,c2也没有存在的价值了,不需要继续阻塞在进程中影响主进程了。应该随着主进程的结束而结束,所以设置成守护进程就可以了。 +``` + +## 进程之间的数据共享 + +但进程间应该尽量避免通信,即便需要通信,也应该选择进程安全的工具来避免加锁带来的问题。 + +以后我们会尝试使用数据库来解决现在进程之间的数据共享问题。 + +进程间数据是独立的,可以借助于队列或管道实现通信,二者都是基于消息传递的 +虽然进程间数据独立,但可以通过Manager实现数据共享,事实上Manager的功能远不止于此 + +```python +from multiprocessing import Manager,Process,Lock +def work(d,lock): + with lock: #不加锁而操作共享的数据,肯定会出现数据错乱 + d['count']-=1 + +if __name__ == '__main__': + lock=Lock() + with Manager() as m: + dic=m.dict({'count':100}) + p_l=[] + for i in range(100): + p=Process(target=work,args=(dic,lock)) + p_l.append(p) + p.start() + for p in p_l: + p.join() + print(dic) +``` + +## 进程池和multiprocess.Pool模块 + +### 进程池 + +那么在成千上万个任务需要被执行的时候,我们就需要去创建成千上万个进程么?首先,创建进程需要消耗时间,销毁进程也需要消耗时间。第二即便开启了成千上万的进程,操作系统也不能让他们同时执行,这样反而会影响程序的效率。因此我们不能无限制的根据任务开启或者结束进程。 + +定义一个池子,在里面放上固定数量的进程,有需求来了,就拿一个池中的进程来处理任务,等到处理完毕,进程并不关闭,而是将进程再放回进程池中继续等待任务。如果有很多任务需要执行,池中的进程数量不够,任务就要等待之前的进程执行任务完毕归来,拿到空闲进程才能继续执行。也就是说,池中进程的数量是固定的,那么同一时间最多有固定数量的进程在运行。这样不会增加操作系统的调度难度,还节省了开闭进程的时间,也一定程度上能够实现并发效果。 + +### multiprocess.Pool模块 + +#### 概念介绍 + +`Pool([numprocess [,initializer [, initargs]]]):创建进程池` + +numprocess:要创建的进程数,如果省略,将默认使用cpu_count()的值 +initializer:是每个工作进程启动时要执行的可调用对象,默认为None +initargs:是要传给initializer的参数组 + +**方法介绍** + +p.apply(func [, args [, kwargs]]):在一个池工作进程中执行func(*args,**kwargs),然后返回结果。 +'''需要强调的是:此操作并不会在所有池工作进程中并执行func函数。如果要通过不同参数并发地执行func函数,必须从不同线程调用p.apply()函数或者使用p.apply_async()''' + +p.apply_async(func [, args [, kwargs]]):在一个池工作进程中执行func(*args,**kwargs),然后返回结果。 +'''此方法的结果是AsyncResult类的实例,callback是可调用对象,接收输入参数。当func的结果变为可用时,将理解传递给callback。callback禁止执行任何阻塞操作,否则将接收其他异步操作中的结果。''' + +p.close():关闭进程池,防止进一步操作。如果所有操作持续挂起,它们将在工作进程终止前完成 + +P.jion():等待所有工作进程退出。此方法只能在close()或teminate()之后调用 + +**其他方法** + +方法apply_async()和map_async()的返回值是AsyncResul的实例obj。实例具有以下方法 +obj.get():返回结果,如果有必要则等待结果到达。timeout是可选的。如果在指定时间内还没有到达,将引发一场。如果远程操作中引发了异常,它将在调用此方法时再次被引发。 +obj.ready():如果调用完成,返回True +obj.successful():如果调用完成且没有引发异常,返回True,如果在结果就绪之前调用此方法,引发异常 +obj.wait([timeout]):等待结果变为可用。 +obj.terminate():立即终止所有工作进程,同时不执行任何清理或结束任何挂起工作。如果p被垃圾回收,将自动调用此函数 + +#### 代码实例 + +**进程池和多进程效率对比** + +```python +from multiprocessing import Pool +import time + + +def func(n): + for i in range(10): # 将1到100,每个数打印十次 + print(n +1) + + +if __name__ == "__main__": + start = time.time() + pool = Pool(5) + pool.map(func, range(100)) # 一百个任务 + t2 = (time.time() - start) + print(t2) +``` + +```python +from multiprocessing import Process +import time + + +def func(n): + for i in range(10): # 同样将1到100,每个数打印十次 + print(n+1) + + +if __name__ == "__main__": + t1 = time.time() + p_list = [] + for i in range(100): + p = Process(target=func, args=(i,)) + p_list.append(p) + p.start() + for p in p_list: + p.join() + t2 = (time.time() - t1) + print(t2) +``` + +**同步和异步** + +同步调用 + +```python +import os,time +from multiprocessing import Pool + +def work(n): + print('%s run' %os.getpid()) + time.sleep(3) + return n**2 + +if __name__ == '__main__': + p=Pool(3) #进程池中从无到有创建三个进程,以后一直是这三个进程在执行任务 + res_l=[] + for i in range(10): + res=p.apply(work,args=(i,)) # 同步调用,直到本次任务执行完毕拿到res,等待任务work执行的过程中可能有阻塞也可能没有阻塞 + # 但不管该任务是否存在阻塞,同步调用都会在原地等着 + print(res_l) +``` + +异步调用 + +```python +import os +import time +import random +from multiprocessing import Pool + +def work(n): + print('%s run' %os.getpid()) + time.sleep(random.random()) + return n**2 + +if __name__ == '__main__': + p=Pool(3) #进程池中从无到有创建三个进程,以后一直是这三个进程在执行任务 + res_l=[] + for i in range(10): + res=p.apply_async(work,args=(i,)) # 异步运行,根据进程池中有的进程数,每次最多3个子进程在异步执行 + # 返回结果之后,将结果放入列表,归还进程,之后再执行新的任务 + # 需要注意的是,进程池中的三个进程不会同时开启或者同时结束 + # 而是执行完一个就释放一个进程,这个进程就去接收新的任务。 + res_l.append(res) + + # 异步apply_async用法:如果使用异步提交的任务,主进程需要使用join,等待进程池内任务都处理完,然后可以用get收集结果 + # 否则,主进程结束,进程池可能还没来得及执行,也就跟着一起结束了 + p.close() + p.join() + for res in res_l: + print(res.get()) #使用get来获取apply_aync的结果,如果是apply,则没有get方法,因为apply是同步执行,立刻获取结果,也根本无需get +``` + +进程池聊天 + +服务端 + +```python +#Pool内的进程数默认是cpu核数,假设为4(查看方法os.cpu_count()) +#开启6个客户端,会发现2个客户端处于等待状态 +#在每个进程内查看pid,会发现pid使用为4个,即多个客户端公用4个进程 +from socket import * +from multiprocessing import Pool +import os + +server=socket(AF_INET,SOCK_STREAM) +server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) +server.bind(('127.0.0.1',8080)) +server.listen(5) + +def talk(conn): + print('进程pid: %s' %os.getpid()) + while True: + try: + msg=conn.recv(1024) + if not msg:break + conn.send(msg.upper()) + except Exception: + break + +if __name__ == '__main__': + p=Pool(4) + while True: + conn,addr=server.accept() + p.apply_async(talk,args=(conn,)) + #p.apply(talk,args=(conn,)) # 同步的话,则同一时间只有一个客户端能访问 +``` + +客户端 + +```python +from socket import * + +client=socket(AF_INET,SOCK_STREAM) +client.connect(('127.0.0.1',8080)) + + +while True: + msg=input('>>: ').strip() + if not msg:continue + + client.send(msg.encode('utf-8')) + msg=client.recv(1024) + print(msg.decode('utf-8')) +``` + +并发开启多个客户端,服务端同一时间只有4个不同的pid,只能结束一个客户端,另外一个客户端才会进来. + +**回调函数** + + 需要回调函数的场景:进程池中任何一个任务一旦处理完了,就立即告知主进程:我好了额,你可以处理我的结果了。主进程则调用一个函数去处理该结果,该函数即回调函数 + + 我们可以把耗时间(阻塞)的任务放到进程池中,然后指定回调函数(主进程负责执行),这样主进程在执行回调函数时就省去了I/O的过程,直接拿到的是任务的结果。 + +```python +from multiprocessing import Pool +import requests +import json +import os + +def get_page(url): + print('<进程%s> get %s' %(os.getpid(),url)) + respone=requests.get(url) + if respone.status_code == 200: + return {'url':url,'text':respone.text} + +def pasrse_page(res): + print('<进程%s> parse %s' %(os.getpid(),res['url'])) + parse_res='url:<%s> size:[%s]\n' %(res['url'],len(res['text'])) + with open('db.txt','a') as f: + f.write(parse_res) + + +if __name__ == '__main__': + urls=[ + 'https://www.baidu.com', + 'https://www.python.org', + 'https://www.openstack.org', + 'http://www.sina.com.cn/' + ] + + p=Pool(3) + res_l=[] + for url in urls: + res=p.apply_async(get_page,args=(url,),callback=pasrse_page) + res_l.append(res) + + p.close() + p.join() + print([res.get()['url'] for res in res_l]) #拿到的是get_page的结果,其实完全没必要拿该结果,该结果已经传给回调函数处理了 +``` + +爬虫实例 + +```python +import re +from urllib.request import urlopen +from multiprocessing import Pool + +def get_page(url,pattern): + response=urlopen(url).read().decode('utf-8') + return pattern,response + +def parse_page(info): + pattern,page_content=info + res=re.findall(pattern,page_content) + for item in res: + dic={ + 'index':item[0].strip(), + 'title':item[1].strip(), + 'actor':item[2].strip(), + 'time':item[3].strip(), + } + print(dic) +if __name__ == '__main__': + regex = r'
.*?<.*?class="board-index.*?>(\d+).*?title="(.*?)".*?class="movie-item-info".*?

(.*?)

.*?

(.*?)

' + pattern1=re.compile(regex,re.S) + + url_dic={ + 'http://maoyan.com/board/7':pattern1, + } + + p=Pool() + res_l=[] + for url,pattern in url_dic.items(): + res=p.apply_async(get_page,args=(url,pattern),callback=parse_page) + res_l.append(res) + + for i in res_l: + i.get() +``` + +如果在主进程中等待进程池中所有任务都执行完毕后,再统一处理结果,则无需回调函数 \ No newline at end of file diff --git a/03.网络编程与并发/03.多进程/image-20210725221132043.png b/03.网络编程与并发/03.多进程/image-20210725221132043.png new file mode 100644 index 0000000..045940e Binary files /dev/null and b/03.网络编程与并发/03.多进程/image-20210725221132043.png differ diff --git a/03.网络编程与并发/03.多进程/image-20210725221139272.png b/03.网络编程与并发/03.多进程/image-20210725221139272.png new file mode 100644 index 0000000..e7a370f Binary files /dev/null and b/03.网络编程与并发/03.多进程/image-20210725221139272.png differ diff --git a/03.网络编程与并发/04.多线程.md b/03.网络编程与并发/04.多线程.md new file mode 100644 index 0000000..e2e6d3a --- /dev/null +++ b/03.网络编程与并发/04.多线程.md @@ -0,0 +1,636 @@ +# 多线程 + +## 操作系统线程理论 + +### 进程 + +进程只能在一个时间干一件事,如果想同时干两件事或多件事,进程就无能为力了。 + +进程在执行的过程中如果阻塞,例如等待输入,整个进程就会挂起,即使进程中有些工作不依赖于输入的数据,也将无法执行。 + +### 线程 + +60年代,在OS中能拥有资源和独立运行的基本单位是进程,然而随着计算机技术的发展,进程出现了很多弊端 + +1. 是由于进程是资源拥有者,创建、撤消与切换存在较大的时空开销,因此需要引入轻型进程; +2. 是由于对称多处理机(SMP)出现,可以满足多个运行单位,而多个进程并行开销过大。 + +因此在80年代,出现了能独立运行的基本单位——线程(Threads)。 +注意:进程是资源分配的最小单位,线程是CPU调度的最小单位.每一个进程中至少有一个线程。  + +### 进程和线程的关系 + +![image-20210725221459812](04.%E5%A4%9A%E7%BA%BF%E7%A8%8B/image-20210725221459812.png) + +线程与进程的区别可以归纳为以下4点: + +1. 地址空间和其它资源(如打开文件):进程间相互独立,同一进程的各线程间共享。某进程内的线程在其它进程不可见。 +2. 通信:进程间通信IPC,线程间可以直接读写进程数据段(如全局变量)来进行通信——需要进程同步和互斥手段的辅助,以保证数据的一致性。 +3. 调度和切换:线程上下文切换比进程上下文切换要快得多。 +4. 在多线程操作系统中,进程不是一个可执行的实体。 + +### 使用线程的实际场景 + +开启一个字处理软件进程,该进程肯定需要办不止一件事情,比如监听键盘输入,处理文字,定时自动将文字保存到硬盘,这三个任务操作的都是同一块数据,因而不能用多进程。只能在一个进程里并发地开启三个线程,如果是单线程,那就只能是,键盘输入时,不能处理文字和自动保存,自动保存时又不能输入和处理文字。 + +### 内存中的线程 + +![image-20210725221509219](04.%E5%A4%9A%E7%BA%BF%E7%A8%8B/image-20210725221509219.png) + +线程通常是有益的,但是带来了不小程序设计难度,线程的问题是: + +1. 父进程有多个线程,那么开启的子线程是否需要同样多的线程 + +2. 在同一个进程中,如果一个线程关闭了文件,而另外一个线程正准备往该文件内写内容呢? + +因此,在多线程的代码中,需要更多的心思来设计程序的逻辑、保护程序的数据。 + +## python使用线程 + +### 全局解释器锁GIL + +Python代码的执行由Python虚拟机(也叫解释器主循环)来控制。Python在设计之初就考虑到要在主循环中,同时只有一个线程在执行。虽然 Python 解释器中可以“运行”多个线程,但在任意时刻只有一个线程在解释器中运行。 +  对Python虚拟机的访问由全局解释器锁(GIL)来控制,正是这个锁能保证同一时刻只有一个线程在运行。 + +  在多线程环境中,Python 虚拟机按以下方式执行: + +1. 设置 GIL; + +2. 切换到一个线程去运行; + +3. 运行指定数量的字节码指令或者线程主动让出控制(可以调用 time.sleep(0)); + +4. 把线程设置为睡眠状态; + +5. 解锁 GIL; + +6. 再次重复以上所有步骤。 + 在调用外部代码(如 C/C++扩展函数)的时候,GIL将会被锁定,直到这个函数结束为止(由于在这期间没有Python的字节码被运行,所以不会做线程切换)编写扩展的程序员可以主动解锁GIL。 + +### python线程模块的选择 + +Python提供了几个用于多线程编程的模块,包括thread、threading和Queue等。thread和threading模块允许程序员创建和管理线程。thread模块提供了基本的线程和锁的支持,threading提供了更高级别、功能更强的线程管理的功能。Queue模块允许用户创建一个可以用于多个线程之间共享数据的队列数据结构。 + +避免使用thread模块,因为更高级别的threading模块更为先进,对线程的支持更为完善,而且使用thread模块里的属性有可能会与threading出现冲突;其次低级别的thread模块的同步原语很少(实际上只有一个),而threading模块则有很多;再者,thread模块中当主线程结束时,所有的线程都会被强制结束掉,没有警告也不会有正常的清除工作,至少threading模块能确保重要的子线程退出后进程才退出。 + +thread模块不支持守护线程,当主线程退出时,所有的子线程不论它们是否还在工作,都会被强行退出。而threading模块支持守护线程,守护线程一般是一个等待客户请求的服务器,如果没有客户提出请求它就在那等着,如果设定一个线程为守护线程,就表示这个线程是不重要的,在进程退出的时候,不用等待这个线程退出。 + +## threading模块 + +### 线程的创建 + +```python +from threading import Thread +import time +def sayhi(name): + time.sleep(2) + print('%s say hello' %name) + +if __name__ == '__main__': + t=Thread(target=sayhi,args=('aaron',)) + t.start() + print('主线程') +``` + +另一种创建进程的方式 + +```python +from threading import Thread +import time +class Sayhi(Thread): + def __init__(self,name): + super().__init__() + self.name=name + def run(self): + time.sleep(2) + print('%s say hello' % self.name) + + +if __name__ == '__main__': + t = Sayhi('aaron') + t.start() + print('主线程') +``` + +### 多线程与多进程 + +```python +from threading import Thread +from multiprocessing import Process +import os + +def work(): + print('hello',os.getpid()) + +if __name__ == '__main__': + #part1:在主进程下开启多个线程,每个线程都跟主进程的pid一样 + t1=Thread(target=work) + t2=Thread(target=work) + t1.start() + t2.start() + print('主线程/主进程pid',os.getpid()) + + #part2:开多个进程,每个进程都有不同的pid + p1=Process(target=work) + p2=Process(target=work) + p1.start() + p2.start() + print('主线程/主进程pid',os.getpid()) +``` + +效率对比 + +```python +from threading import Thread +from multiprocessing import Process +import os + +def work(): + print('hello') + +if __name__ == '__main__': + #在主进程下开启线程 + t=Thread(target=work) + t.start() + print('主线程/主进程') + ''' + 打印结果: + hello + 主线程/主进程 + ''' + + #在主进程下开启子进程 + t=Process(target=work) + t.start() + print('主线程/主进程') +``` + +内存数据共享 + +```python +from threading import Thread +from multiprocessing import Process +from threading import Thread +import os +def work(): + global n + n=0 + +if __name__ == '__main__': + # n=100 + # p=Process(target=work) + # p.start() + # p.join() + # print('主',n) #毫无疑问子进程p已经将自己的全局的n改成了0,但改的仅仅是它自己的,查看父进程的n仍然为100 + + + n=1 + t=Thread(target=work) + t.start() + t.join() + print('主',n) #查看结果为0,因为同一进程内的线程之间共享进程内的数据 +``` + +### 多线程实现socket + +服务端 + +```python +import multiprocessing +import threading + +import socket +s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) +s.bind(('127.0.0.1',8080)) +s.listen(5) + +def action(conn): + while True: + data=conn.recv(1024) + print(data) + conn.send(data.upper()) + +if __name__ == '__main__': + while True: + conn,addr=s.accept() + + p=threading.Thread(target=action,args=(conn,)) + p.start() +``` + +客户端 + +```python +import socket + +s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) +s.connect(('127.0.0.1',8080)) + +while True: + msg=input('>>: ').strip() + if not msg:continue + + s.send(msg.encode('utf-8')) + data=s.recv(1024) + print(data) +``` + +### Thread类的其他方法 + +- Thread实例对象的方法 + - isAlive(): 返回线程是否活动的。 + - getName(): 返回线程名。 + - setName(): 设置线程名。 + +- threading模块提供的一些方法: + - threading.currentThread(): 返回当前的线程变量。 + - threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。 + - threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。 + +```python +from threading import Thread +import threading +from multiprocessing import Process +import os + +def work(): + import time + time.sleep(3) + print(threading.current_thread().getName()) + + +if __name__ == '__main__': + #在主进程下开启线程 + t=Thread(target=work) + t.start() + + print(threading.current_thread().getName()) + print(threading.current_thread()) #主线程 + print(threading.enumerate()) #连同主线程在内有两个运行的线程 + print(threading.active_count()) + print('主线程/主进程') +``` + +使用join + +```python +from threading import Thread +import time +def sayhi(name): + time.sleep(2) + print('%s say hello' %name) + +if __name__ == '__main__': + t=Thread(target=sayhi,args=('aaron',)) + t.start() + t.join() + print('主线程') + print(t.is_alive()) +``` + +### 守护线程 + +无论是进程还是线程,都遵循:守护xx会等待主xx运行完毕后被销毁。需要强调的是:运行完毕并非终止运行 + +1. 对主进程来说,运行完毕指的是主进程代码运行完毕 + 主进程在其代码结束后就已经算运行完毕了(守护进程在此时就被回收),然后主进程会一直等非守护的子进程都运行完毕后回收子进程的资源(否则会产生僵尸进程),才会结束, +2. 对主线程来说,运行完毕指的是主线程所在的进程内所有非守护线程统统运行完毕,主线程才算运行完毕 + 主线程在其他非守护线程运行完毕后才算运行完毕(守护线程在此时就被回收)。因为主线程的结束意味着进程的结束,进程整体的资源都将被回收,而进程必须保证非守护线程都运行完毕后才能结束。 + +```python +from threading import Thread +import time +def sayhi(name): + time.sleep(2) + print('%s say hello' %name) + +if __name__ == '__main__': + t=Thread(target=sayhi,args=('aaron',)) + t.setDaemon(True) #必须在t.start()之前设置 + t.start() + + print('主线程') + print(t.is_alive()) +``` + +```python +from threading import Thread +import time +def foo(): + print(123) + time.sleep(1) + print("end123") + +def bar(): + print(456) + time.sleep(3) + print("end456") + +if __name__ == '__main__': + t1=Thread(target=foo) + t2=Thread(target=bar) + + t1.daemon=True + t1.start() + t2.start() + print("main") +``` + +## 锁 + +### 同步锁 + +没有锁的情况下 + +```python +from threading import Thread +import os,time +def work(): + global n + temp=n + time.sleep(0.1) + n=temp-1 +if __name__ == '__main__': + n=100 + l=[] + for i in range(100): + p=Thread(target=work) + l.append(p) + p.start() + for p in l: + p.join() + + print(n) +``` + +同步锁 + +```python +import threading +R=threading.Lock() +R.acquire() +''' +对公共数据的操作 +''' +R.release() +``` + +```python +from threading import Thread,Lock +import os,time +def work(): + global n + lock.acquire() + temp=n + time.sleep(0.1) + n=temp-1 + lock.release() +if __name__ == '__main__': + lock=Lock() + n=100 + l=[] + for i in range(100): + p=Thread(target=work) + l.append(p) + p.start() + for p in l: + p.join() + + print(n) #结果肯定为0,由原来的并发执行变成串行,牺牲了执行效率保证了数据安全 +``` + +```python +#不加锁:并发执行,速度快,数据不安全 +from threading import current_thread,Thread,Lock +import os,time +def task(): + global n + print('%s is running' %current_thread().getName()) + temp=n + time.sleep(0.5) + n=temp-1 + + +if __name__ == '__main__': + n=100 + lock=Lock() + threads=[] + start_time=time.time() + for i in range(100): + t=Thread(target=task) + threads.append(t) + t.start() + for t in threads: + t.join() + + stop_time=time.time() + print('主:%s n:%s' %(stop_time-start_time,n)) +``` + +```python +#不加锁:未加锁部分并发执行,加锁部分串行执行,速度慢,数据安全 +from threading import current_thread,Thread,Lock +import os,time +def task(): + #未加锁的代码并发运行 + time.sleep(3) + print('%s start to run' %current_thread().getName()) + global n + #加锁的代码串行运行 + lock.acquire() + temp=n + time.sleep(0.5) + n=temp-1 + lock.release() + +if __name__ == '__main__': + n=100 + lock=Lock() + threads=[] + start_time=time.time() + for i in range(100): + t=Thread(target=task) + threads.append(t) + t.start() + for t in threads: + t.join() + stop_time=time.time() + print('主:%s n:%s' %(stop_time-start_time,n)) +``` + +有的同学可能有疑问:既然加锁会让运行变成串行,那么我在start之后立即使用join,就不用加锁了啊,也是串行的效果啊 +没错:在start之后立刻使用jion,肯定会将100个任务的执行变成串行,毫无疑问,最终n的结果也肯定是0,是安全的,但问题是 +start后立即join:任务内的所有代码都是串行执行的,而加锁,只是加锁的部分即修改共享数据的部分是串行的 +单从保证数据安全方面,二者都可以实现,但很明显是加锁的效率更高. + +```python +from threading import current_thread,Thread,Lock +import os,time +def task(): + time.sleep(3) + print('%s start to run' %current_thread().getName()) + global n + temp=n + time.sleep(0.5) + n=temp-1 + + +if __name__ == '__main__': + n=100 + lock=Lock() + start_time=time.time() + for i in range(100): + t=Thread(target=task) + t.start() + t.join() + stop_time=time.time() + print('主:%s n:%s' %(stop_time-start_time,n)) +``` + +### 死锁与递归锁 + +两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为**死锁进程** + +```python +from threading import Lock as Lock +import time +mutexA=Lock() +mutexA.acquire() +mutexA.acquire() # 上面已经拿过一次key了,这边就拿不到了 +print(123) +mutexA.release() +mutexA.release() +``` + +解决方法,递归锁,在Python中为了支持在同一线程中多次请求同一资源,python提供了可重入锁RLock。 + +这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次acquire。直到一个线程所有的acquire都被release,其他的线程才能获得资源。上面的例子如果使用RLock代替Lock,则不会发生死锁 + +```python +from threading import RLock as Lock +import time +mutexA=Lock() +mutexA.acquire() +mutexA.acquire() +print(123) +mutexA.release() +mutexA.release() +``` + +吃面的问题 + +```python +import time +from threading import Thread,Lock +noodle_lock = Lock() +fork_lock = Lock() +def eat1(name): + noodle_lock.acquire() + print('%s 抢到了面条'%name) + fork_lock.acquire() + print('%s 抢到了叉子'%name) + print('%s 吃面'%name) + fork_lock.release() + noodle_lock.release() + +def eat2(name): + fork_lock.acquire() + print('%s 抢到了叉子' % name) + time.sleep(1) + noodle_lock.acquire() + print('%s 抢到了面条' % name) + print('%s 吃面' % name) + noodle_lock.release() + fork_lock.release() + +for name in ['顾客1','顾客2','顾客3']: + t1 = Thread(target=eat1,args=(name,)) + t2 = Thread(target=eat2,args=(name,)) + t1.start() + t2.start() +``` + +使用递归锁解决问题 + +```python +import time +from threading import Thread,RLock + +noodle_lock = fork_lock = RLock() + +def eat1(name): + noodle_lock.acquire() + print('%s 抢到了面条'%name) + fork_lock.acquire() + print('%s 抢到了叉子'%name) + print('%s 吃面'%name) + fork_lock.release() + noodle_lock.release() + +def eat2(name): + fork_lock.acquire() + print('%s 抢到了叉子' % name) + time.sleep(1) + noodle_lock.acquire() + print('%s 抢到了面条' % name) + print('%s 吃面' % name) + noodle_lock.release() + fork_lock.release() + +for name in ['顾客1','顾客2','顾客3']: + t1 = Thread(target=eat1,args=(name,)) + t2 = Thread(target=eat2,args=(name,)) + t1.start() + t2.start() +``` + +### 线程队列 + +queue队列 :使用import queue,用法与进程Queue一样 + +先进先出 + +```python +import queue + +q=queue.Queue() +q.put('first') +q.put('second') +q.put('third') + +print(q.get()) +print(q.get()) +print(q.get()) +``` + +先进后出 + +```python +import queue + +q=queue.LifoQueue() +q.put('first') +q.put('second') +q.put('third') + +print(q.get()) +print(q.get()) +print(q.get()) +``` + +优先级队列 + +```python + +import queue + +q=queue.PriorityQueue() +##put进入一个元组,元组的第一个元素是优先级(通常是数字,也可以是非数字之间的比较),数字越小优先级越高 +q.put((20,'a')) +q.put((10,'b')) +q.put((30,'c')) + +print(q.get()) +print(q.get()) +print(q.get()) +``` \ No newline at end of file diff --git a/03.网络编程与并发/04.多线程/image-20210725221459812.png b/03.网络编程与并发/04.多线程/image-20210725221459812.png new file mode 100644 index 0000000..d4674be Binary files /dev/null and b/03.网络编程与并发/04.多线程/image-20210725221459812.png differ diff --git a/03.网络编程与并发/04.多线程/image-20210725221509219.png b/03.网络编程与并发/04.多线程/image-20210725221509219.png new file mode 100644 index 0000000..1c44bff Binary files /dev/null and b/03.网络编程与并发/04.多线程/image-20210725221509219.png differ diff --git a/03.网络编程与并发/05.多协程.md b/03.网络编程与并发/05.多协程.md new file mode 100644 index 0000000..b2b7a1a --- /dev/null +++ b/03.网络编程与并发/05.多协程.md @@ -0,0 +1,425 @@ +# 多协程 + +## 协程理论 + +进程是资源分配的最小单位,线程是CPU调度的最小单位 + +无论是创建多进程还是创建多线程来解决问题,都要消耗一定的时间来创建进程、创建线程、以及管理他们之间的切换。 + +随着我们对于效率的追求不断提高,基于单线程来实现并发又成为一个新的课题,即只用一个主线程(很明显可利用的cpu只有一个)情况下实现并发。这样就可以节省创建线进程所消耗的时间。 + +cpu正在运行一个任务,会在两种情况下切走去执行其他的任务(切换由操作系统强制控制),一种情况是该任务发生了阻塞,另外一种情况是该任务计算的时间过长 + +![image-20210725221729223](05.%E5%A4%9A%E5%8D%8F%E7%A8%8B/image-20210725221729223.png) + +其中第二种情况并不能提升效率,只是为了让cpu能够雨露均沾,实现看起来所有任务都被“同时”执行的效果,如果多个任务都是纯计算的,这种切换反而会降低效率。 + +为此我们可以基于yield来验证。yield本身就是一种在单线程下可以保存任务运行状态的方法 + +1. yield可以保存状态,yield的状态保存与操作系统的保存线程状态很像,但是yield是代码级别控制的,更轻量级 +2. send可以把一个函数的结果传给另外一个函数,以此实现单线程内程序之间的切换 + +```python +#串行执行 +import time +def consumer(res): + '''任务1:接收数据,处理数据''' + pass + +def producer(): + '''任务2:生产数据''' + res=[] + for i in range(10000000): + res.append(i) + return res + +start=time.time() +#串行执行 +res=producer() +consumer(res) #写成consumer(producer())会降低执行效率 +stop=time.time() +print(stop-start) #1.5536692142486572 + + + +#基于yield并发执行 +import time +def consumer(): + '''任务1:接收数据,处理数据''' + while True: + x=yield + +def producer(): + '''任务2:生产数据''' + g=consumer() + next(g) + for i in range(10000000): + g.send(i) + +start=time.time() +#基于yield保存状态,实现两个任务直接来回切换,即并发的效果 +#PS:如果每个任务中都加上打印,那么明显地看到两个任务的打印是你一次我一次,即并发执行的. +producer() + +stop=time.time() +print(stop-start) #2.0272178649902344 +``` + +第一种情况的切换。在任务一遇到io情况下,切到任务二去执行,这样就可以利用任务一阻塞的时间完成任务二的计算,效率的提升就在于此。 + +```python +import time +def consumer(): + '''任务1:接收数据,处理数据''' + while True: + x=yield + +def producer(): + '''任务2:生产数据''' + g=consumer() + next(g) + for i in range(10000000): + g.send(i) + time.sleep(2) + +start=time.time() +producer() #并发执行,但是任务producer遇到io就会阻塞住,并不会切到该线程内的其他任务去执行 + +stop=time.time() +print(stop-start) +``` + +1. 可以控制多个任务之间的切换,切换之前将任务的状态保存下来,以便重新运行时,可以基于暂停的位置继续执行。 +2. 作为1的补充:可以检测io操作,在遇到io操作的情况下才发生切换 + +## 协程 + +协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的。、 + +1. python的线程属于内核级别的,即由操作系统控制调度(如单线程遇到io或执行时间过长就会被迫交出cpu执行权限,切换其他线程运行) +2. 单线程内开启协程,一旦遇到io,就会从应用程序级别(而非操作系统)控制切换,以此来提升效率(!!!非io操作的切换与效率无关) + +对比操作系统控制线程的切换,用户在单线程内控制协程的切换 + +优点: + +1. 协程的切换开销更小,属于程序级别的切换,操作系统完全感知不到,因而更加轻量级 +2. 单线程内就可以实现并发的效果,最大限度地利用cpu + +缺点: + +1. 协程的本质是单线程下,无法利用多核,可以是一个程序开启多个进程,每个进程内开启多个线程,每个线程内开启协程 +2. 协程指的是单个线程,因而一旦协程出现阻塞,将会阻塞整个线程 + +协程特点: + +1. 必须在只有一个单线程里实现并发 +2. 修改共享数据不需加锁 +3. 用户程序里自己保存多个控制流的上下文栈 +4. 附加:一个协程遇到IO操作自动切换到其它协程(如何实现检测IO,yield、greenlet都无法实现,就用到了gevent模块(select机制) + +## Greenlet模块 + +pip install greenlet + +```python +from greenlet import greenlet + +def eat(name): + print('%s eat 1' %name) + g2.switch('aaron') + print('%s eat 2' %name) + g2.switch() +def play(name): + print('%s play 1' %name) + g1.switch() + print('%s play 2' %name) + +g1=greenlet(eat) +g2=greenlet(play) + +g1.switch('aaron') # 可以在第一次switch时传入参数,以后都不需要 +``` + +单纯的切换(在没有io的情况下或者没有重复开辟内存空间的操作),反而会降低程序的执行速度 + +```python +#顺序执行 +import time +def f1(): + res=1 + for i in range(100000000): + res+=i + +def f2(): + res=1 + for i in range(100000000): + res*=i + +start=time.time() +f1() +f2() +stop=time.time() +print('run time is %s' %(stop-start)) + +#切换 +from greenlet import greenlet +import time +def f1(): + res=1 + for i in range(100000000): + res+=i + g2.switch() + +def f2(): + res=1 + for i in range(100000000): + res*=i + g1.switch() + +start=time.time() +g1=greenlet(f1) +g2=greenlet(f2) +g1.switch() +stop=time.time() +print('run time is %s' %(stop-start)) +``` + +greenlet只是提供了一种比generator更加便捷的切换方式,当切到一个任务执行时如果遇到io,那就原地阻塞,仍然是没有解决遇到IO自动切换来提升效率的问题。 + +单线程里的这20个任务的代码通常会既有计算操作又有阻塞操作,我们完全可以在执行任务1时遇到阻塞,就利用阻塞的时间去执行任务2。。。。如此,才能提高效率,这就用到了Gevent模块。 + +## Gevent模块 + +pip install gevent + +Gevent 是一个第三方库,可以轻松通过gevent实现并发同步或异步编程,在gevent中用到的主要模式是Greenlet, 它是以C扩展模块形式接入Python的轻量级协程。 Greenlet全部运行在主程序操作系统进程的内部,但它们被协作式地调度。 + +用法介绍 + +```python +g1=gevent.spawn(func,1,2,3,x=4,y=5) # 创建一个协程对象g1,spawn括号内第一个参数是函数名,如eat,后面可以有多个参数,可以是位置实参或关键字实参,都是传给函数eat的 + +g2=gevent.spawn(func2) + +g1.join() #等待g1结束 + +g2.join() #等待g2结束 + +#或者上述两步合作一步:gevent.joinall([g1,g2]) + +g1.value#拿到func1的返回值 +``` + +```python +import gevent +def eat(name): + print('%s eat 1' %name) + gevent.sleep(2) + print('%s eat 2' %name) + +def play(name): + print('%s play 1' %name) + gevent.sleep(1) + print('%s play 2' %name) + + +g1=gevent.spawn(eat,'aaron') +g2=gevent.spawn(play,name='aaron') +g1.join() +g2.join() +#或者gevent.joinall([g1,g2]) +print('主') +``` + +上例gevent.sleep(2)模拟的是gevent可以识别的io阻塞,而time.sleep(2)或其他的阻塞,gevent是不能直接识别的需要用下面一行代码,打补丁,就可以识别了 + +from gevent import monkey;monkey.patch_all()必须放到被打补丁者的前面,如time,socket模块之前 + +或者我们干脆记忆成:要用gevent,需要将from gevent import monkey;monkey.patch_all()放到文件的开头 + +```python +from gevent import monkey;monkey.patch_all() + +import gevent +import time +def eat(): + print('eat food 1') + time.sleep(2) + print('eat food 2') + +def play(): + print('play 1') + time.sleep(1) + print('play 2') + +g1=gevent.spawn(eat) +g2=gevent.spawn(play) +gevent.joinall([g1,g2]) +print('主') +``` + +用threading.current_thread().getName()来查看每个g1和g2,查看的结果为DummyThread-n,即假线程 + +```python +from gevent import monkey;monkey.patch_all() +import threading +import gevent +import time +def eat(): + print(threading.current_thread().getName()) + print('eat food 1') + time.sleep(2) + print('eat food 2') + +def play(): + print(threading.current_thread().getName()) + print('play 1') + time.sleep(1) + print('play 2') + +g1=gevent.spawn(eat) +g2=gevent.spawn(play) +gevent.joinall([g1,g2]) +print('主') +``` + +## Gevent之同步与异步 + +```python +from gevent import spawn,joinall,monkey;monkey.patch_all() + +import time +def task(pid): + """ + Some non-deterministic task + """ + time.sleep(0.5) + print('Task %s done' % pid) + + +def synchronous(): # 同步 + for i in range(10): + task(i) + +def asynchronous(): # 异步 + g_l=[spawn(task,i) for i in range(10)] + joinall(g_l) + print('DONE') + +if __name__ == '__main__': + print('Synchronous:') + synchronous() + print('Asynchronous:') + asynchronous() +# 上面程序的重要部分是将task函数封装到Greenlet内部线程的gevent.spawn。 +# 初始化的greenlet列表存放在数组threads中,此数组被传给gevent.joinall 函数, +# 后者阻塞当前流程,并执行所有给定的greenlet任务。执行流程只会在 所有greenlet执行完后才会继续向下走。 +``` + +## Gevent之应用举例一 + +```python +from gevent import monkey;monkey.patch_all() +import gevent +import requests +import time + +def get_page(url): + print('GET: %s' %url) + response=requests.get(url) + if response.status_code == 200: + print('%d bytes received from %s' %(len(response.text),url)) + + +start_time=time.time() +gevent.joinall([ + gevent.spawn(get_page,'https://www.python.org/'), + gevent.spawn(get_page,'https://www.yahoo.com/'), + gevent.spawn(get_page,'https://github.com/'), +]) +stop_time=time.time() +print('run time is %s' %(stop_time-start_time)) +``` + +## Gevent之应用举例二 + +通过gevent实现单线程下的socket并发 + +注意 :from gevent import monkey;monkey.patch_all()一定要放到导入socket模块之前,否则gevent无法识别socket的阻塞 + +服务端 + +```python +from gevent import monkey;monkey.patch_all() +from socket import * +import gevent + +#如果不想用money.patch_all()打补丁,可以用gevent自带的socket +# from gevent import socket +# s=socket.socket() + +def server(server_ip,port): + s=socket(AF_INET,SOCK_STREAM) + s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) + s.bind((server_ip,port)) + s.listen(5) + while True: + conn,addr=s.accept() + gevent.spawn(talk,conn,addr) + +def talk(conn,addr): + try: + while True: + res=conn.recv(1024) + print('client %s:%s msg: %s' %(addr[0],addr[1],res)) + conn.send(res.upper()) + except Exception as e: + print(e) + finally: + conn.close() + +if __name__ == '__main__': + server('127.0.0.1',8088) +``` + +客户端 + +```python +from socket import * + +client=socket(AF_INET,SOCK_STREAM) +client.connect(('127.0.0.1',8080)) + + +while True: + msg=input('>>: ').strip() + if not msg:continue + + client.send(msg.encode('utf-8')) + msg=client.recv(1024) + print(msg.decode('utf-8')) +``` + +多线程并发客户端 + +```python +from threading import Thread +from socket import * +import threading + +def client(server_ip,port): + c=socket(AF_INET,SOCK_STREAM) #套接字对象一定要加到函数内,即局部名称空间内,放在函数外则被所有线程共享,则大家公用一个套接字对象,那么客户端端口永远一样了 + c.connect((server_ip,port)) + + count=0 + while True: + c.send(('%s say hello %s' %(threading.current_thread().getName(),count)).encode('utf-8')) + msg=c.recv(1024) + print(msg.decode('utf-8')) + count+=1 +if __name__ == '__main__': + for i in range(500): + t=Thread(target=client,args=('127.0.0.1',8088)) + t.start() +``` \ No newline at end of file diff --git a/03.网络编程与并发/05.多协程/image-20210725221729223.png b/03.网络编程与并发/05.多协程/image-20210725221729223.png new file mode 100644 index 0000000..fd7b149 Binary files /dev/null and b/03.网络编程与并发/05.多协程/image-20210725221729223.png differ diff --git a/04.Flask/01.URL与视图.md b/04.Flask/01.URL与视图.md new file mode 100644 index 0000000..0fad4e3 --- /dev/null +++ b/04.Flask/01.URL与视图.md @@ -0,0 +1,252 @@ +# URL与视图 + +## 1. Flask简介 + +`flask`是一款非常流行的`Python Web`框架,出生于2010年,作者是`Armin Ronacher`,本来这个项目只是作者在愚人节的一个玩笑,后来由于非常受欢迎,进而成为一个正式的项目。 + +`flask`自2010年发布第一个版本以来,大受欢迎,深得开发者的喜爱,目前在`Github`上的Star数已经超过`55.5k`了,有超`Django`之趋势。`flask`能如此流行的原因,可以分为以下几点: + +- 微框架、简洁、只做他需要做的,给开发者提供了很大的扩展性。 +- Flask和相应的插件写得很好,用起来很爽。 +- 开发效率非常高,比如使用`SQLAlchemy`的`ORM`操作数据库可以节省开发者大量书写`sql`的时间。 + +`Flask`的灵活度非常之高,他不会帮你做太多的决策,一些你都可以按照自己的意愿进行更改。比如: + +- 使用`Flask`开发数据库的时候,具体是使用`SQLAlchemy`还是`MongoEngine`,选择权完全掌握在你自己的手中。区别于`Django`,`Django`内置了非常完善和丰富的功能,并且如果你想替换成你自己想要的,要么不支持,要么非常麻烦。 +- 把默认的`Jinija2`模板引擎替换成其他模板引擎都是非常容易的。 + +### 1.1 安装Flask + +通过`pip install flask`即可安装。 + +### 1.2 第一个flask程序 + +用`pycharm`新建一个`flask`项目,新建项目的截图如下: + +![img](01.URL%E4%B8%8E%E8%A7%86%E5%9B%BE/87L8AaNBNKGcAAn7oomKYT.png) + +点击`create`后创建一个新项目,然后在`helloworld.py`文件中书写代码: + +```python +#coding: utf8 + +# 从flask框架中导入Flask类 +from flask import Flask + +# 传入__name__初始化一个Flask实例 +app = Flask(__name__) + +# app.route装饰器映射URL和执行的函数。这个设置将根URL映射到了hello_world函数上 +@app.route('/') +def hello_world(): + return 'Hello World!' + +if __name__ == '__main__': + # 运行本项目,host=0.0.0.0可以让其他电脑也能访问到该网站,port指定访问的端口。默认的host是127.0.0.1,port为5000 + app.run(host='0.0.0.0',port=9000) +``` + +然后点击运行,在浏览器中输入`http://127.0.0.1:9000`就能看到`hello world`了。需要说明一点的是,`app.run`这种方式只适合于开发,如果在生产环境中,应该使用`Gunicorn`或者`uWSGI`来启动。如果是在终端运行的,可以按`ctrl+c`来让服务停止。 + +## 2. 项目配置 + +### 2.1 设置为DEBUG模式 + +默认情况下`flask`不会开启`DEBUG`模式,开启`DEBUG`模式后,flask会在每次保存代码的时候自动的重新载入代码,并且如果代码有错误,会在终端进行提示。 + +![img](01.URL%E4%B8%8E%E8%A7%86%E5%9B%BE/2UZz2JSDySff5o8CPeqPRN.png) + +如果一切正常,会在终端打印以下信息: + +``` +* Restarting with stat +* Debugger is active! +* Debugger pin code: 294-745-044 +* Running on http://0.0.0.0:9000/ (Press CTRL+C to quit) +``` + +需要注意的是,只能在开发环境下开启`DEBUG`模式,因为`DEBUG`模式会带来非常大的安全隐患。 + +### 2.2 配置文件 + +`Flask`项目的配置,都是通过`app.config`对象来进行配置的。比如要配置一个项目的`SECRET_KEY`,那么可以使用`app.config['SECRET_KEY'] = "xxx"`来进行设置,在`Flask`项目中,有四种方式进行项目的配置: + +1. 直接硬编码: + +```python +app = Flask(__name__) +app.config['SECRET_KEY'] = "xxx" +``` + +2. 因为`app.config`是`flask.config.Config`的实例,而`Config`类是继承自`dict`,因此可以通过`update`方法: + +```python +app.config.update( + DEBUG=True, + SECRET_KEY='...' +) +``` + +3. 如果你的配置项特别多,你可以把所有的配置项都放在一个模块中,然后通过加载模块的方式进行配置,假设有一个`settings.py`模块,专门用来存储配置项的,此时你可以通过`app.config.from_object()`方法进行加载,并且该方法既可以接收模块的的字符串名称,也可以模块对象: + +```python +# 1. 通过模块字符串 +app.config.from_object('settings') +# 2. 通过模块对象 +import settings +app.config.from_object(settings) +``` + +4. 也可以通过另外一个方法加载,该方法就是`app.config.from_pyfile()`,该方法传入一个文件名,通常是以`.py`结尾的文件,但也不限于只使用`.py`后缀的文件: + +```python +app.config.from_pyfile('settings.py',silent=True) +# silent=True表示如果配置文件不存在的时候不抛出异常,默认是为False,会抛出异常。 +``` + +## 3. URL与视图 + +### 3.1 URL与函数的映射 + +从之前的`helloworld.py`文件中,我们已经看到,一个`URL`要与执行函数进行映射,使用的是`@app.route`装饰器。`@app.route`装饰器中,可以指定`URL`的规则来进行更加详细的映射,比如现在要映射一个文章详情的`URL`,文章详情的`URL`是`/article/id/`,id有可能为1、2、3…,那么可以通过以下方式: + +```python +@app.route('/article//') +def article(id): + return '%s article detail' % id +``` + +其中``,尖括号是固定写法,语法为``,`variable`默认的数据类型是字符串。如果需要指定类型,则要写成``,其中`converter`就是类型名称,可以有以下几种: + +- string: 默认的数据类型,接受没有任何斜杠`/`的字符串。 +- int: 整形 +- float: 浮点型。 +- path: 和`string`类似,但是可以传递斜杠`/`。 +- uuid: `uuid`类型的字符串。 +- any:可以指定多种路径,这个通过一个例子来进行说明: + +```python +@app.route('//') +def item(url_path): + return url_path +``` + +以上例子中,`item`这个函数可以接受两个`URL`,一个是`/article/`,另一个是`/blog/`。并且,一定要传`url_path`参数,当然这个`url_path`的名称可以随便。 + +如果不想定制子路径来传递参数,也可以通过传统的`?=`的形式来传递参数,例如:`/article?id=xxx`,这种情况下,可以通过`request.args.get('id')`来获取`id`的值。如果是`post`方法,则可以通过`request.form.get('id')`来进行获取。 + +### 3.2 构造URL(url_for) + +一般我们通过一个`URL`就可以执行到某一个函数。如果反过来,我们知道一个函数,怎么去获得这个`URL`呢?`url_for`函数就可以帮我们实现这个功能。`url_for()`函数接收两个及以上的参数,他接收**函数名**作为第一个参数,接收对应**URL规则的命名参数**,如果还出现其他的参数,则会添加到`URL`的后面作为**查询参数**。 + +通过构建`URL`的方式而选择直接在代码中拼`URL`的原因有两点: + +1. 将来如果修改了`URL`,但没有修改该`URL`对应的函数名,就不用到处去替换`URL`了。 +2. `url_for()`函数会转义一些特殊字符和`unicode`字符串,这些事情`url_for`会自动的帮我们搞定。 + +下面用一个例子来进行解释: + +```python +from flask import Flask,url_for +app = Flask(__name__) + +@app.route('/article//') +def article(id): + return '%s article detail' % id + +@app.route('/') +def index(request): + print(url_for("article",id=1)) + return "首页" +``` + +在访问index的时候,会打印出`/article/1/`。 + +### 3.3 指定URL末尾的斜杠 + +有些`URL`的末尾是有斜杠的,有些`URL`末尾是没有斜杠的。这其实是两个不同的`URL`。 + +举个例子: + +```python + @app.route('/article/') + def articles(): + return '文章列表页' +``` + +上述例子中,当访问一个结尾不带斜线的`URL`:`/article`,会被重定向到带斜线的`URL`:`/article/`上去。但是当我们在定义`article`的`url`的时候,如果在末尾没有加上斜杠,但是在访问的时候又加上了斜杠,这时候就会抛出一个`404`错误页面了: + +```python +@app.route("/article") +def articles(request): + return "文章列表页面" +``` + +以上没有在末尾加斜杠,因此在访问`/article/`的时候,就会抛出一个`404`错误。 + +### 3.4 指定HTTP方法 + +在`@app.route()`中可以传入一个关键字参数`methods`来指定本方法支持的`HTTP`方法,默认情况下,只能使用`GET`请求,看以下例子: + +```python +@app.route('/login/',methods=['GET','POST']) +def login(): + return 'login' +``` + +以上装饰器将让`login`的`URL`既能支持`GET`又能支持`POST`。 + +### 3.5 页面跳转和重定向 + +重定向分为永久性重定向和暂时性重定向,在页面上体现的操作就是浏览器会从一个页面自动跳转到另外一个页面。比如用户访问了一个需要权限的页面,但是该用户当前并没有登录,因此我们应该给他重定向到登录页面。 + +- 永久性重定向:`http`的状态码是`301`,多用于旧网址被废弃了要转到一个新的网址确保用户的访问,最经典的就是京东网站,你输入`www.jingdong.com`的时候,会被重定向到`www.jd.com`,因为`jingdong.com`这个网址已经被废弃了,被改成`jd.com`,所以这种情况下应该用永久重定向。 +- 暂时性重定向:`http`的状态码是`302`,表示页面的暂时性跳转。比如访问一个需要权限的网址,如果当前用户没有登录,应该重定向到登录页面,这种情况下,应该用暂时性重定向。 + +在`flask`中,重定向是通过`flask.redirect(location,code=302)`这个函数来实现的,`location`表示需要重定向到的`URL`,应该配合之前讲的`url_for()`函数来使用,`code`表示采用哪个重定向,默认是`302`也即`暂时性重定向`,可以修改成`301`来实现永久性重定向。 + +以下来看一个例子,关于在`flask`中怎么使用重定向: + +```python + from flask import Flask,url_for,redirect + + app = Flask(__name__) + app.debug = True + + @app.route('/login/',methods=['GET','POST']) + def login(): + return 'login page' + + @app.route('/profile/',methods=['GET','POST']) + def profile(): + name = request.args.get('name') + + if not name: + # 如果没有name,说明没有登录,重定向到登录页面 + return redirect(url_for('login')) + else: + return name +``` + + + + + + + + + + + + + + + + + + + + + + + diff --git a/04.Flask/01.URL与视图/2UZz2JSDySff5o8CPeqPRN.png b/04.Flask/01.URL与视图/2UZz2JSDySff5o8CPeqPRN.png new file mode 100644 index 0000000..e00d2e5 Binary files /dev/null and b/04.Flask/01.URL与视图/2UZz2JSDySff5o8CPeqPRN.png differ diff --git a/04.Flask/01.URL与视图/87L8AaNBNKGcAAn7oomKYT.png b/04.Flask/01.URL与视图/87L8AaNBNKGcAAn7oomKYT.png new file mode 100644 index 0000000..b07a7c1 Binary files /dev/null and b/04.Flask/01.URL与视图/87L8AaNBNKGcAAn7oomKYT.png differ diff --git a/04.Flask/02.Jinja2模板.md b/04.Flask/02.Jinja2模板.md new file mode 100644 index 0000000..faa4e5e --- /dev/null +++ b/04.Flask/02.Jinja2模板.md @@ -0,0 +1,493 @@ +# Jinja2模板 + +## 1. 模板简介 + +模板是一个`web`开发必备的模块。因为我们在渲染一个网页的时候,并不是只渲染一个纯文本字符串,而是需要渲染一个有富文本标签的页面。这时候我们就需要使用模板了。在`Flask`中,配套的模板是`Jinja2`,`Jinja2`的作者也是`Flask`的作者。这个模板非常的强大,并且执行效率高。以下对`Jinja2`做一个简单介绍! + +### 1.1 Flask渲染`Jinja`模板: + +要渲染一个模板,通过`render_template`方法即可,以下将用一个简单的例子进行讲解: + +```python +from flask import Flask,render_template +app = Flask(__name__) + +@app.route('/about/') +def about(): + return render_template('about.html') +``` + +当访问`/about/`的时候,`about()`函数会在当前目录下的`templates`文件夹下寻找`about.html`模板文件。如果想更改模板文件地址,应该在创建`app`的时候,给`Flask`传递一个关键字参数`template_folder`,指定具体的路径,再看以下例子: + +```python +from flask import Flask,render_template +app = Flask(__name__,template_folder=r'C:\templates') + +@app.route('/about/') +def about(): + return render_template('about.html') +``` + +以上例子将会在C盘的`templates`文件夹中寻找模板文件。还有最后一点是,如果模板文件中有参数需要传递,应该怎么传呢,我们再来看一个例子: + +```python +from flask import Flask,render_template +app = Flask(__name__) + +@app.route('/about/') +def about(): + # return render_template('about.html',user='zhiliao') + return render_template('about.html',**{'user':'zhiliao'}) +``` + +以上例子介绍了两种传递参数的方式,因为`render_template`需要传递的是一个关键字参数,所以第一种方式是顺其自然的。但是当你的模板中要传递的参数过多的时候,把所有参数放在一个函数中显然不是一个好的选择,因此我们使用字典进行包装,并且加两个`*`号,来转换成关键字参数。 + +## 2. Jinja2模版概述 + +### 2.1 概要: + +先看一个简单例子: + +```html +1. +2. +3. My Webpage +4. +5. +6. +11. +12. {{ a_variable }} +13. {{ user.name }} +14. {{ user['name'] }} +15. +16. {# a comment #} +17. +18. +``` + +以上示例有需要进行解释: + +- 第12~14行的`{{ ... }}`:用来装载一个变量,模板渲染的时候,会把这个变量代表的值替换掉。并且可以间接访问一个变量的属性或者一个字典的`key`。关于点`.`号访问和`[]`中括号访问,没有任何区别,都可以访问属性和字典的值。 +- 第7~9行的`{% ... %}`:用来装载一个控制语句,以上装载的是`for`循环,以后只要是要用到控制语句的,就用`{% ... %}`。 +- 第14行的`{# ... #}`:用来装载一个注释,模板渲染的时候会忽视这中间的值。 + +### 2.2 属性访问规则: + +1. 比如在模板中有一个变量这样使用:`foo.bar`,那么在`Jinja2`中是这样进行访问的: + - 先去查找`foo`的`bar`这个属性,也即通过`getattr(foo,'bar')`。 + - 如果没有,就去通过`foo.__getitem__('bar')`的方式进行查找。 + - 如果以上两种方式都没有找到,返回一个`undefined`。 +2. 在模板中有一个变量这样使用:`foo['bar']`,那么在`Jinja2`中是这样进行访问: + - 通过`foo.__getitem__('bar')`的方式进行查找。 + - 如果没有,就通过`getattr(foo,'bar')`的方式进行查找。 + - 如果以上没有找到,则返回一个`undefined`。 + +## 3. Jinja2模版过滤器 + +过滤器是通过管道符号(`|`)进行使用的,例如:`{{ name|length }}`,将返回name的长度。过滤器相当于是一个函数,把当前的变量传入到过滤器中,然后过滤器根据自己的功能,再返回相应的值,之后再将结果渲染到页面中。`Jinja2`中内置了许多过滤器,在[这里](https://jinja.palletsprojects.com/en/3.0.x/templates/#list-of-builtin-filters)可以看到所有的过滤器,现对一些常用的过滤器进行讲解: + +1. `abs(value)`:返回一个数值的绝对值。 例如:`-1|abs`。 + +2. `default(value,default_value,boolean=false)`:如果当前变量没有值,则会使用参数中的值来代替。`name|default('xiaotuo')`——如果name不存在,则会使用`xiaotuo`来替代。`boolean=False`默认是在只有这个变量为`undefined`的时候才会使用`default`中的值,如果想使用`python`的形式判断是否为`false`,则可以传递`boolean=true`。也可以使用`or`来替换。 + +3. `escape(value)或e`:转义字符,会将`<`、`>`等符号转义成HTML中的符号。例如:`content|escape`或`content|e`。 + +4. `first(value)`:返回一个序列的第一个元素。`names|first`。 + +5. `format(value,*arags,**kwargs)`:格式化字符串。例如以下代码: + +```jinja2 +{{ "%s" - "%s"|format('Hello?',"Foo!") }} +``` + + 将输出:Helloo? - Foo! + +6. `last(value)`:返回一个序列的最后一个元素。示例:`names|last`。 + +7. `length(value)`:返回一个序列或者字典的长度。示例:`names|length`。 + +8. `join(value,d=u'')`:将一个序列用`d`这个参数的值拼接成字符串。 + +9. `safe(value)`:如果开启了全局转义,那么`safe`过滤器会将变量关掉转义。示例:`content_html|safe`。 + +10. `int(value)`:将值转换为`int`类型。 + +11. `float(value)`:将值转换为`float`类型。 + +12. `lower(value)`:将字符串转换为小写。 + +13. `upper(value)`:将字符串转换为小写。 + +14. `replace(value,old,new)`: 替换将`old`替换为`new`的字符串。 + +15. `truncate(value,length=255,killwords=False)`:截取`length`长度的字符串。 + +16. `striptags(value)`:删除字符串中所有的HTML标签,如果出现多个空格,将替换成一个空格。 + +17. `trim`:截取字符串前面和后面的空白字符。 + +18. `string(value)`:将变量转换成字符串。 + +19. `wordcount(s)`:计算一个长字符串中单词的个数。 + +## 4. 控制语句 + +所有的控制语句都是放在`{% ... %}`中,并且有一个语句`{% endxxx %}`来进行结束,`Jinja`中常用的控制语句有`if/for..in..`,现对他们进行讲解: + +1. `if`:if语句和`python`中的类似,可以使用`>,<,<=,>=,==,!=`来进行判断,也可以通过`and,or,not,()`来进行逻辑合并操作,以下看例子: + +```jinja2 +{% if kenny.sick %} + Kenny is sick. +{% elif kenny.dead %} + You killed Kenny! You bastard!!! +{% else %} + Kenny looks okay --- so far +{% endif %} +``` + +2. `for...in...`:`for`循环可以遍历任何一个序列包括列表、字典、元组。并且可以进行反向遍历,以下将用几个例子进行解释: + + - 普通的遍历: + +```jinja2 +
    +{% for user in users %} +
  • {{ user.username|e }}
  • +{% endfor %} +
+``` + + - 遍历字典: + +```jinja2 +
+{% for key, value in my_dict.iteritems() %} +
{{ key|e }}
+
{{ value|e }}
+{% endfor %} +
+``` + + - 如果序列中没有值的时候,进入`else`: + +```jinja2 +
    +{% for user in users %} +
  • {{ user.username|e }}
  • +{% else %} +
  • no users found
  • +{% endfor %} +
+``` + +并且`Jinja`中的`for`循环还包含以下变量,可以用来获取当前的遍历状态: + +| 变量 | 描述 | +| :---------- | :---------------------------------- | +| loop.index | 当前迭代的索引(从1开始) | +| loop.index0 | 当前迭代的索引(从0开始) | +| loop.first | 是否是第一次迭代,返回True或False | +| loop.last | 是否是最后一次迭代,返回True或False | +| loop.length | 序列的长度 | + +另外,**不可以**使用`continue`和`break`表达式来控制循环的执行。 + +## 5. 测试器 + +测试器主要用来判断一个值是否满足某种类型,并且这种类型一般通过普通的`if`判断是有很大的挑战的。语法是:`if...is...`,先来简单的看个例子: + +```jinja2 +{% if variable is escaped%} + value of variable: {{ escaped }} +{% else %} + variable is not escaped +{% endif %} +``` + +以上判断`variable`这个变量是否已经被转义了,`Jinja`中内置了许多的测试器,看以下列表: + +| 测试器 | 说明 | +| :----------------- | :----------------- | +| `callable(object)` | 是否可调用 | +| `defined(object)` | 是否已经被定义了。 | +| `escaped(object)` | 是否已经被转义了。 | +| `upper(object)` | 是否全是大写。 | +| `lower(object)` | 是否全是小写。 | +| `string(object)` | 是否是一个字符串。 | +| `sequence(object)` | 是否是一个序列。 | +| `number(object)` | 是否是一个数字。 | +| `odd(object)` | 是否是奇数。 | +| `even(object)` | 是否是偶数。 | + +## 6. 宏和import语句 + +### 6.1 宏: + +模板中的宏跟python中的函数类似,可以传递参数,但是不能有返回值,可以将一些经常用到的代码片段放到宏中,然后把一些不固定的值抽取出来当成一个变量,以下将用一个例子来进行解释: + +```jinja2 +{% macro input(name, value='', type='text') %} + +{% endmacro %} +``` + +以上例子可以抽取出了一个input标签,指定了一些默认参数。那么我们以后创建`input`标签的时候,可以通过他快速的创建: + +```jinja2 +

{{ input('username') }}

+

{{ input('password', type='password') }}

+``` + +### 6.2 import语句: + +在真实的开发中,会将一些常用的宏单独放在一个文件中,在需要使用的时候,再从这个文件中进行导入。`import`语句的用法跟`python`中的`import`类似,可以直接`import...as...`,也可以`from...import...`或者`from...import...as...`,假设现在有一个文件,叫做`forms.html`,里面有两个宏分别为`input`和`textarea`,如下: + +```jinja2 +{% macro input(name, value='', type='text') %} + +{% endmacro %} + +{% macro textarea(name, value='', rows=10, cols=40) %} + +{% endmacro %} +``` + +### 6.3 导入宏的例子: + +1. `import...as...`形式: + +```jinja2 +{% import 'forms.html' as forms %} +
+
Username
+
{{ forms.input('username') }}
+
Password
+
{{ forms.input('password', type='password') }}
+
+

{{ forms.textarea('comment') }}

+``` + +2. `from...import...as.../from...import...`形式: + +```jinja2 +{% from 'forms.html' import input as input_field, textarea %} +
+
Username
+
{{ input_field('username') }}
+
Password
+
{{ input_field('password', type='password') }}
+
+

{{ textarea('comment') }}

+``` + +另外需要注意的是,导入模板并不会把当前上下文中的变量添加到被导入的模板中,如果你想要导入一个需要访问当前上下文变量的宏,有两种可能的方法: + +- 显式地传入请求或请求对象的属性作为宏的参数。 + +- 与上下文一起(with context)导入宏。 + + 与上下文中一起(with context)导入的方式如下: + +```jinja2 + {% from '_helpers.html' import my_macro with context %} +``` + +## 7. include和set语句 + +### 7.1 include语句: + +`include`语句可以把一个模板引入到另外一个模板中,类似于把一个模板的代码copy到另外一个模板的指定位置,看以下例子: + +```jinja2 +{% include 'header.html' %} + 主体内容 +{% include 'footer.html' %} +``` + +### 7.2 赋值(set)语句: + +有时候我们想在在模板中添加变量,这时候赋值语句(set)就派上用场了,先看以下例子: + +```jinja2 +{% set name='zhiliao' %} +``` + +那么以后就可以使用`name`来代替`zhiliao`这个值了,同时,也可以给他赋值为列表和元组: + +```jinja2 +{% set navigation = [('index.html', 'Index'), ('about.html', 'About')] %} +``` + +赋值语句创建的变量在其之后都是有效的,如果不想让一个变量污染全局环境,可以使用`with`语句来创建一个内部的作用域,将`set`语句放在其中,这样创建的变量只在`with`代码块中才有效,看以下示例: + +```jinja2 +{% with %} + {% set foo = 42 %} + {{ foo }} foo is 42 here +{% endwith %} +``` + +也可以在`with`的后面直接添加变量,比如以上的写法可以修改成这样: + +```jinja2 +{% with foo = 42 %} + {{ foo }} +{% endwith %} +``` + +这两种方式都是等价的,一旦超出`with`代码块,就不能再使用`foo`这个变量了。 + +## 8. 模版继承 + +`Flask`中的模板可以继承,通过继承可以把模板中许多重复出现的元素抽取出来,放在父模板中,并且父模板通过定义`block`给子模板开一个口,子模板根据需要,再实现这个`block`,假设现在有一个`base.html`这个父模板,代码如下: + +```html + + + + + {% block title %}{% endblock %} + {% block head %}{% endblock %} + + +
{% block body %}{% endblock %}
+ + + +``` + +以上父模板中,抽取了所有模板都需要用到的元素`html`、`body`等,并且对于一些所有模板都要用到的样式文件`style.css`也进行了抽取,同时对于一些子模板需要重写的地方,比如`title`、`head`、`body`都定义成了`block`,然后子模板可以根据自己的需要,再具体的实现。以下再来看子模板的代码: + +```jinja2 +{% extends "base.html" %} +{% block title %}首页{% endblock %} +{% block head %} + {{ super() }} + +{% endblock %} +{% block content %} +

这里是首页

+

+ 首页的内容 +

+{% endblock %} +``` + +首先第一行就定义了子模板继承的父模板,并且可以看到子模板实现了`title`这个`block`,并填充了自己的内容,再看`head`这个`block`,里面调用了`super()`这个函数,这个函数的目的是执行父模板中的代码,把父模板中的内容添加到子模板中,如果没有这一句,则父模板中处在`head`这个`block`中的代码将会被子模板中的代码给覆盖掉。 + +另外,模板中不能出现重名的`block`,如果一个地方需要用到另外一个`block`中的内容,可以使用`self.blockname`的方式进行引用,比如以下示例: + +```html + + {% block title %} + 这是标题 + {% endblock %} + +

{{ self.title() }}

+``` + +以上示例中`h1`标签重用了`title`这个`block`中的内容,子模板实现了`title`这个`block`,`h1`标签也能拥有这个值。 + +另外,在子模板中,所有的文本标签和代码都要添加到从父模板中继承的`block`中。否则,这些文本和标签将不会被渲染。 + +## 9. 转义 + +转义的概念是,在模板渲染字符串的时候,字符串有可能包括一些非常危险的字符比如`<`、`>`等,这些字符会破坏掉原来`HTML`标签的结构,更严重的可能会发生`XSS`跨域脚本攻击,因此如果碰到`<`、`>`这些字符的时候,应该转义成`HTML`能正确表示这些字符的写法,比如`>`在`HTML`中应该用`<`来表示等。 + +但是`Flask`中默认没有开启全局自动转义,针对那些以`.html`、`.htm`、`.xml`和`.xhtml`结尾的文件,如果采用`render_template`函数进行渲染的,则会开启自动转义。并且当用`render_template_string`函数的时候,会将所有的字符串进行转义后再渲染。而对于`Jinja2`默认没有开启全局自动转义,作者有自己的原因: + +1. 渲染到模板中的字符串并不是所有都是危险的,大部分还是没有问题的,如果开启自动转义,那么将会带来大量的不必要的开销。 +2. `Jinja2`很难获取当前的字符串是否已经被转义过了,因此如果开启自动转义,将对一些已经被转义过的字符串发生二次转义,在渲染后会破坏原来的字符串。 + +在没有开启自动转义的模式下(比如以`.conf`结尾的文件),对于一些不信任的字符串,可以通过`{{ content_html|e }}`或者是`{{ content_html|escape }}`的方式进行转义。在开启了自动转义的模式下,如果想关闭自动转义,可以通过`{{ content_html|safe }}`的方式关闭自动转义。而`{%autoescape true/false%}...{%endautoescape%}`可以将一段代码块放在中间,来关闭或开启自动转义,例如以下代码关闭了自动转义: + +```jinja2 +{% autoescape false %} +

autoescaping is disabled here +

{{ will_not_be_escaped }} +{% endautoescape %} +``` + +## 10. 数据类型和运算符 + +### 10.1 数据类型: + +`Jinja`支持许多数据类型,包括:**字符串、整型、浮点型、列表、元组、字典、True/False**。 + +### 10.2 运算符: + +- `+`号运算符:可以完成数字相加,字符串相加,列表相加。但是并不推荐使用`+`运算符来操作字符串,字符串相加应该使用`~`运算符。 +- `-`号运算符:只能针对两个数字相减。 +- `/`号运算符:对两个数进行相除。 +- `%`号运算符:取余运算。 +- `*`号运算符:乘号运算符,并且可以对字符进行相乘。 +- `**`号运算符:次幂运算符,比如2**3=8。 +- `in`操作符:跟python中的`in`一样使用,比如`{{1 in [1,2,3]}}`返回`true`。 +- `~`号运算符:拼接多个字符串,比如`{{"Hello" ~ "World"}}`将返回`HelloWorld`。 + +## 11. 静态文件的配置 + +`Web`应用中会出现大量的静态文件来使得网页更加生动美观。类似于`CSS`样式文件、`JavaScript`脚本文件、图片文件、字体文件等静态资源。在`Jinja`中加载静态文件非常简单,只需要通过`url_for`全局函数就可以实现,看以下代码: + +```html + +``` + +`url_for`函数默认会在项目根目录下的`static`文件夹中寻找`about.css`文件,如果找到了,会生成一个相对于项目根目录下的`/static/about.css`路径。当然我们也可以把静态文件不放在`static`文件夹中,此时就需要具体指定了,看以下代码: + +```python +app = Flask(__name__,static_folder='C:\static') +``` + +那么访问静态文件的时候,将会到`/static`这个文件夹下寻找。 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/04.Flask/03.视图高级.md b/04.Flask/03.视图高级.md new file mode 100644 index 0000000..7aff9b6 --- /dev/null +++ b/04.Flask/03.视图高级.md @@ -0,0 +1,182 @@ +# 视图高级 + +## 1. 类视图 + +之前我们接触的视图都是函数,所以一般简称视图函数。其实视图也可以基于类来实现,类视图的好处是支持继承,但是类视图不能跟函数视图一样,写完类视图还需要通过`app.add_url_rule(url_rule,view_func)`来进行注册。以下将对两种类视图进行讲解: + +### 1.1 标准类视图: + +标准类视图是继承自`flask.views.View`,并且在子类中必须实现`dispatch_request`方法,这个方法类似于视图函数,也要返回一个基于`Response`或者其子类的对象。以下将用一个例子进行讲解: + +```python +from flask.views import View +class PersonalView(View): + def dispatch_request(self): + return "知了课堂" +# 类视图通过add_url_rule方法和url做映射 +app.add_url_rule('/users/',view_func=PersonalView.as_view('personalview')) +``` + +### 1.2 基于调度方法的视图: + +`Flask`还为我们提供了另外一种类视图`flask.views.MethodView`,对每个HTTP方法执行不同的函数(映射到对应方法的小写的同名方法上),以下将用一个例子来进行讲解: + +```python +class LoginView(views.MethodView): + # 当客户端通过get方法进行访问的时候执行的函数 + def get(self): + return render_template("login.html") + + # 当客户端通过post方法进行访问的时候执行的函数 + def post(self): + email = request.form.get("email") + password = request.form.get("password") + if email == 'xx@qq.com' and password == '111111': + return "登录成功!" + else: + return "用户名或密码错误!" + +## 通过add_url_rule添加类视图和url的映射,并且在as_view方法中指定该url的名称,方便url_for函数调用 +app.add_url_rule('/myuser/',view_func=LoginView.as_view('loginview')) +``` + +如果用类视图,我们怎么使用装饰器呢?比如有时候需要做权限验证的时候,比如看以下例子: + +```python +from flask import session +def login_required(func): + def wrapper(*args,**kwargs): + if not session.get("user_id"): + return 'auth failure' + return func(*args,**kwargs) + return wrapper +``` + +装饰器写完后,可以在类视图中定义一个属性叫做`decorators`,然后存储装饰器。以后每次调用这个类视图的时候,就会执行这个装饰器。示例代码如下: + +```python +class UserView(views.MethodView): + decorators = [user_required] + ... +``` + +## 2. 蓝图和子域名 + +### 2.1 蓝图: + +之前我们写的`url`和视图函数都是处在同一个文件,如果项目比较大的话,这显然不是一个合理的结构,而蓝图可以优雅的帮我们实现这种需求。以下看一个使用蓝图的文件的例子: + +``` +from flask import Blueprint +bp = Blueprint('user',__name__,url_prefix='/user/') + +@bp.route('/') +def index(): + return "用户首页" + +@bp.route('profile/') +def profile(): + return "个人简介" +``` + +然后我们在主程序中,通过`app.register_blueprint()`方法将这个蓝图注册进url映射中,看下主`app`的实现: + +``` +from flask import Flask +import user + +app = Flask(__name__) +app.register_blueprint(user.bp) + +if __name__ == '__main__': + app.run(host='0.0.0.0',port=9000) +``` + +以后访问`/user/`,`/user/profile/`,都是执行的`user.py`文件中的视图函数,这样就实现了项目的模块化。 + +以上是对蓝图的一个简单介绍,但是使用蓝图还有几个需要注意的地方,就是在蓝图如何寻找静态文件、模板文件,`url_for`函数如何反转`url`,以下分别进行解释: + +#### 2.1.1 寻找静态文件: + +默认不设置任何静态文件路径,`Jinja2`会在项目的`static`文件夹中寻找静态文件。也可以设置其他的路径,在初始化蓝图的时候,`Blueprint`这个构造函数,有一个参数`static_folder`可以指定静态文件的路径,如: + +```python +bp = Blueprint('admin',__name__,url_prefix='/admin',static_folder='static') +``` + +`static_folder`可以是相对路径(相对蓝图文件所在的目录),也可以是绝对路径。在配置完蓝图后,还有一个需要注意的地方是如何在模板中引用静态文件。在模板中引用蓝图,应该要使用`蓝图名+.+static`来引用,如下所示: + +```python + +``` + +#### 2.1.2 寻找模板文件: + +跟静态文件一样,默认不设置任何模板文件的路径,将会在项目的`templates`中寻找模板文件。也可以设置其他的路径,在构造函数`Blueprint`中有一个`template_folder`参数可以设置模板的路径,如下所示: + +```python +bp = Blueprint('admin',__name__,url_prefix='/admin',template_folder='templates') +``` + +模板文件和静态文件有点区别,以上代码写完以后,如果你渲染一个模板`return render_template('admin.html')`,`Flask`默认会去项目根目录下的`templates`文件夹中查找`admin.html`文件,如果找到了就直接返回,如果没有找到,才会去蓝图文件所在的目录下的`templates`文件夹中寻找。 + +#### 2.1.3 url_for生成`url`: + +用`url_for`生成蓝图的`url`,使用的格式是:`蓝图名称+.+视图函数名称`。比如要获取`admin`这个蓝图下的`index`视图函数的`url`,应该采用以下方式: + +```python +url_for('admin.index') +``` + +其中这个**蓝图名称**是在创建蓝图的时候,传入的第一个参数。`bp = Blueprint('admin',__name__,url_prefix='/admin',template_folder='templates')` + +### 2.2 子域名: + +子域名在许多网站中都用到了,比如一个网站叫做`xxx.com`,那么我们可以定义一个子域名`cms.xxx.com`来作为`cms`管理系统的网址,子域名的实现一般也是通过蓝图来实现,在之前章节中,我们创建蓝图的时候添加了一个`url_prefix=/user`作为url前缀,那样我们就可以通过`/user/`来访问`user`下的url。但使用子域名则不需要。另外,还需要配置`SERVER_NAME`,比如`app.config[SERVER_NAME]='example.com:9000'`。并且在注册蓝图的时候,还需要添加一个`subdomain`的参数,这个参数就是子域名的名称,先来看一下蓝图的实现(admin.py): + +```python +from flask import Blueprint +bp = Blueprint('admin',__name__,subdomain='admin') + +@bp.route('/') +def admin(): + return 'Admin Page' +``` + +这个没有多大区别,接下来看主`app`的实现: + +```python +from flask import Flask +import admin + +# 配置`SERVER_NAME` +app.config['SERVER_NAME'] = 'example.com:8000' +# 注册蓝图,指定了subdomain +app.register_blueprint(admin.bp) + +if __name__ == '__main__': + app.run(host='0.0.0.0',port=8000,debug=True) +``` + +写完以上两个文件后,还是不能正常的访问`admin.example.com:8000`这个子域名,因为我们没有在`host`文件中添加域名解析,你可以在最后添加一行`127.0.0.1 admin.example.com`,就可以访问到了。另外,子域名不能在`127.0.0.1`上出现,也不能在`localhost`上出现。 + + + + + + + + + + + + + + + + + + + + + diff --git a/04.Flask/04.SQLAlchemy.md b/04.Flask/04.SQLAlchemy.md new file mode 100644 index 0000000..88a8484 --- /dev/null +++ b/04.Flask/04.SQLAlchemy.md @@ -0,0 +1,919 @@ +# SQLAlchemy + +## 1. MySQL数据库 + +在网站开发中,数据库是网站的重要组成部分。只有提供数据库,数据才能够动态的展示,而不是在网页中显示一个静态的页面。数据库有很多,比如有`SQL Server`、`Oracle`、`PostgreSQL`以及`MySQL`等等。`MySQL`由于价格实惠、简单易用、不受平台限制、灵活度高等特性,目前已经取得了绝大多数的市场份额。因此我们在`Flask`中,也是使用`MySQL`来作为数据存储。 + +### 1.1 MySQL数据库安装 + +1. 在`MySQL`的官网下载`MySQL`数据库安装文件:`https://dev.mysql.com/downloads/mysql/`。 +2. 然后双击安装,如果出现以下错误,则到`http://www.microsoft.com/en-us/download/details.aspx?id=17113`下载`.net framework`。 + ![QQ截图20171026122939.png](04.SQLAlchemy/rHS8Ny8FHDrwhvbUWv4XAC.png) +3. 在安装过程中,如果提示没有`Microsoft C++ 2013`,那么就到以下网址下载安装即可:`http://download.microsoft.com/download/9/0/5/905DBD86-D1B8-4D4B-8A50-CB0E922017B9/vcredist_x64.exe`。 + ![QQ截图20171026144632.png](04.SQLAlchemy/XYQtENVVzPvVVARq7Qt74D.png) +4. 接下来就是做好用户名和密码的配置即可。 + +### 1.2 navicat数据库操作软件 + +安装完`MySQL`数据库以后,就可以使用`MySQL`提供的终端客户端软件来操作数据库。如下: +![mysql客户端.png](04.SQLAlchemy/p2YQ6oveDpNYrYQsnejFyV.png) +这个软件所有的操作都是基于`sql`语言,对于想要熟练`sql`语言的同学来讲是非常合适的。但是对于在企业中可能不是一款好用的工具。在企业中我们推荐使用`mysql workbench`以及`navicat`这种图形化操作的软件。而`mysql workbench`是`mysql`官方提供的一个免费的软件,正因为是免费,所以在一些功能上不及`navicat`。`navicat for mysql`是一款收费的软件。官网地址如下:`https://www.navicat.com.cn/products`。使用的截图如下: +![navicat.png](04.SQLAlchemy/eyw6PKK6tH8uAXPtd9AwiD.png) + +### 1.3 MySQL驱动程序安装 + +我们使用`Django`来操作`MySQL`,实际上底层还是通过`Python`来操作的。因此我们想要用`Flask`来操作`MySQL`,首先还是需要安装一个驱动程序。在`Python3`中,驱动程序有多种选择。比如有`pymysql`以及`mysqlclient`等。这里我们就使用`mysqlclient`来操作。`mysqlclient`安装非常简单。只需要通过`pip install mysqlclient`即可安装。 + +常见`MySQL`驱动介绍: + +1. `MySQL-python`:也就是`MySQLdb`。是对`C`语言操作`MySQL`数据库的一个简单封装。遵循了`Python DB API v2`。但是只支持`Python2`,目前还不支持`Python3`。 +2. `mysqlclient`:是`MySQL-python`的另外一个分支。支持`Python3`并且修复了一些`bug`。 +3. `pymysql`:纯`Python`实现的一个驱动。因为是纯`Python`编写的,因此执行效率不如`MySQL-python`。并且也因为是纯`Python`编写的,因此可以和`Python`代码无缝衔接。 +4. `MySQL Connector/Python`:`MySQL`官方推出的使用纯`Python`连接`MySQL`的驱动。因为是纯`Python`开发的。效率不高。 + +## 2. SQLAlchemy介绍 + +### 2.1 安装: + +`SQLAlchemy`是一个数据库的`ORM`框架,让我们操作数据库的时候不要再用`SQL`语句了,跟直接操作模型一样。安装命令为:`pip install SQLAlchemy`。 + +### 2.2 通过`SQLAlchemy`连接数据库: + +首先来看一段代码: + +```python +from sqlalchemy import create_engine + +# 数据库的配置变量 +HOSTNAME = '127.0.0.1' +PORT = '3306' +DATABASE = 'xt_flask' +USERNAME = 'root' +PASSWORD = 'root' +DB_URI = 'mysql+pymysql://{}:{}@{}:{}/{}'.format(USERNAME,PASSWORD,HOSTNAME,PORT,DATABASE) + +# 创建数据库引擎 +engine = create_engine(DB_URI) + +#创建连接 +with engine.connect() as con: + rs = con.execute('SELECT 1') + print rs.fetchone() +``` + +首先从`sqlalchemy`中导入`create_engine`,用这个函数来创建引擎,然后用`engine.connect()`来连接数据库。其中一个比较重要的一点是,通过`create_engine`函数的时候,需要传递一个满足某种格式的字符串,对这个字符串的格式来进行解释: + +``` +dialect+driver://username:password@host:port/database?charset=utf8 +``` + +`dialect`是数据库的实现,比如`MySQL`、`PostgreSQL`、`SQLite`,并且转换成小写。`driver`是`Python`对应的驱动,如果不指定,会选择默认的驱动,比如MySQL的默认驱动是`MySQLdb`。`username`是连接数据库的用户名,`password`是连接数据库的密码,`host`是连接数据库的域名,`port`是数据库监听的端口号,`database`是连接哪个数据库的名字。 + +如果以上输出了`1`,说明`SQLAlchemy`能成功连接到数据库。 + +### 2.3 用SQLAlchemy执行原生SQL: + +我们将上一个例子中的数据库配置选项单独放在一个`constants.py`的文件中,看以下例子: + +```python +from sqlalchemy import create_engine +from constants import DB_URI + +#连接数据库 +engine = create_engine(DB_URI,echo=True) + +# 使用with语句连接数据库,如果发生异常会被捕获 +with engine.connect() as con: + # 先删除users表 + con.execute('drop table if exists authors') + # 创建一个users表,有自增长的id和name + con.execute('create table authors(id int primary key auto_increment,'name varchar(25))') + # 插入两条数据到表中 + con.execute('insert into persons(name) values("abc")') + con.execute('insert into persons(name) values("xiaotuo")') + # 执行查询操作 + results = con.execute('select * from persons') + # 从查找的结果中遍历 + for result in results: + print(result) +``` + +## 3. SQLAlchemy基本使用 + +### 3.1 使用SQLAlchemy: + +#### 3.1.1 创建`ORM`模型: + +要使用`ORM`来操作数据库,首先需要创建一个类来与对应的表进行映射。现在以`User表`来做为例子,它有`自增长的id`、`name`、`fullname`、`password`这些字段,那么对应的类为: + +```python +from sqlalchemy import Column,Integer,String +from constants import DB_URI +from sqlalchemy import create_engine +from sqlalchemy.ext.declarative import declarative_base + +engine = create_engine(DB_URI,echo=True) + +# 所有的类都要继承自`declarative_base`这个函数生成的基类 +Base = declarative_base(engine) +class User(Base): + # 定义表名为users + __tablename__ = 'users' + + # 将id设置为主键,并且默认是自增长的 + id = Column(Integer,primary_key=True) + # name字段,字符类型,最大的长度是50个字符 + name = Column(String(50)) + fullname = Column(String(50)) + password = Column(String(100)) + + # 让打印出来的数据更好看,可选的 + def __repr__(self): + return "" % (self.id,self.name,self.fullname,self.password) +``` + +#### 3.1.2 映射到数据库中: + +`SQLAlchemy`会自动的设置第一个`Integer`的主键并且没有被标记为外键的字段添加自增长的属性。因此以上例子中`id`自动的变成自增长的。以上创建完和表映射的类后,还没有真正的映射到数据库当中,执行以下代码将类映射到数据库中: + +```python +Base.metadata.create_all() +``` + +#### 3.1.3 添加数据到表中: + +在创建完数据表,并且做完和数据库的映射后,接下来让我们添加数据进去: + +```python +ed_user = User(name='ed',fullname='Ed Jones',password='edspassword') +# 打印名字 +print ed_user.name +> ed +# 打印密码 +print ed_user.password +> edspassword +# 打印id +print(ed_user.id) +> None +``` + +可以看到,name和password都能正常的打印,唯独`id`为`None`,这是因为`id`是一个自增长的主键,还未插入到数据库中,`id`是不存在的。接下来让我们把创建的数据插入到数据库中。和数据库打交道的,是一个叫做`Session`的对象: + +```python +from sqlalchemy.orm import sessionmaker +Session = sessionmaker(bind=engine) +# 或者 +# Session = sessionmaker() +# Session.configure(bind=engine) +session = Session() +ed_user = User(name='ed',fullname='Ed Jones',password='edspassword') +session.add(ed_user) +``` + +现在只是把数据添加到`session`中,但是并没有真正的把数据存储到数据库中。如果需要把数据存储到数据库中,还要做一次`commit`操作: + +```python +session.commit() +# 打印ed_user的id +print ed_user.id +> 1 +``` + +#### 3.1.4 回滚: + +这时候,`ed_user`就已经有id。 说明已经插入到数据库中了。有人肯定有疑问了,为什么添加到`session`中后还要做一次`commit`操作呢,这是因为,在`SQLAlchemy`的`ORM`实现中,在做`commit`操作之前,所有的操作都是在事务中进行的,因此如果你要将事务中的操作真正的映射到数据库中,还需要做`commit`操作。既然用到了事务,这里就并不能避免的提到一个回滚操作了,那么看以下代码展示了如何使用回滚(接着以上示例代码): + +```python +# 修改ed_user的用户名 +ed_user.name = 'Edwardo' +# 创建一个新的用户 +fake_user = User(name='fakeuser',fullname='Invalid',password='12345') +# 将新创建的fake_user添加到session中 +session.add(fake_user) +# 判断`fake_user`是否在`session`中存在 +print fake_user in session +> True +# 从数据库中查找name=Edwardo的用户 +tmp_user = session.query(User).filter_by(name='Edwardo') +# 打印tmp_user的name +print tmp_user +# 打印出查找到的tmp_user对象,注意这个对象的name属性已经在事务中被修改为Edwardo了。 +> +# 刚刚所有的操作都是在事务中进行的,现在来做回滚操作 +session.rollback() +# 再打印tmp_user +print tmp_user +> +# 再看fake_user是否还在session中 +print fake_user in session +> False +``` + +#### 3.1.5 查找数据: + +接下来看下如何进行查找操作,查找操作是通过`session.query()`方法实现的,这个方法会返回一个`Query`对象,`Query`对象相当于一个数组,装载了查找出来的数据,并且可以进行迭代。具体里面装的什么数据,就要看向`session.query()`方法传的什么参数了,如果只是传一个`ORM`的类名作为参数,那么提取出来的数据就是都是这个类的实例,比如: + +```python +for instance in session.query(User).order_by(User.id): + print instance +# 输出所有的user实例 +> +> +``` + +如果传递了两个及其两个以上的对象,或者是传递的是`ORM`类的属性,那么查找出来的就是元组,例如: + +```python +for instance in session.query(User.name): + print instance +# 输出所有的查找结果 +> ('ed',) +> ('be',) +``` + +以及: + +```python +for instance in session.query(User.name,User.fullname): + print instance +# 输出所有的查找结果 +> ('ed', 'Ed Json') +> ('be', 'Be Engine') +``` + +或者是: + +```python +for instance in session.query(User,User.name).all(): + print instance +# 输出所有的查找结果 +> (, 'Ed Json') +> (, 'Be Engine') +``` + +另外,还可以对查找的结果(`Query`)做切片操作: + +```python +for instance in session.query(User).order_by(User.id)[1:3] + instance +``` + +如果想对结果进行过滤,可以使用`filter_by`和`filter`两个方法,这两个方法都是用来做过滤的,区别在于,`filter_by`是传入关键字参数,`filter`是传入条件判断,并且`filter`能够传入的条件更多更灵活,请看以下例子: + +```python +# 第一种:使用filter_by过滤: +for name in session.query(User.name).filter_by(fullname='Ed Jones'): + print name +# 输出结果: +> ('ed',) + +# 第二种:使用filter过滤: +for name in session.query(User.name).filter(User.fullname=='Ed Jones'): + print name +# 输出结果: +> ('ed',) +``` + +### 3.2 Column常用参数: + +- `default`:默认值。 +- `nullable`:是否可空。 +- `primary_key`:是否为主键。 +- `unique`:是否唯一。 +- `autoincrement`:是否自动增长。 +- `onupdate`:更新的时候执行的函数。 +- `name`:该属性在数据库中的字段映射。 + +### 3.3 sqlalchemy常用数据类型: + +- `Integer`:整形。 +- `Float`:浮点类型。 +- `Boolean`:传递`True/False`进去。 +- `DECIMAL`:定点类型。 +- `enum`:枚举类型。 +- `Date`:传递`datetime.date()`进去。 +- `DateTime`:传递`datetime.datetime()`进去。 +- `Time`:传递`datetime.time()`进去。 +- `String`:字符类型,使用时需要指定长度,区别于`Text`类型。 +- `Text`:文本类型。 +- `LONGTEXT`:长文本类型。 + +## 4. 查找操作 + +### 4.1 query可用参数: + +1. 模型对象。指定查找这个模型中所有的对象。 +2. 模型中的属性。可以指定只查找某个模型的其中几个属性。 +3. 聚合函数。 + - `func.count`:统计行的数量。 + - `func.avg`:求平均值。 + - `func.max`:求最大值。 + - `func.min`:求最小值。 + - `func.sum`:求和。 + +### 4.2 过滤条件: + +过滤是数据提取的一个很重要的功能,以下对一些常用的过滤条件进行解释,并且这些过滤条件都是只能通过`filter`方法实现的: + +1. `equals`: + +```python +query.filter(User.name == 'ed') +``` + +2. `not equals`: + +```python +query.filter(User.name != 'ed') +``` + +3. `like`: + +```python +query.filter(User.name.like('%ed%')) +``` + +4. `in`: + +```python +query.filter(User.name.in_(['ed','wendy','jack'])) +# 同时,in也可以作用于一个Query +query.filter(User.name.in_(session.query(User.name).filter(User.name.like('%ed%')))) +``` + +5. `not in`: + +```python +query.filter(~User.name.in_(['ed','wendy','jack'])) +``` + +6. `is null`: + +```python +query.filter(User.name==None) +# 或者是 +query.filter(User.name.is_(None)) +``` + +7. `is not null`: + +```python +query.filter(User.name != None) +# 或者是 +query.filter(User.name.isnot(None)) +``` + +8. `and`: + +```python +from sqlalchemy import and_ +query.filter(and_(User.name=='ed',User.fullname=='Ed Jones')) +# 或者是传递多个参数 +query.filter(User.name=='ed',User.fullname=='Ed Jones') +# 或者是通过多次filter操作 +query.filter(User.name=='ed').filter(User.fullname=='Ed Jones') +``` + +9. `or`: + +```python +from sqlalchemy import or_ query.filter(or_(User.name=='ed',User.name=='wendy')) +``` + +### 4.3 查找方法: + +介绍完过滤条件后,有一些经常用到的查找数据的方法也需要解释一下: + +1. `all()`:返回一个`Python`列表(`list`): + +```python +query = session.query(User).filter(User.name.like('%ed%').order_by(User.id) +# 输出query的类型 +print type(query) +> +# 调用all方法 +query = query.all() +# 输出query的类型 +print type(query) +> +``` + +2. `first()`:返回`Query`中的第一个值: + +```python +user = session.query(User).first() +print user +> +``` + +3. `one()`:查找所有行作为一个结果集,如果结果集中只有一条数据,则会把这条数据提取出来,如果这个结果集少于或者多于一条数据,则会抛出异常。总结一句话:有且只有一条数据的时候才会正常的返回,否则抛出异常: + +```python +# 多于一条数据 +user = query.one() +> Traceback (most recent call last): +> ... +> MultipleResultsFound: Multiple rows were found for one() +# 少于一条数据 +user = query.filter(User.id == 99).one() +> Traceback (most recent call last): +> ... +> NoResultFound: No row was found for one() +# 只有一条数据 +> query(User).filter_by(name='ed').one() +``` + +4. `one_or_none()`:跟`one()`方法类似,但是在结果集中没有数据的时候也不会抛出异常。 + +5. `scalar()`:底层调用`one()`方法,并且如果`one()`方法没有抛出异常,会返回查询到的第一列的数据: + +```python +session.query(User.name,User.fullname).filter_by(name='ed').scalar() +``` + +### 4.4 文本SQL: + +`SQLAlchemy`还提供了使用**文本SQL**的方式来进行查询,这种方式更加的灵活。而文本SQL要装在一个`text()`方法中,看以下例子: + +```python +from sqlalchemy import text +for user in session.query(User).filter(text("id<244")).order_by(text("id")).all(): + print user.name +``` + +如果过滤条件比如上例中的244存储在变量中,这时候就可以通过传递参数的形式进行构造: + +```python +session.query(User).filter(text("id<:value and name=:name")).params(value=224,name='ed').order_by(User.id) +``` + +在文本SQL中的变量前面使用了`:`来区分,然后使用`params`方法,指定需要传入进去的参数。另外,使用`from_statement`方法可以把过滤的函数和条件函数都给去掉,使用纯文本的SQL: + +```python +sesseion.query(User).from_statement(text("select * from users where name=:name")).params(name='ed').all() +``` + +使用`from_statement`方法一定要注意,`from_statement`返回的是一个`text`里面的查询语句,一定要记得调用`all()`方法来获取所有的值。 + +### 4.5 计数(Count): + +`Query`对象有一个非常方便的方法来计算里面装了多少数据: + +```python +session.query(User).filter(User.name.like('%ed%')).count() +``` + +当然,有时候你想明确的计数,比如要统计`users`表中有多少个不同的姓名,那么简单粗暴的采用以上`count`是不行的,因为姓名有可能会重复,但是处于两条不同的数据上,如果在原生数据库中,可以使用`distinct`关键字,那么在`SQLAlchemy`中,可以通过`func.count()`方法来实现: + +```python +from sqlalchemy import func +session.query(func.count(User.name),User.name).group_by(User.name).all() +## 输出的结果 +> [(1, u'ed'), (1, u'fred'), (1, u'mary'), (1, u'wendy')] +``` + +另外,如果想实现`select count(*) from users`,可以通过以下方式来实现: + +```python +session.query(func.count(*)).select_from(User).scalar() +``` + +当然,如果指定了要查找的表的字段,可以省略`select_from()`方法: + +```python +session.query(func.count(User.id)).scalar() +``` + +## 5. 表关系: + +表之间的关系存在三种:一对一、一对多、多对多。而`SQLAlchemy`中的`ORM`也可以模拟这三种关系。因为一对一其实在`SQLAlchemy`中底层是通过一对多的方式模拟的,所以先来看下一对多的关系: + +### 5.1 外键: + +在Mysql中,外键可以让表之间的关系更加紧密。而SQLAlchemy同样也支持外键。通过ForeignKey类来实现,并且可以指定表的外键约束。相关示例代码如下: + +```python +class Article(Base): + __tablename__ = 'article' + id = Column(Integer,primary_key=True,autoincrement=True) + title = Column(String(50),nullable=False) + content = Column(Text,nullable=False) + uid = Column(Integer,ForeignKey('user.id')) + + def __repr__(self): + return "" % self.title + +class User(Base): + __tablename__ = 'user' + id = Column(Integer,primary_key=True,autoincrement=True) + username = Column(String(50),nullable=False) +``` + +外键约束有以下几项: + +1. `RESTRICT`:父表数据被删除,会阻止删除。默认就是这一项。 +2. `NO ACTION`:在MySQL中,同`RESTRICT`。 +3. `CASCADE`:级联删除。 +4. `SET NULL`:父表数据被删除,子表数据会设置为NULL。 + +### 5.2 一对多: + +拿之前的`User`表为例,假如现在要添加一个功能,要保存用户的邮箱帐号,并且邮箱帐号可以有多个,这时候就必须创建一个新的表,用来存储用户的邮箱,然后通过`user.id`来作为外键进行引用,先来看下邮箱表的实现: + +```python +from sqlalchemy import ForeignKey +from sqlalchemy.orm import relationship + +class Address(Base): + __tablename__ = 'address' + id = Column(Integer,primary_key=True) + email_address = Column(String,nullable=False) + # User表的外键,指定外键的时候,是使用的是数据库表的名称,而不是类名 + user_id = Column(Integer,ForeignKey('users.id')) + # 在ORM层面绑定两者之间的关系,第一个参数是绑定的表的类名, + # 第二个参数back_populates是通过User反向访问时的字段名称 + user = relationship('User',back_populates="addresses") + + def __repr__(self): + return "" % self.email_address + +# 重新修改User表,添加了addresses字段,引用了Address表的主键 +class User(Base): + __tablename__ = 'users' + id = Column(Integer,primary_key=True) + name = Column(String(50)) + fullname = Column(String(50)) + password = Column(String(100)) + # 在ORM层面绑定和`Address`表的关系 + addresses = relationship("Address",order_by=Address.id,back_populates="user") +``` + +其中,在`User`表中添加的`addresses`字段,可以通过`User.addresses`来访问和这个user相关的所有address。在`Address`表中的`user`字段,可以通过`Address.user`来访问这个user。达到了双向绑定。表关系已经建立好以后,接下来就应该对其进行操作,先看以下代码: + +```python +jack = User(name='jack',fullname='Jack Bean',password='gjffdd') +jack.addresses = [Address(email_address='jack@google.com'), + Address(email_address='j25@yahoo.com')] +session.add(jack) +session.commit() +``` + +首先,创建一个用户,然后对这个`jack`用户添加两个邮箱,最后再提交到数据库当中,可以看到这里操作`Address`并没有直接进行保存,而是先添加到用户里面,再保存。 + +### 5.3 一对一: + +一对一其实就是一对多的特殊情况,从以上的一对多例子中不难发现,一对应的是`User`表,而多对应的是`Address`,也就是说一个`User`对象有多个`Address`。因此要将一对多转换成一对一,只要设置一个`User`对象对应一个`Address`对象即可,看以下示例: + +```python +class User(Base): + __tablename__ = 'users' + id = Column(Integer,primary_key=True) + name = Column(String(50)) + fullname = Column(String(50)) + password = Column(String(100)) + # 设置uselist关键字参数为False + addresses = relationship("Address",back_populates='addresses',uselist=False) +class Address(Base): + __tablename__ = 'addresses' + id = Column(Integer,primary_key=True) + email_address = Column(String(50)) + user_id = Column(Integer,ForeignKey('users.id') + user = relationship('Address',back_populates='user') +``` + +从以上例子可以看到,只要在`User`表中的`addresses`字段上添加`uselist=False`就可以达到一对一的效果。设置了一对一的效果后,就不能添加多个邮箱到`user.addresses`字段了,只能添加一个: + +```python +user.addresses = Address(email_address='ed@google.com') +``` + +### 5.4 多对多: + +多对多需要一个中间表来作为连接,同理在`sqlalchemy`中的`orm`也需要一个中间表。假如现在有一个`Teacher`和一个`Classes`表,即老师和班级,一个老师可以教多个班级,一个班级有多个老师,是一种典型的多对多的关系,那么通过`sqlalchemy`的`ORM`的实现方式如下: + +```python +association_table = Table('teacher_classes',Base.metadata, + Column('teacher_id',Integer,ForeignKey('teacher.id')), + Column('classes_id',Integer,ForeignKey('classes.id')) +) + +class Teacher(Base): + __tablename__ = 'teacher' + id = Column(Integer,primary_key=True) + tno = Column(String(10)) + name = Column(String(50)) + age = Column(Integer) + classes = relationship('Classes',secondary=association_table,back_populates='teachers') + +class Classes(Base): + __tablename__ = 'classes' + id = Column(Integer,primary_key=True) + cno = Column(String(10)) + name = Column(String(50)) + teachers = relationship('Teacher',secondary=association_table,back_populates='classes') +``` + +要创建一个多对多的关系表,首先需要一个中间表,通过`Table`来创建一个中间表。上例中第一个参数`teacher_classes`代表的是中间表的表名,第二个参数是`Base`的元类,第三个和第四个参数就是要连接的两个表,其中`Column`第一个参数是表示的是连接表的外键名,第二个参数表示这个外键的类型,第三个参数表示要外键的表名和字段。 +创建完中间表以后,还需要在两个表中进行绑定,比如在`Teacher`中有一个`classes`属性,来绑定`Classes`表,并且通过`secondary`参数来连接中间表。同理,`Classes`表连接`Teacher`表也是如此。定义完类后,之后就是添加数据,请看以下示例: + +```python +teacher1 = Teacher(tno='t1111',name='xiaotuo',age=10) +teacher2 = Teacher(tno='t2222',name='datuo',age=10) +classes1 = Classes(cno='c1111',name='english') +classes2 = Classes(cno='c2222',name='math') +teacher1.classes = [classes1,classes2] +teacher2.classes = [classes1,classes2] +classes1.teachers = [teacher1,teacher2] +classes2.teachers = [teacher1,teacher2] +session.add(teacher1) +session.add(teacher2) +session.add(classes1) +session.add(classes2) +``` + +### 5.5 `ORM`层面的`CASCADE`: + +如果将数据库的外键设置为`RESTRICT`,那么在`ORM`层面,删除了父表中的数据,那么从表中的数据将会`NULL`。如果不想要这种情况发生,那么应该将这个值的`nullable=False`。 + +在`SQLAlchemy`,只要将一个数据添加到`session`中,和他相关联的数据都可以一起存入到数据库中了。这些是怎么设置的呢?其实是通过`relationship`的时候,有一个关键字参数`cascade`可以设置这些属性: + +1. `save-update`:默认选项。在添加一条数据的时候,会把其他和他相关联的数据都添加到数据库中。这种行为就是`save-update`属性影响的。 +2. `delete`:表示当删除某一个模型中的数据的时候,是否也删掉使用`relationship`和他关联的数据。 +3. `delete-orphan`:表示当对一个ORM对象解除了父表中的关联对象的时候,自己便会被删除掉。当然如果父表中的数据被删除,自己也会被删除。这个选项只能用在一对多上,不能用在多对多以及多对一上。并且还需要在子模型中的`relationship`中,增加一个`single_parent=True`的参数。 +4. `merge`:默认选项。当在使用`session.merge`,合并一个对象的时候,会将使用了`relationship`相关联的对象也进行`merge`操作。 +5. `expunge`:移除操作的时候,会将相关联的对象也进行移除。这个操作只是从session中移除,并不会真正的从数据库中删除。 +6. `all`:是对`save-update, merge, refresh-expire, expunge, delete`几种的缩写。 + +## 6. 查询高级 + +### 6.1 排序: + +1. `order_by`:可以指定根据这个表中的某个字段进行排序,如果在前面加了一个`-`,代表的是降序排序。 + +2. 在模型定义的时候指定默认排序:有些时候,不想每次在查询的时候都指定排序的方式,可以在定义模型的时候就指定排序的方式。有以下两种方式: + + - relationship的order_by参数:在指定`relationship`的时候,传递`order_by`参数来指定排序的字段。 + + - 在模型定义中,添加以下代码: + + ``` + __mapper_args__ = { + "order_by": title + } + ``` + + 即可让文章使用标题来进行排序。 + +3. 正向排序和反向排序:默认情况是从小到大,从前到后排序的,如果想要反向排序,可以调用排序的字段的`desc`方法。 + +### 6.2 limit、offset和切片: + +1. `limit`:可以限制每次查询的时候只查询几条数据。 +2. `offset`:可以限制查找数据的时候过滤掉前面多少条。 +3. 切片:可以对`Query`对象使用切片操作,来获取想要的数据。 + +### 6.3 懒加载: + +在一对多,或者多对多的时候,如果想要获取多的这一部分的数据的时候,往往能通过一个属性就可以全部获取了。比如有一个作者,想要或者这个作者的所有文章,那么可以通过`user.articles`就可以获取所有的。但有时候我们不想获取所有的数据,比如只想获取这个作者今天发表的文章,那么这时候我们可以给`relationship`传递一个`lazy='dynamic'`,以后通过`user.articles`获取到的就不是一个列表,而是一个`AppendQuery`对象了。这样就可以对这个对象再进行一层过滤和排序等操作。 + +### 6.4 查询高级: + +1. group_by: + +根据某个字段进行分组。比如想要根据性别进行分组,来统计每个分组分别有多少人,那么可以使用以下代码来完成: + +```python +session.query(User.gender,func.count(User.id)).group_by(User.gender).all() +``` + +2. having: + +`having`是对查找结果进一步过滤。比如只想要看未成年人的数量,那么可以首先对年龄进行分组统计人数,然后再对分组进行`having`过滤。示例代码如下: + +```python +result = session.query(User.age,func.count(User.id)).group_by(User.age).having(User.age >= 18).all() +``` + +3. join方法: + +`join`查询分为两种,一种是`inner join`,另一种是`outer join`。默认的是`inner join`,如果指定`left join`或者是`right join`则为`outer join`。如果想要查询`User`及其对应的`Address`,则可以通过以下方式来实现: + +```python +for u,a in session.query(User,Address).filter(User.id==Address.user_id).all(): + print(u) + print(a) +# 输出结果: +> +>

+``` + +这是通过普通方式的实现,也可以通过`join`的方式实现,更加简单: + +```python +for u,a in session.query(User,Address).join(Address).all(): + print(u) + print(a) +# 输出结果: +> +>
+``` + +当然,如果采用`outerjoin`,可以获取所有`user`,而不用在乎这个`user`是否有`address`对象,并且`outerjoin`默认为左外查询: + +```python +for instance in session.query(User,Address).outerjoin(Address).all(): + print(instance) + +# 输出结果: +(,
) +(, None) +``` + +4. 别名: + +当多表查询的时候,有时候同一个表要用到多次,这时候用别名就可以方便的解决命名冲突的问题了: + +```python +from sqlalchemy.orm import aliased +adalias1 = aliased(Address) +adalias2 = aliased(Address) +for username,email1,email2 in session.query(User.name,adalias1.email_address,adalias2.email_address).join(adalias1).join(adalias2).all(): + print(username,email1,email2) +``` + +5. 子查询: + +`sqlalchemy`也支持子查询,比如现在要查找一个用户的用户名以及该用户的邮箱地址数量。要满足这个需求,可以在子查询中找到所有用户的邮箱数(通过group by合并同一用户),然后再将结果放在父查询中进行使用: + +```python +from sqlalchemy.sql import func +# 构造子查询 +stmt = session.query(Address.user_id.label('user_id'),func.count(*).label('address_count')).group_by(Address.user_id).subquery() + +# 将子查询放到父查询中 +for u,count in session.query(User,stmt.c.address_count).outerjoin(stmt,User.id==stmt.c.user_id).order_by(User.id): + print(u,count) +``` + +从上面我们可以看到,一个查询如果想要变为子查询,则是通过`subquery()`方法实现,变成子查询后,通过`子查询.c`属性来访问查询出来的列。以上方式只能查询某个对象的具体字段,如果要查找整个实体,则需要通过`aliased`方法,示例如下: + +```python +stmt = session.query(Address) +adalias = aliased(Address,stmt) +for user,address in session.query(User,stmt).join(stmt,User.addresses): + print(user,address) +``` + +## 7. Flask-SQLAlchemy库 + +另外一个库,叫做`Flask-SQLAlchemy`,`Flask-SQLAlchemy`是对`SQLAlchemy`进行了一个简单的封装,使得我们在`flask`中使用`sqlalchemy`更加的简单。可以通过`pip install flask-sqlalchemy`。使用`Flask-SQLAlchemy`的流程如下: + +1. 数据库初始化:数据库初始化不再是通过`create_engine`,请看以下示例: + +```python +from flask import Flask +from flask_sqlalchemy import SQLAlchemy +from constants import DB_URI +app = Flask(__name__) +app.config['SQLALCHEMY_DATABASE_URI'] = DB_URI +db = SQLAlchemy(app) +``` + +2. `ORM`类:之前都是通过`Base = declarative_base()`来初始化一个基类,然后再继承,在`Flask-SQLAlchemy`中更加简单了(代码依赖以上示例): + +```python +class User(db.Model): + id = db.Column(db.Integer,primary_key=True) + username = db.Column(db.String(80),unique=True) + email = db.Column(db.String(120),unique=True) + def __init__(self,username,email): + self.username = username + self.email = email + def __repr__(self): + return '' % self.username +``` + +3. 映射模型到数据库表:使用`Flask-SQLAlchemy`所有的类都是继承自`db.Model`,并且所有的`Column`和数据类型也都成为`db`的一个属性。但是有个好处是不用写表名了,`Flask-SQLAlchemy`会自动将类名小写化,然后映射成表名。 + 写完类模型后,要将模型映射到数据库的表中,使用以下代码创建所有的表: + +```python +db.create_all() +``` + +4. 添加数据:这时候就可以在数据库中看到已经生成了一个`user`表了。接下来添加数据到表中: + +```python +admin = User('admin','admin@example.com') +guest = User('guest','guest@example.com') +db.session.add(admin) +db.session.add(guest) +db.session.commit() +``` + + 添加数据和之前的没有区别,只是`session`成为了一个`db`的属性。 + +5. 查询数据:查询数据不再是之前的`session.query`了,而是将`query`属性放在了`db.Model`上,所以查询就是通过`Model.query`的方式进行查询了: + +```python +users = User.query.all() +# 再如: +admin = User.query.filter_by(username='admin').first() +# 或者: +admin = User.query.filter(User.username='admin').first() +``` + +6. 删除数据:删除数据跟添加数据类似,只不过`session`是`db`的一个属性而已: + +```python +db.session.delete(admin) +db.session.commit() +``` + +## 8. MySQL8图文教程 + +### 8.1 下载: + +在以下链接中下载`MySQL8 Community`:https://dev.mysql.com/downloads/windows/installer/8.0.html +![image.png](04.SQLAlchemy/JkerUJzxSe9gkEZM8kq4td.png) + +### 8.2 安装: + +下载完成后,就可以双击`msi`文件进行安装了。安装步骤如下。 + +1. 第一步:选择`Developer Default`: + ![image.png](04.SQLAlchemy/Yfgrhaxrx6NCj9gSHFbHuV.png) +2. 点击Execute: + ![image.png](04.SQLAlchemy/PYHwMTRXxKjfBKyYG6b2Vi.png) + 然后再点击`Next`执行下一步 + ![image.png](04.SQLAlchemy/8P5sFSmXzjYHNiN76MStNS.png) +3. 点击Next: + ![image.png](04.SQLAlchemy/6jGy66928WdhmKVvX6PtgY.png) +4. 保持默认值,点击Next: + ![image.png](04.SQLAlchemy/wkgYVxahsubMtRv4NrMk9h.png) +5. 设置密码加密方式,用默认的即可,然后点击Next: + ![image.png](04.SQLAlchemy/axbEskKZYY2XaaKfPgrcnD.png) +6. 设置密码,两次密码输入保持一致,以后登录`MySQL`就要用这个密码了,所以要记住: + ![image.png](04.SQLAlchemy/ZhBkRdPgvRrnfAQrseTfs3.png) +7. 保持默认值,点击Next: + ![image.png](04.SQLAlchemy/2wrbfuJzg3RVPL8UaLnw8U.png) +8. 点击Next: + ![image.png](04.SQLAlchemy/mZEdUQoEPJuyXBtZbWsyRF.png) + 执行完后点击Finish + ![image.png](04.SQLAlchemy/TCiEyKKyv5b9iJRT48HbMY.png) +9. 重新点击Next: + ![image.png](04.SQLAlchemy/MW2uxnkekaQG5SiWFcLcfX.png) +10. 点击Next: + ![image.png](04.SQLAlchemy/hT2fsYR8NemfdcVhUpjYSQ.png) +11. 输入密码,点击Check: + ![image.png](04.SQLAlchemy/JeVsr6NJbo73HJhN2qEC5o.png) +12. 点击Finish,完成安装: + ![image.png](04.SQLAlchemy/wYbVmHwu4Crndi4mMMjH9Z.png) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/04.Flask/04.SQLAlchemy/2wrbfuJzg3RVPL8UaLnw8U.png b/04.Flask/04.SQLAlchemy/2wrbfuJzg3RVPL8UaLnw8U.png new file mode 100644 index 0000000..44bb5fc Binary files /dev/null and b/04.Flask/04.SQLAlchemy/2wrbfuJzg3RVPL8UaLnw8U.png differ diff --git a/04.Flask/04.SQLAlchemy/6jGy66928WdhmKVvX6PtgY.png b/04.Flask/04.SQLAlchemy/6jGy66928WdhmKVvX6PtgY.png new file mode 100644 index 0000000..6c5ff57 Binary files /dev/null and b/04.Flask/04.SQLAlchemy/6jGy66928WdhmKVvX6PtgY.png differ diff --git a/04.Flask/04.SQLAlchemy/8P5sFSmXzjYHNiN76MStNS.png b/04.Flask/04.SQLAlchemy/8P5sFSmXzjYHNiN76MStNS.png new file mode 100644 index 0000000..58104da Binary files /dev/null and b/04.Flask/04.SQLAlchemy/8P5sFSmXzjYHNiN76MStNS.png differ diff --git a/04.Flask/04.SQLAlchemy/JeVsr6NJbo73HJhN2qEC5o.png b/04.Flask/04.SQLAlchemy/JeVsr6NJbo73HJhN2qEC5o.png new file mode 100644 index 0000000..7f8e06b Binary files /dev/null and b/04.Flask/04.SQLAlchemy/JeVsr6NJbo73HJhN2qEC5o.png differ diff --git a/04.Flask/04.SQLAlchemy/JkerUJzxSe9gkEZM8kq4td.png b/04.Flask/04.SQLAlchemy/JkerUJzxSe9gkEZM8kq4td.png new file mode 100644 index 0000000..261cdce Binary files /dev/null and b/04.Flask/04.SQLAlchemy/JkerUJzxSe9gkEZM8kq4td.png differ diff --git a/04.Flask/04.SQLAlchemy/MW2uxnkekaQG5SiWFcLcfX.png b/04.Flask/04.SQLAlchemy/MW2uxnkekaQG5SiWFcLcfX.png new file mode 100644 index 0000000..0f7175d Binary files /dev/null and b/04.Flask/04.SQLAlchemy/MW2uxnkekaQG5SiWFcLcfX.png differ diff --git a/04.Flask/04.SQLAlchemy/PYHwMTRXxKjfBKyYG6b2Vi.png b/04.Flask/04.SQLAlchemy/PYHwMTRXxKjfBKyYG6b2Vi.png new file mode 100644 index 0000000..7f1482e Binary files /dev/null and b/04.Flask/04.SQLAlchemy/PYHwMTRXxKjfBKyYG6b2Vi.png differ diff --git a/04.Flask/04.SQLAlchemy/TCiEyKKyv5b9iJRT48HbMY.png b/04.Flask/04.SQLAlchemy/TCiEyKKyv5b9iJRT48HbMY.png new file mode 100644 index 0000000..d749ad2 Binary files /dev/null and b/04.Flask/04.SQLAlchemy/TCiEyKKyv5b9iJRT48HbMY.png differ diff --git a/04.Flask/04.SQLAlchemy/XYQtENVVzPvVVARq7Qt74D.png b/04.Flask/04.SQLAlchemy/XYQtENVVzPvVVARq7Qt74D.png new file mode 100644 index 0000000..4fad10f Binary files /dev/null and b/04.Flask/04.SQLAlchemy/XYQtENVVzPvVVARq7Qt74D.png differ diff --git a/04.Flask/04.SQLAlchemy/Yfgrhaxrx6NCj9gSHFbHuV.png b/04.Flask/04.SQLAlchemy/Yfgrhaxrx6NCj9gSHFbHuV.png new file mode 100644 index 0000000..c1b7627 Binary files /dev/null and b/04.Flask/04.SQLAlchemy/Yfgrhaxrx6NCj9gSHFbHuV.png differ diff --git a/04.Flask/04.SQLAlchemy/ZhBkRdPgvRrnfAQrseTfs3.png b/04.Flask/04.SQLAlchemy/ZhBkRdPgvRrnfAQrseTfs3.png new file mode 100644 index 0000000..0a88275 Binary files /dev/null and b/04.Flask/04.SQLAlchemy/ZhBkRdPgvRrnfAQrseTfs3.png differ diff --git a/04.Flask/04.SQLAlchemy/axbEskKZYY2XaaKfPgrcnD.png b/04.Flask/04.SQLAlchemy/axbEskKZYY2XaaKfPgrcnD.png new file mode 100644 index 0000000..1986329 Binary files /dev/null and b/04.Flask/04.SQLAlchemy/axbEskKZYY2XaaKfPgrcnD.png differ diff --git a/04.Flask/04.SQLAlchemy/eyw6PKK6tH8uAXPtd9AwiD.png b/04.Flask/04.SQLAlchemy/eyw6PKK6tH8uAXPtd9AwiD.png new file mode 100644 index 0000000..9b37859 Binary files /dev/null and b/04.Flask/04.SQLAlchemy/eyw6PKK6tH8uAXPtd9AwiD.png differ diff --git a/04.Flask/04.SQLAlchemy/hT2fsYR8NemfdcVhUpjYSQ.png b/04.Flask/04.SQLAlchemy/hT2fsYR8NemfdcVhUpjYSQ.png new file mode 100644 index 0000000..1480a18 Binary files /dev/null and b/04.Flask/04.SQLAlchemy/hT2fsYR8NemfdcVhUpjYSQ.png differ diff --git a/04.Flask/04.SQLAlchemy/mZEdUQoEPJuyXBtZbWsyRF.png b/04.Flask/04.SQLAlchemy/mZEdUQoEPJuyXBtZbWsyRF.png new file mode 100644 index 0000000..12de1e4 Binary files /dev/null and b/04.Flask/04.SQLAlchemy/mZEdUQoEPJuyXBtZbWsyRF.png differ diff --git a/04.Flask/04.SQLAlchemy/p2YQ6oveDpNYrYQsnejFyV.png b/04.Flask/04.SQLAlchemy/p2YQ6oveDpNYrYQsnejFyV.png new file mode 100644 index 0000000..713d22a Binary files /dev/null and b/04.Flask/04.SQLAlchemy/p2YQ6oveDpNYrYQsnejFyV.png differ diff --git a/04.Flask/04.SQLAlchemy/rHS8Ny8FHDrwhvbUWv4XAC.png b/04.Flask/04.SQLAlchemy/rHS8Ny8FHDrwhvbUWv4XAC.png new file mode 100644 index 0000000..c5759eb Binary files /dev/null and b/04.Flask/04.SQLAlchemy/rHS8Ny8FHDrwhvbUWv4XAC.png differ diff --git a/04.Flask/04.SQLAlchemy/wYbVmHwu4Crndi4mMMjH9Z.png b/04.Flask/04.SQLAlchemy/wYbVmHwu4Crndi4mMMjH9Z.png new file mode 100644 index 0000000..673f619 Binary files /dev/null and b/04.Flask/04.SQLAlchemy/wYbVmHwu4Crndi4mMMjH9Z.png differ diff --git a/04.Flask/04.SQLAlchemy/wkgYVxahsubMtRv4NrMk9h.png b/04.Flask/04.SQLAlchemy/wkgYVxahsubMtRv4NrMk9h.png new file mode 100644 index 0000000..a76c041 Binary files /dev/null and b/04.Flask/04.SQLAlchemy/wkgYVxahsubMtRv4NrMk9h.png differ diff --git a/04.Flask/05.ORM迁移.md b/04.Flask/05.ORM迁移.md new file mode 100644 index 0000000..10e60bf --- /dev/null +++ b/04.Flask/05.ORM迁移.md @@ -0,0 +1,284 @@ +# ORM迁移 + +## 1. alembic + +`alembic`是`sqlalchemy`的作者开发的。用来做`OMR`模型与数据库的迁移与映射。`alembic`使用方式跟`git`有点了类似,表现在两个方面。 + +1. 第一个,`alembic`的所有命令都是以`alembic`开头 +2. 第二,`alembic`的迁移文件也是通过版本进行控制的。首先,通过`pip install alembic`进行安装。 + +以下将解释`alembic`的用法。 + +### 1.1 操作步骤 + +#### 1.1.1 初始化仓库: + +初始化`alembic`仓库。在终端中,`cd`到你的项目目录中,然后执行命令`alembic init alembic`,创建一个名叫`alembic`的仓库。 + +#### 1.1.2 创建模型(ORM)类: + +比如这里创建一个`models.py`模块,然后在里面定义你的模型类,示例代码如下: + +```python +from sqlalchemy import Column,Integer,String,create_engine,Text +from sqlalchemy.orm import sessionmaker +from sqlalchemy.ext.declarative import declarative_base + +Base = declarative_base() +class User(Base): + __tablename__ = 'user' + + id = Column(Integer,primary_key=True) + username = Column(String(20),nullable=False) + password = Column(String(100),nullable=False) + +class Article(Base): + __tablename__ = 'article' + + id = Column(Integer,primary_key=True) + title = Column(String(100),nullable=False) + content = Column(Text, nullable=False) +``` + +#### 1.1.3 修改配置文件: + +- 在`alembic.ini`中设置数据库的连接,`sqlalchemy.url = driver://user:pass@localhost/dbname`,比如以`mysql`数据库为例,则配置后的代码为: + +```python +sqlalchemy.url = mysql+mysqldb://root:root@localhost/alembic_demo?charset=utf8 +``` + +- 为了使用模型类更新数据库,需要在`env.py`文件中设置`target_metadata`,默认为`target_metadata=None`。使用`sys`模块把当前项目的路径导入到`path`中: + +```python +import os +import sys +sys.path.append(os.path.dirname(os.path.abspath(__file__)) + "/../") +from models import Base +... #省略代码 +target_metadata = Base.metadata # 设置创建模型的元类 +... #省略代码 +``` + +#### 1.1.4 生成迁移文件 + +使用命令`alembic revision --autogenerate -m "message"`可以将当前模型中的状态生成迁移文件。 + +#### 1.1.5 更新数据库 + +使用`alembic upgrade head`将刚刚生成的迁移文件,真正映射到数据库中。同理,如果要降级,那么使用`alembic downgrade head`。 + +#### 1.1.6 重复 + +如果以后修改了代码,则重复4~5的步骤。 + +### 1.2 命令和参数解释: + +- init:创建一个`alembic`仓库。 +- revision:创建一个新的版本文件。 +- –autogenerate:自动将当前模型的修改,生成迁移脚本。 +- -m:本次迁移做了哪些修改,用户可以指定这个参数,方便回顾。 +- upgrade:将指定版本的迁移文件映射到数据库中,会执行版本文件中的`upgrade`函数。如果有多个迁移脚本没有被映射到数据库中,那么会执行多个迁移脚本。 +- [head]:代表最新的迁移脚本的版本号。 +- downgrade:会执行指定版本的迁移文件中的`downgrade`函数。 +- heads:展示head指向的脚本文件版本号。 +- history:列出所有的迁移版本及其信息。 +- current:展示当前数据库中的版本号。 + +另外,在你第一次执行`upgrade`的时候,就会在数据库中创建一个名叫`alembic_version`表,这个表只会有一条数据,记录当前数据库映射的是哪个版本的迁移文件。 + +### 1.3 经典错误: + +| 错误描述 | 原因 | 解决办法 | +| :----------------------------------------------------------- | :----------------------------------------------------------- | :----------------------------------------------------------- | +| `FAILED: Target database is not up to date.` | 主要是`heads`和`current`不相同。`current`落后于`heads`的版本。 | 将current移动到head上。alembic upgrade head | +| `FAILED: Can't locate revision identified by '77525ee61b5b'` | 数据库中存的版本号不在迁移脚本文件中 | 删除数据库的`alembic_version`表中的数据,重新执行`alembic upgrade head` | + +## 2. Flask-Migrate插件 + +在实际的开发环境中,经常会发生数据库修改的行为。一般我们修改数据库不会直接手动的去修改,而是去修改`ORM`对应的模型,然后再把模型映射到数据库中。这时候如果有一个工具能专门做这种事情,就显得非常有用了,而`flask-migrate`就是做这个事情的。`flask-migrate`是基于`Alembic`进行的一个封装,并集成到`Flask`中,而所有的迁移操作其实都是`Alembic`做的,他能跟踪模型的变化,并将变化映射到数据库中。 + +使用`Flask-Migrate`需要安装,命令如下: + +``` +pip install flask-migrate +``` + +### 2.1 基本用法 + +要让`Flask-Migrate`能够管理`app`中的数据库,需要使用`Migrate(app,db)`来绑定`app`和数据库。假如现在有以下`app`文件: + +```python +from flask import Flask +from flask_sqlalchemy import SQLAlchemy +from constants import DB_URI +from flask_migrate import Migrate + +app = Flask(__name__) +app.config['SQLALCHEMY_DATABASE_URI'] = DB_URI +app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True +db = SQLAlchemy(app) +## 绑定app和数据库 +migrate = Migrate(app,db) + +class User(db.Model): + id = db.Column(db.Integer,primary_key=True) + username = db.Column(db.String(20)) + + addresses = db.relationship('Address',backref='user') + +class Address(db.Model): + id = db.Column(db.Integer,primary_key=True) + email_address = db.Column(db.String(50)) + user_id = db.Column(db.Integer,db.ForeignKey('user.id')) + +db.create_all() + +@app.route('/') +def hello_world(): + return 'Hello World!' + +if __name__ == '__main__': + app.run() +``` + +之后,就可以在命令行中映射`ORM`了。首先需要初始化一个迁移文件夹: + +```python +flask db init +``` + +然后再把当前的模型添加到迁移文件中: + +```python +flask db migrate +``` + +最后再把迁移文件中对应的数据库操作,真正的映射到数据库中: + +```python +flask db upgrade +``` + +### 2.2 项目重构 + +现在是所有代码都写在一个文件中,这样会导致文件会越来越乱。所以进行一下项目重构,设置为以下的目录结构: +![migrate.png](05.ORM%E8%BF%81%E7%A7%BB/rKAhcte9Fcf6DXAeQATfaV.png) +以下对各个文件的作用进行解释。 + +#### 2.2.1 constants.py文件 + +常量文件,用来存放数据库配置。 + +```python +## constants.py +HOSTNAME = '127.0.0.1' +PORT = '3306' +DATABASE = 'xt_flask_migrate' +USERNAME = 'root' +PASSWORD = 'root' +DB_URI = 'mysql+mysqldb://{}:{}@{}:{}/{}'.format(USERNAME,PASSWORD,HOSTNAME,PORT,DATABASE) +``` + +#### 2.2.2 ext.py文件 + +把`db`变量放到一个单独的文件,而不是放在主`app`文件。这样做的目的是为了在大型项目中如果`db`被多个模型文件引用的话,会造成`from your_app import db`这样的方式,但是往往也在`your_app.py`中也会引入模型文件定义的类,这就造成了循环引用。所以最好的办法是把它放在不依赖其他模块的独立文件中。 + +```python +## ext.py +from flask_sqlalchemy import SQLAlchemy +db = SQLAlchemy() +``` + +#### 2.2.3 models.py文件 + +模型文件,用来存放所有的模型,并且注意,因为这里使用的是`flask-script`的方式进行模型和表的映射,因此不需要使用`db.create_all()`的方式创建数据库。 + +```python +## models.py +from ext import db +class User(db.Model): + id = db.Column(db.Integer,primary_key=True) + username = db.Column(db.String(50)) + addresses = db.relationship('Address',backref='user') + + def __init__(self,username): + self.username = username + +class Address(db.Model): + id = db.Column(db.Integer,primary_key=True) + email_address = db.Column(db.String(50)) + user_id = db.Column(db.Integer,db.ForeignKey('user.id')) + + def __init__(self,email_address): + self.email_address = email_address +``` + +#### 2.2.4 app.py文件 + +这个是主`app`文件,运行文件。并且因为`db`被放到另外一个文件中,所以使用`db.init_app(app)`的方式来绑定数据库。 + +```python +## app.py +from flask import Flask +from ext import db + +app = Flask(__name__) +db.init_app(app) + +@app.route('/') +def hello_world(): + return 'Hello World!' + +if __name__ == '__main__': + app.run() +``` + +### 2.3 迁移命令: + +通过以上项目重构后,后续我们就只要通过以下三个命令即可完成迁移操作了。 + +1. 运行命令来初始化迁移文件: + +```python +python manage.py db init +``` + +2. 运行命令来将模型的映射添加到文件中: + +```python +python manage.py db migrate +``` + +3. 添加将映射文件真正的映射到数据库中: + +```python +python manage.py db upgrade +``` + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/04.Flask/05.ORM迁移/rKAhcte9Fcf6DXAeQATfaV.png b/04.Flask/05.ORM迁移/rKAhcte9Fcf6DXAeQATfaV.png new file mode 100644 index 0000000..37dd513 Binary files /dev/null and b/04.Flask/05.ORM迁移/rKAhcte9Fcf6DXAeQATfaV.png differ diff --git a/04.Flask/06.Flask-WTF插件.md b/04.Flask/06.Flask-WTF插件.md new file mode 100644 index 0000000..f32a82d --- /dev/null +++ b/04.Flask/06.Flask-WTF插件.md @@ -0,0 +1,319 @@ +# Flask-WTF插件 + +## 1. Flask-WTF表单验证 + +`Flask-WTF`是简化了`WTForms`操作的一个第三方库。`WTForms`表单的两个主要功能是验证用户提交数据的合法性以及渲染模板。当然还包括一些其他的功能:`CSRF保护`,文件上传等。安装`Flask-WTF`默认也会安装`WTForms`,因此使用以下命令来安装`Flask-WTF`: + +``` +pip install flask-wtf +``` + +### 1.1 表单验证: + +安装完`Flask-WTF`后。来看下第一个功能,就是用表单来做数据验证,现在有一个`forms.py`文件,然后在里面创建一个`RegistForm`的注册验证表单: + +```python +class RegistForm(Form): + name = StringField(validators=[length(min=4,max=25)]) + email = StringField(validators=[email()]) + password = StringField(validators=[DataRequired(),length(min=6,max=10),EqualTo('confirm')]) + confirm = StringField() +``` + +在这个里面指定了需要上传的参数,并且指定了验证器,比如`name`的长度应该在`4-25`之间。`email`必须要满足邮箱的格式。`password`长度必须在`6-10`之间,并且应该和`confirm`相等才能通过验证。 + +写完表单后,接下来就是`regist.html`文件: + +```python +
+ + + + + + + + + + + + + + + + + + + + + +
用户名:
邮箱:
密码:
确认密码:
+
+``` + +再来看视图函数`regist`: + +```python +@app.route('/regist/',methods=['POST','GET']) +def regist(): + form = RegistForm(request.form) + if request.method == 'POST' and form.validate(): + user = User(name=form.name.data,email=form.email.data,password=form.password.data) + db.session.add(user) + db.session.commit() + return u'注册成功!' + return render_template('regist.html') +``` + +`RegistForm`传递的是`request.form`进去进行初始化,并且判断`form.validate`会返回用户提交的数据是否满足表单的验证。 + +### 1.2 渲染模板: + +`form`还可以渲染模板,让你少写了一丢丢的代码,比如重写以上例子,`RegistForm`表单代码如下: + +```python +class RegistForm(Form): + name = StringField(u'用户名:',validators=[length(min=4,max=25)]) + email = StringField(u'邮箱:'validators=[email()]) + password = StringField(u'密码:',validators=[DataRequired(),length(min=6,max=10),EqualTo('confirm')]) + confirm = StringField(u'确认密码:') +``` + +以上增加了第一个位置参数,用来在html文件中,做标签提示作用。 + +在`app`中的视图函数中,修改为如下: + +```python +@app.route('/regist/',methods=['POST','GET']) +def regist(): + form = RegistForm(request.form) + if request.method == 'POST' and form.validate(): + user = User(name=form.name.data,email=form.email.data,password=form.password.data) + db.session.add(user) + db.session.commit() + return u'注册成功!' + return render_template('regist.html',form=form) +``` + +以上唯一的不同是在渲染模板的时候传入了`form`表单参数进去,这样在模板中就可以使用表单`form`变量了。 + +接下来看下`regist.html`文件: + +```python +
+ + + + + + + + + + + + + + + + + + + + + +
{{ form.name.label }}{{ form.name() }}
{{ form.email.label }}{{ form.email() }}
{{ form.password.label }}{{ form.password() }}
{{ form.confirm.label }}{{ form.confirm() }}
+
+``` + +## 2. Flask-WTF常用字段和验证器 + +### 2.1 Field常用参数: + +在使用`Field`的时候,经常需要传递一些参数进去,以下将对一些常用的参数进行解释: + +- label(第一个参数):`Field`的label的文本。 +- validators:验证器。 +- id:`Field`的id属性,默认不写为该属性名。 +- default:默认值。 +- widget:指定的`html`控件。 + +### 2.2 常用Field: + +- BooleanField:布尔类型的Field,渲染出去是`checkbox`。 + +- FileField:文件上传Field。 + + ```python + # forms.py + from flask_wtf.file import FileField,FileAllowed,FileRequired + class UploadForm(FlaskForm): + avatar = FileField(u'头像:',validators=[FileRequired(),FileAllowed([])]) + + # app.py + @app.route('/profile/',methods=('POST','GET')) + def profile(): + form = ProfileForm() + if form.validate_on_submit(): + filename = secure_filename(form.avatar.data.filename) + form.avatar.data.save(os.path.join(app.config['UPLOAD_FOLDER'],filename)) + return u'上传成功' + + return render_template('profile.html',form=form) + ``` + +- FloatField:浮点数类型的Field,但是渲染出去的时候是`text`的input。 + +- IntegerField:整形的Field。同FloatField。 + +- RadioField:`radio`类型的`input`。表单例子如下: + + ```python + # form.py + class RegistrationForm(FlaskForm): + gender = wtforms.RadioField(u'性别:',validators=[DataRequired()]) + ``` + + 模板文件代码如下: + + ```python + + + {{ form.gender.label }} + + + {% for gender in form.gender %} + {{ gender.label }} + {{ gender }} + {% endfor %} + + + ``` + + `app.py`文件的代码如下,给`gender`添加了`choices`: + + ```python + @app.route('/register/',methods=['POST','GET']) + def register(): + form = RegistrationForm() + form.gender.choices = [('1',u'男'),('2',u'女')] + if form.validate_on_submit(): + return u'success' + + return render_template('register.html',form=form) + ``` + +- SelectField:类似于`RadioField`。看以下示例: + + ```python + # forms.py + class ProfileForm(FlaskForm): + language = wtforms.SelectField('Programming Language',choices=[('cpp','C++'),('py','python'),('text','Plain Text')],validators=[DataRequired()]) + ``` + + 再来看`app.py`文件: + + ```python + @app.route('/profile/',methods=('POST','GET')) + def profile(): + form = ProfileForm() + if form.validate_on_submit(): + print form.language.data + return u'上传成功' + return render_template('profile.html',form=form) + ``` + + 模板文件为: + + ```html +
+ {{ form.csrf_token }} + {{ form.language.label }} + {{ form.language() }} + +
+ ``` + +- StringField:渲染到模板中的类型为``,并且是最基本的文本验证。 + +- PasswordField:渲染出来的是一个`password`的`input`标签。 + +- TextAreaField:渲染出来的是一个`textarea`。 + +### 2.3 常用的验证器: + +数据发送过来,经过表单验证,因此需要验证器来进行验证,以下对一些常用的内置验证器进行讲解: + +- Email:验证上传的数据是否为邮箱。 +- EqualTo:验证上传的数据是否和另外一个字段相等,常用的就是密码和确认密码两个字段是否相等。 +- InputRequired:原始数据的需要验证。如果不是特殊情况,应该使用`InputRequired`。 +- Length:长度限制,有min和max两个值进行限制。 +- NumberRange:数字的区间,有min和max两个值限制,如果处在这两个数字之间则满足。 +- Regexp:自定义正则表达式。 +- URL:必须要是`URL`的形式。 +- UUID:验证`UUID`。 + +### 2.4 自定义验证字段: + +使用`validate_fieldname(self,field)`可以对某个字段进行更加详细的验证,如下: + +```python +class ProfileForm(FlaskForm): + name = wtforms.StringField('name',[validators.InputRequired()]) + def validate_name(self,field): + if len(field.data) > 5: + raise wtforms.ValidationError(u'超过5个字符') +``` + +## 3. CSRF保护: + +在flask的表单中,默认是开启了`csrf`保护功能的,如果你想关闭表单的`csrf`保护,可以在初始化表单的时候传递`csrf_enabled=False`进去来关闭`csrf`保护。如果你想关闭这种默认的行为。如果你想在没有表单存在的请求视图函数中也添加`csrf`保护,可以开启全局的`csrf`保护功能: + +```python +csrf = CsrfProtect() +csrf.init_app(app) +``` + +或者是针对某一个视图函数,使用`csrf.protect`装饰器来开启`csrf`保护功能。并且如果已经开启了全局的`csrf`保护,想要关闭某个视图函数的`csrf`保护功能,可以使用`csrf.exempt`装饰器来取消本视图函数的保护功能。 + +### 3.1 AJAX的CSRF保护: + +在`AJAX`中要使用`csrf`保护,则必须手动的添加`X-CSRFToken`到`Header`中。但是`CSRF`从哪里来,还是需要通过模板给渲染,而`Flask`比较推荐的方式是在`meta`标签中渲染`csrf`,如下: + +```html + +``` + +如果要发送`AJAX`请求,则在发送之前要添加`CSRF`,代码如下(使用了jQuery): + +```javascript +var csrftoken = $('meta[name=csrf-token]').attr('content') +$.ajaxSetup({ + beforeSend: function(xhr, settings) { + if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type) && !this.crossDomain) { + xhr.setRequestHeader("X-CSRFToken", csrftoken) + } + } +}) +``` + + + + + + + + + + + + + + + + + + + + + diff --git a/04.Flask/07.上下文与信号.md b/04.Flask/07.上下文与信号.md new file mode 100644 index 0000000..12e7dc2 --- /dev/null +++ b/04.Flask/07.上下文与信号.md @@ -0,0 +1,174 @@ +# 上下文与信号 + +## 1. Flask上下文 + +`Flask`项目中有两个上下文,一个是应用上下文(app),另外一个是请求上下文(request)。请求上下文`request`和应用上下文`current_app`都是一个全局变量。所有请求都共享的。`Flask`有特殊的机制可以保证每次请求的数据都是隔离的,即A请求所产生的数据不会影响到B请求。所以可以直接导入`request`对象,也不会被一些脏数据影响了,并且不需要在每个函数中使用request的时候传入`request`对象。这两个上下文具体的实现方式和原理可以没必要详细了解。只要了解这两个上下文的四个属性就可以了: + +- `request`:请求上下文上的对象。这个对象一般用来保存一些请求的变量。比如`method`、`args`、`form`等。 +- `session`:请求上下文上的对象。这个对象一般用来保存一些会话信息。 +- `current\_app`:返回当前的app。 +- `g`:应用上下文上的对象。处理请求时用作临时存储的对象。 + +### 1.1 常用的钩子函数 + +- before_first_request:处理第一次请求之前执行。例如以下代码: + +```python + @app.before_first_request + def first_request(): + print 'first time request' +``` + +- before_request:在每次请求之前执行。通常可以用这个装饰器来给视图函数增加一些变量。例如以下代码: + +```python + @app.before_request + def before_request(): + if not hasattr(g,'user'): + setattr(g,'user','xxxx') +``` + +- teardown_appcontext:不管是否有异常,注册的函数都会在每次请求之后执行。 + +```python + @app.teardown_appcontext + def teardown(exc=None): + if exc is None: + db.session.commit() + else: + db.session.rollback() + db.session.remove() +``` + +- template_filter:在使用`Jinja2` 模板的时候自定义过滤器。比如可以增加一个`upper` 的过滤器(当然Jinja2已经存在这个过滤器,本示例只是为了演示作用): + +```python + @app.template_filter + def upper_filter(s): + return s.upper() +``` + +- context_processor:上下文处理器。返回的字典中的键可以在模板上下文中使用。例如: + +```python + @app.context_processor + return {'current_user':'xxx'} +``` + +- errorhandler:errorhandler接收状态码,可以自定义返回这种状态码的响应的处理方法。例如: + +```python + @app.errorhandler(404) + def page_not_found(error): + return 'This page does not exist',404 +``` + +## 2. flask信号: + +### 2.1 安装: + +`flask`中的信号使用的是一个第三方插件,叫做`blinker`。通过`pip list`看一下,如果没有安装,通过以下命令即可安装`blinker`: + +``` +pip install blinker +``` + +### 2.2 内置信号: + +`flask`内置集中常用的信号: + +1. `flask.template_rendered`:模版渲染完毕后发送,示例如下: + +```python + from flask import template_rendered + def log_template_renders(sender,template,context,*args): + print 'sender:',sender + print 'template:',template + print 'context:',context + + template_rendered.connect(log_template_renders,app) +``` + +2. `flask.request_started`:请求开始之前,在到达视图函数之前发送,订阅者可以调用`request`之类的标准全局代理访问请求。示例如下: + +```python + def log_request_started(sender,**extra): + print 'sender:',sender + print 'extra:',extra + request_started.connect(log_request_started,app) +``` + +3. `flask.request_finished`:请求结束时,在响应发送给客户端之前发送,可以传递`response`,示例代码如下: + +```python + def log_request_finished(sender,response,*args): + print 'response:',response + request_finished.connect(log_request_finished,app) +``` + +4. `flask.got_request_exception`:在请求过程中抛出异常时发送,异常本身会通过`exception`传递到订阅的函数。示例代码如下: + +```python + def log_exception_finished(sender,exception,*args): + print 'sender:',sender + print type(exception) + got_request_exception.connect(log_exception_finished,app) +``` + +5. `flask.request_tearing_down`:请求被销毁的时候发送,即使在请求过程中发生异常,也会发送,示例代码如下: + +```python + def log_request_tearing_down(sender,**kwargs): + print 'coming...' + request_tearing_down.connect(log_request_tearing_down,app) +``` + +6. `flask.appcontext_tearing_down`:在应用上下文销毁的时候发送,它总是会被调用,即使发生异常。示例代码如下: + +```python + def log_appcontext_tearing_down(sender,**kwargs): + print 'coming...' + appcontext_tearing_down.connect(log_appcontext_tearing_down,app) +``` + +### 2.3 自定义信号: + +自定义信号分为3步,第一是定义一个信号,第二是监听一个信号,第三是发送一个信号。以下将对这三步进行讲解: + +1. 定义信号:定义信号需要使用到`blinker`这个包的`Namespace`类来创建一个命名空间。比如定义一个在访问了某个视图函数的时候的信号。示例代码如下: + +```python + from blinker import Namespace + + mysignal = Namespace() + visit_signal = mysignal.signal('visit-signal') +``` + +2. 监听信号:监听信号使用`singal`对象的`connect`方法,在这个方法中需要传递一个函数,用来接收以后监听到这个信号该做的事情。示例代码如下: + +```python + def visit_func(sender,username): + print(sender) + print(username) + + mysignal.connect(visit_func) +``` + +3. 发送信号:发送信号使用`singal`对象的`send`方法,这个方法可以传递一些其他参数过去。示例代码如下: + +```python + mysignal.send(username='zhiliao') +``` + + + + + + + + + + + + + diff --git a/04.Flask/08.Flask-Restful.md b/04.Flask/08.Flask-Restful.md new file mode 100644 index 0000000..777e513 --- /dev/null +++ b/04.Flask/08.Flask-Restful.md @@ -0,0 +1,195 @@ +# Flask-Restful + +## 1. Restful API规范 + +`restful api`是用于在前端与后台进行通信的一套规范。使用这个规范可以让前后端开发变得更加轻松。以下将讨论这套规范的一些设计细节。 + +### 1.1 协议: + +采用`http`或者`https`协议。 + +### 1.2 数据传输格式: + +数据之间传输的格式应该都使用`json`,而不使用`xml`。 + +### 1.3 url链接: + +url链接中,不能有动词,只能有名词。并且对于一些名词,如果出现复数,那么应该在后面加`s`。 + +比如:获取文章列表,应该使用`articles`,而不应该使用`get_article` + +### 1.4 HTTP请求的方法: + +1. `GET`:从服务器上获取资源。 +2. `POST`:在服务器上新创建一个资源。 +3. `PUT`:在服务器上更新资源。(客户端提供所有改变后的数据) +4. `PATCH`:在服务器上更新资源。(客户端只提供需要改变的属性) +5. `DELETE`:从服务器上删除资源。 + +**示例如下:** + +- `GET /users/`:获取所有用户。 +- `POST /user/`:新建一个用户。 +- `GET /user/id/`:根据id获取一个用户。 +- `PUT /user/id/`:更新某个id的用户的信息(需要提供用户的所有信息)。 +- `PATCH /user/id/`:更新某个id的用户信息(只需要提供需要改变的信息)。 +- `DELETE /user/id/`:删除一个用户。 + +### 1.5 状态码: + +| 状态码 | 原生描述 | 描述 | +| :----- | :-------------------- | :----------------------------------------------------------- | +| 200 | OK | 服务器成功响应客户端的请求。 | +| 400 | INVALID REQUEST | 用户发出的请求有错误,服务器没有进行新建或修改数据的操作 | +| 401 | Unauthorized | 用户没有权限访问这个请求 | +| 403 | Forbidden | 因为某些原因禁止访问这个请求 | +| 404 | NOT FOUND | 用户发送的请求的url不存在 | +| 406 | NOT Acceptable | 用户请求不被服务器接收(比如服务器期望客户端发送某个字段,但是没有发送)。 | +| 500 | Internal server error | 服务器内部错误,比如出现了bug | + +## 2. Flask-Restful插件 + +### 2.1 介绍: + +`Flask-Restful`是一个专门用来写`restful api`的一个插件。使用他可以快速的集成`restful api`功能。在`app`的后台以及纯`api`的后台中,这个插件可以帮助我们节省很多时间。当然,如果在普通的网站中,这个插件就显得有些鸡肋了,因为在普通的网页开发中,是需要去渲染HTML代码的,而`Flask-Restful`在每个请求中都是返回`json`格式的数据。 + +### 2.2 安装: + +`Flask-Restful`需要在`Flask 0.8`以上的版本,在`Python2.6`或者`Python3.3`上运行。通过`pip install flask-restful`即可安装。 + +### 2.3 定义Restful的视图: + +如果使用`Flask-Restful`,那么定义视图函数的时候,就要继承自`flask_restful.Resource`类,然后再根据当前请求的`method`来定义相应的方法。比如期望客户端是使用`get`方法发送过来的请求,那么就定义一个`get`方法。类似于`MethodView`。示例代码如下: + +```python +from flask import Flask,render_template,url_for +from flask_restful import Api,Resource + +app = Flask(__name__) +## 用Api来绑定app +api = Api(app) + +class IndexView(Resource): + def get(self): + return {"username":"zhiliao"} + +api.add_resource(IndexView,'/',endpoint='index') +``` + +注意事项: + +1. `endpoint`是用来给`url_for`反转`url`的时候指定的。如果不写`endpoint`,那么将会使用视图的名字的小写来作为`endpoint`。 +2. `add_resource`的第二个参数是访问这个视图函数的`url`,这个`url`可以跟之前的`route`一样,可以传递参数。并且还有一点不同的是,这个方法可以传递多个`url`来指定这个视图函数。 + +### 2.4 参数解析: + +`Flask-Restful`插件提供了类似`WTForms`来验证提交的数据是否合法的包,叫做`reqparse`。以下是基本用法: + +```python +parser = reqparse.RequestParser() +parser.add_argument('username',type=str,help='请输入用户名') +args = parser.parse_args() +``` + +`add_argument`可以指定这个字段的名字,这个字段的数据类型等。以下将对这个方法的一些参数做详细讲解: + +1. `default`:默认值,如果这个参数没有值,那么将使用这个参数指定的值。 +2. `required`:是否必须。默认为False,如果设置为`True`,那么这个参数就必须提交上来。 +3. `type`:这个参数的数据类型,如果指定,那么将使用指定的数据类型来强制转换提交上来的值。 +4. `choices`:选项。提交上来的值只有满足这个选项中的值才符合验证通过,否则验证不通过。 +5. `help`:错误信息。如果验证失败后,将会使用这个参数指定的值作为错误信息。 +6. `trim`:是否要去掉前后的空格。 + +其中的`type`,可以使用`python`自带的一些数据类型,也可以使用`flask_restful.inputs`下的一些特定的数据类型来强制转换。比如一些常用的: + +1. `url`:会判断这个参数的值是否是一个url,如果不是,那么就会抛出异常。 +2. `regex`:正则表达式。 +3. `date`:将这个字符串转换为`datetime.date`数据类型。如果转换不成功,则会抛出一个异常。 + +### 2.5 输出字段: + +对于一个视图函数,你可以指定好一些字段用于返回。以后可以使用ORM模型或者自定义的模型的时候,他会自动的获取模型中的相应的字段,生成`json`数据,然后再返回给客户端。这其中需要导入`flask_restful.marshal_with`装饰器。并且需要写一个字典,来指示需要返回的字段,以及该字段的数据类型。示例代码如下: + +```python +class ProfileView(Resource): + resource_fields = { + 'username': fields.String, + 'age': fields.Integer, + 'school': fields.String + } + + @marshal_with(resource_fields) + def get(self,user_id): + user = User.query.get(user_id) + return user +``` + +在`get`方法中,返回`user`的时候,`flask_restful`会自动的读取`user`模型上的`username`以及`age`还有`school`属性。组装成一个`json`格式的字符串返回给客户端。 + +#### 2.5.1 重命名属性: + +很多时候你面向公众的字段名称是不同于内部的属性名。使用 attribute可以配置这种映射。比如现在想要返回`user.school`中的值,但是在返回给外面的时候,想以`education`返回回去,那么可以这样写: + +```python +resource_fields = { + 'education': fields.String(attribute='school') +} +``` + +#### 2.5.2 默认值: + +在返回一些字段的时候,有时候可能没有值,那么这时候可以在指定`fields`的时候给定一个默认值,示例代码如下: + +```python +resource_fields = { + 'age': fields.Integer(default=18) +} +``` + +#### 2.5.3 复杂结构: + +有时候想要在返回的数据格式中,形成比较复杂的结构。那么可以使用一些特殊的字段来实现。比如要在一个字段中放置一个列表,那么可以使用`fields.List`,比如在一个字段下面又是一个字典,那么可以使用`fields.Nested`。以下将讲解下复杂结构的用法: + +```python +class ProfileView(Resource): + resource_fields = { + 'username': fields.String, + 'age': fields.Integer, + 'school': fields.String, + 'tags': fields.List(fields.String), + 'more': fields.Nested({ + 'signature': fields.String + }) + } +``` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/04.Flask/09.Cookie和Session.md b/04.Flask/09.Cookie和Session.md new file mode 100644 index 0000000..566f7f9 --- /dev/null +++ b/04.Flask/09.Cookie和Session.md @@ -0,0 +1,21 @@ +# Cookie和Session + +1. `cookie`:在网站中,http请求是无状态的。也就是说即使第一次和服务器连接后并且登录成功后,第二次请求服务器依然不能知道当前请求是哪个用户。`cookie`的出现就是为了解决这个问题,第一次登录后服务器返回一些数据(cookie)给浏览器,然后浏览器保存在本地,当该用户发送第二次请求的时候,就会自动的把上次请求存储的`cookie`数据自动的携带给服务器,服务器通过浏览器携带的数据就能判断当前用户是哪个了。`cookie`存储的数据量有限,不同的浏览器有不同的存储大小,但一般不超过4KB。因此使用`cookie`只能存储一些小量的数据。 +2. `session`: session和cookie的作用有点类似,都是为了存储用户相关的信息。不同的是,`cookie`是存储在本地浏览器,`session`是一个思路、一个概念、一个服务器存储授权信息的解决方案,不同的服务器,不同的框架,不同的语言有不同的实现。虽然实现不一样,但是他们的目的都是服务器为了方便存储数据的。`session`的出现,是为了解决`cookie`存储数据不安全的问题的。 +3. `cookie`和`session`结合使用:`web`开发发展至今,`cookie`和`session`的使用已经出现了一些非常成熟的方案。在如今的市场或者企业里,一般有两种存储方式: + - 存储在服务端:通过`cookie`存储一个`session_id`,然后具体的数据则是保存在`session`中。如果用户已经登录,则服务器会在`cookie`中保存一个`session_id`,下次再次请求的时候,会把该`session_id`携带上来,服务器根据`session_id`在`session`库中获取用户的`session`数据。就能知道该用户到底是谁,以及之前保存的一些状态信息。这种专业术语叫做`server side session`。存储在服务器的数据会更加的安全,不容易被窃取。但存储在服务器也有一定的弊端,就是会占用服务器的资源,但现在服务器已经发展至今,一些`session`信息还是绰绰有余的。 + - 将`session`数据加密,然后存储在`cookie`中。这种专业术语叫做`client side session`。`flask`采用的就是这种方式,但是也可以替换成其他形式。 + +### flask中使用cookie和session + +1. cookies:在`Flask` 中操作`cookie` ,是通过`response` 对象来操作,可以在`response` 返回之前,通过`response.set_cookie` 来设置,这个方法有以下几个参数需要注意: + + - key:设置的cookie的key。 + - value:key对应的value。 + - max_age:改cookie的过期时间,如果不设置,则浏览器关闭后就会自动过期。 + - expires:过期时间,应该是一个`datetime`类型。 + - domain:该cookie在哪个域名中有效。一般设置子域名,比如`cms.example.com`。 + - path:该cookie在哪个路径下有效。 + +2. session:`Flask`中的`session`是通过`from flask import session`。然后添加值key和value进去即可。并且,`Flask`中的`session`机制是将`session`信息加密,然后存储在`cookie`中。专业术语叫做`client side session`。 + diff --git a/index.md b/index.md new file mode 100644 index 0000000..a2604c4 --- /dev/null +++ b/index.md @@ -0,0 +1,46 @@ +# Python教程大纲 + +## 第一部分: 基础语法 + +- [01.Python基础](/python/01.基础语法/01.python基础.html) +- [02.python文件操作](/python/01.基础语法/02.python文件操作.html) +- [03.python认识函数](/python/01.基础语法/03.python认识函数.html) +- [04.装饰器](/python/01.基础语法/04.装饰器.html) +- [05.迭代器与生成器](/python/01.基础语法/05.迭代器与生成器.html) +- [06.推导式](/python/01.基础语法/06.推导式.html) +- [07.内置函数与匿名函数](/python/01.基础语法/07.内置函数与匿名函数.html) +- [08.递归函数](/python/01.基础语法/08.递归函数.html) +- [09.模块和包](/python/01.基础语法/09.模块和包.html) +- [10.常用模块](/python/01.基础语法/10.常用模块.html) +- [11.异常处理](/python/01.基础语法/12.异常处理.html) +- [12.垃圾回收机制](/python/01.基础语法/13.垃圾回收机制.html) + +## 第二部分: 面向对象 + +- [01.初识面向对象](/python/02.面向对象/01.初识面向对象.html) +- [02.类空间与类之间的关系](/python/02.面向对象/02.类空间与类之间的关系.html) +- [03.类的继承](/python/02.面向对象/03.类的继承.html) +- [04.封装与多态](/python/02.面向对象/04.封装与多态.html) +- [05.类的成员](/python/02.面向对象/05.类的成员.html) +- [06.反射与双下方法](/python/02.面向对象/06.反射与双下方法.html) + +## 第三部分: 网络编程与并发 + +- [01.网络编程基础](/python/03.网络编程与并发/01.网络编程基础.html) +- [02.操作系统发展史](/python/03.网络编程与并发/02.操作系统发展史.html) +- [03.多进程](/python/03.网络编程与并发/03.多进程.html) +- [04.多线程](/python/03.网络编程与并发/04.多线程.html) +- [05.多协程](/python/03.网络编程与并发/05.多协程.html) + + +## 第四部分: Flask框架 + +- [01.URL与视图](/python/04.Flask/01.URL与视图.html) +- [02.Jinja2模板](/python/04.Flask/02.Jinja2模板.html) +- [03.视图高级](/python/04.Flask/03.视图高级.html) +- [04.SQLAlchemy](/python/04.Flask/04.SQLAlchemy.html) +- [05.ORM迁移](/python/04.Flask/05.ORM迁移.html) +- [06.Flask-WTF插件](/python/04.Flask/06.Flask-WTF插件.html) +- [07.上下文与信号](/python/04.Flask/07.上下文与信号.html) +- [08.Flask-Restful](/python/04.Flask/08.Flask-Restful.html) +- [09.Cookie和Session](/python/04.Flask/09.Cookie和Session.html)