├── 第10章 python socket编程 ├── 10-1 弄懂 HTTP、Socket、TCP 这几个概念.md ├── 10-2 socket 和 server 实现通信.md ├── 10-3 socket 实现聊天和多用户连接.md ├── 10-4 socket 模拟 http请求.md └── 10-5 本章小结.md ├── 第11章 多线程、多进程和线程池编程 ├── 11-1 python 中的 GIL.md ├── 11-10 multiprocessing 多进程编程.md ├── 11-11 进程间通信 - Queue、Pipe,Manager.md ├── 11-12 本章小结.md ├── 11-2 多线程编程 - threading.md ├── 11-3 线程间通信 - 共享变量和 Queue.md ├── 11-4 线程同步 - Lock、RLock.md ├── 11-5 线程同步 - condition 使用以及源码分析.md ├── 11-6 线程同步 - Semaphore 使用以及源码分析.md ├── 11-7 ThreadPoolExecutor线程池.md ├── 11-8 ThreadPoolExecutor源码分析.md └── 11-9 多线程和多进程对比.md ├── 第12章 协程和异步io ├── 12-1 并发、并行、同步、异步、阻塞、非阻塞.md ├── 12-10 生成器实现协程.md ├── 12-11 async和await.md ├── 12-12 本章小节.md ├── 12-2 IO 多路复用 (select、poll 和 epoll).md ├── 12-3 select+回调+事件循环获取html.md ├── 12-5 回调之痛.md ├── 12-6 协程是什么.md ├── 12-7 生成器进阶-send、close和throw方法.md └── 12-8 生成器进阶-yield from.md ├── 第13章 asyncio并发编程 ├── 13-1 事件循环.md ├── 13-12 本章小节.md ├── 13-3 task取消和子协程调用原理.md ├── 13-4 call_soon、call_at、call_later、call_soon_threadsafe.md ├── 13-5 ThreadPollExecutor 和 asycio 完成阻塞 IO 请求.md ├── 13-6 asyncio 模拟 http 请求.md ├── 13-7 future 和 task.md ├── 13-8 asyncio同步和通信.md └── 13-9 aiohttp实现高并发爬虫.md ├── 第1章 课程简介 ├── 1-1 导学.md ├── 1-2 开发环境配置.md └── 1-3 资源获取方式.md ├── 第2章 python中一切皆对象 ├── 2-1 python中一切皆对象.md ├── 2-2 type、object和class之间的关系.md ├── 2-3 python中的内置类型.md └── 2-4 本章小结.md ├── 第3章 魔法函数 ├── 3-1 什么是魔法函数.md ├── 3-2 python数据模型对python的影响.md ├── 3-3 python魔法函数一览.md ├── 3-4 len函数的特殊性.md └── 3-5 本章小结.md ├── 第4章 深入类和对象 ├── 4-1 鸭子类型和多态.md ├── 4-10 super真的是调用父类吗?.md ├── 4-11 mixin继承案例-django rest framework.md ├── 4-12 python中的with语句.md ├── 4-13 contextlib简化上下文管理器.md ├── 4-14 本章小结.md ├── 4-2 抽象基类(abc模块).md ├── 4-4 isinstance和type的区别.md ├── 4-5 类变量和实例变量.md ├── 4-6 类和实例属性的查找顺序—mro查找.md ├── 4-7 类方法、静态方法和实例方法.md ├── 4-8 数据封装和私有属性.md └── 4-9 python对象的自省机制.md ├── 第5章 自定义序列类 ├── 5-1 python中的序列分类.md ├── 5-2 python中序列类型的abc继承关系.md ├── 5-3 list中extend方法区别.md ├── 5-4 实现可切片的对象.md ├── 5-5 bisect维护已排序序列.md ├── 5-6 什么时候我们不该使用列表.md ├── 5-7 列表推导式、生成器表达式、字典推导式.md └── 5-8本章小结.md ├── 第6章 深入python的set和dict ├── 6-1 dict的abc继承关系.md ├── 6-2 dict的常用方法.md ├── 6-3 dict的子类.md ├── 6-4 set和frozenset.md ├── 6-5 dict和set的实现原理.md └── 6-6 本章小结.md ├── 第7章 对象引用、可变性和垃圾回收 ├── 7-1 python中的变量是什么.md ├── 7-2 ==和is的区别.md ├── 7-3 del语句和垃圾回收.md ├── 7-4 一个经典的参数错误.md └── 7-5 本章小结.md ├── 第8章 元类编程 ├── 8-1 property动态属性.md ├── 8-2 __getattr__、__getattribute__魔法函数.md ├── 8-3 属性描述符和属性查找过程.md ├── 8-4 __new__和__init__的区别.md ├── 8-5 自定义元类.md ├── 8-6 通过元类实现orm.md └── 8-8 本章小结.md └── 第9章 迭代器和生成器 ├── 9-1 python中的迭代协议.md ├── 9-2 什么是迭代器和可迭代对象.md ├── 9-3 生成器函数的使用.md ├── 9-4 python是如何实现生成器的.md ├── 9-5 生成器在UserList中的应用.md ├── 9-6 生成器如何读取大文件.md └── 9-7 本章小结.md /第10章 python socket编程/10-1 弄懂 HTTP、Socket、TCP 这几个概念.md: -------------------------------------------------------------------------------- 1 | ## 基本概念 2 | - 推荐书籍: TCP/IP详解 卷1: 协议 3 | 4 | ### 五层网络模型 5 | ![](http://qiniu.rearib.top/Fr5eDJbpDM45IXmPajqNFUceyFoV) 6 | 7 | 操作系统给我们提供了一个socket接口, 用于实现TCP和UDP, 它不属于任何协议 8 | 9 | ### socket编程 10 | ![](http://qiniu.rearib.top/Fnpjj9hCnNMMCuVol3aoKsUgZgiB) 11 | 12 | django的socket是存在于uwsgi中 13 | 14 | ### 数据格式转换 15 | ``` 16 | import socket, json 17 | 18 | server = socket.socket() 19 | server.bind(('0.0.0.0', 8000)) 20 | server.listen() 21 | 22 | a = {'1': 1, '2': 2, '3': 3} 23 | 24 | while True: 25 | # 如果没有新的链接过来会堵塞在这里 26 | conn, addr = server.accept() 27 | data = conn.recv(1024) 28 | # 接收的数据是bytes类型, 需要解码成unicode字符串 29 | print(data.decode('utf-8')) 30 | # 首先对字典进行序列化, 从对象变成字符串, 然后再转换成bytes类型 31 | conn.send(json.dumps(a).encode('utf-8')) 32 | conn.close() 33 | 34 | 35 | import socket 36 | import json 37 | 38 | server = socket.socket() 39 | server.connect(('127.0.0.1', 8000)) 40 | server.send('456'.encode('utf-8')) 41 | data = server.recv(1024) 42 | # 接收的data是bytes类型 43 | print(json.loads(data)) 44 | >>> {'1': 1, '2': 2, '3': 3} 45 | print(json.loads(data.decode('utf-8'))) 46 | >>> dict对象输出 47 | server.close() 48 | ``` 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /第10章 python socket编程/10-2 socket 和 server 实现通信.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/love112358/AdvancePython/cff798a25979b33b9eda4af66698cfe3f78a3822/第10章 python socket编程/10-2 socket 和 server 实现通信.md -------------------------------------------------------------------------------- /第10章 python socket编程/10-3 socket 实现聊天和多用户连接.md: -------------------------------------------------------------------------------- 1 | ## 使用多线程实现多用户连接 2 | ``` 3 | import socket 4 | import threading 5 | 6 | server = socket.socket() 7 | server.bind(('0.0.0.0', 8000)) 8 | server.listen() 9 | 10 | # 可以添加收到某个指令break出where循环然后close连接 11 | def handler_sock(conn, addr): 12 | while True: 13 | data = conn.recv(1024) 14 | print(data.decode('utf-8')) 15 | input_data = input() 16 | conn.send(input_data.encode('utf-8')) 17 | 18 | 19 | while True: 20 | conn, addr = server.accept() 21 | client_thread = threading.Thread(target=handler_sock, args=(conn, addr)) 22 | client_thread.start() 23 | ``` 24 | 25 | ``` 26 | import socket 27 | 28 | server = socket.socket() 29 | server.connect(('127.0.0.1', 8000)) 30 | while True: 31 | input_data = input() 32 | server.send(input_data.encode('utf-8')) 33 | data = server.recv(1024) 34 | print(data.decode('utf-8')) 35 | ``` 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /第10章 python socket编程/10-4 socket 模拟 http请求.md: -------------------------------------------------------------------------------- 1 | ## socket 模拟http请求 2 | - 对url解析得到host和path(调用urllib) 3 | - 使用socket进行连接 4 | - 发送get请求, 然后接受数据 5 | - 对数据进行解析处理 6 | - 最后断开socket连接 7 | ``` 8 | #requests -> urlib -> socket 9 | import socket 10 | from urllib.parse import urlparse 11 | 12 | 13 | def get_url(url): 14 | # 解析url 15 | url = urlparse(url) 16 | host = url.netloc 17 | path = url.path 18 | if path == "": 19 | path = "/" 20 | 21 | #建立socket连接 22 | client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 23 | client.connect((host, 80)) 24 | 25 | # 发送请求的格式很重要 26 | client.send("GET {} HTTP/1.1\r\nHost:{}\r\nConnection:close\r\n\r\n".format(path, host).encode("utf8")) 27 | 28 | data = b"" 29 | while True: 30 | d = client.recv(1024) 31 | if d: 32 | data += d 33 | else: 34 | break 35 | 36 | data = data.decode("utf8") 37 | # 去掉request header 38 | html_data = data.split("\r\n\r\n")[1] 39 | print(html_data) 40 | client.close() 41 | 42 | if __name__ == "__main__": 43 | import time 44 | start_time = time.time() 45 | for url in range(20): 46 | url = "http://shop.projectsedu.com/goods/{}/".format(url) 47 | get_url(url) 48 | print(time.time()-start_time) 49 | 50 | ``` -------------------------------------------------------------------------------- /第10章 python socket编程/10-5 本章小结.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/love112358/AdvancePython/cff798a25979b33b9eda4af66698cfe3f78a3822/第10章 python socket编程/10-5 本章小结.md -------------------------------------------------------------------------------- /第11章 多线程、多进程和线程池编程/11-1 python 中的 GIL.md: -------------------------------------------------------------------------------- 1 | ## 全局解释器锁 2 | GIL的全称是Global Interpreter Lock, 3 | - python中一个线程对应于c语言中的一个线程 4 | - GIL使得同一个时刻只有一个线程在一个cpu上执行字节码, 无法将多个线程映射到多个cpu上执行 5 | - GIL会根据执行的字节码行数以及时间片释放gil, gil在遇到io的操作时候主动释放 6 | 7 | ## GIL的特点: 8 | - Python在多线程下,每个线程的执行方式为: 9 | 1. 获取GIL 10 | 2. 执行代码直到sleep或者是python虚拟机将其挂起。 11 | 3. 释放GIL 12 | 13 | 一个CPU只能执行一个线程, 例如一个CPU 有三个线程, 首先线程A执行, 然后线程A达到释放条件进行释放GIL, 线程B和线程C进行竞争GIL, 谁抢到GIL, 继续执行. 14 | 15 | ## GIL无法保证线程绝对安全 16 | ``` 17 | total = 0 18 | 19 | def add(): 20 | global total 21 | for i in range(1000000): 22 | total += 1 23 | def desc(): 24 | global total 25 | for i in range(1000000): 26 | total -= 1 27 | 28 | import threading 29 | thread1 = threading.Thread(target=add) 30 | thread2 = threading.Thread(target=desc) 31 | thread1.start() 32 | thread2.start() 33 | 34 | thread1.join() 35 | thread2.join() 36 | print(total) 37 | ``` 38 | 39 | 40 | -------------------------------------------------------------------------------- /第11章 多线程、多进程和线程池编程/11-10 multiprocessing 多进程编程.md: -------------------------------------------------------------------------------- 1 | ``` 2 | import os 3 | import time 4 | #fork 只用于linux和Unix中 5 | #进程的数据是隔离的 6 | # print("bobby") 7 | # pid = os.fork() 8 | # # print("bobby") 9 | # if pid ==0: 10 | # print("子进程 {},父进程是:{}".format(os.getpid(),os.getppid())) 11 | 12 | # else: 13 | # print("我是父进程:{}".format(pid)) 14 | 15 | # time.sleep(2) 16 | 17 | from concurrent.futures import ProcessPoolExecutor 18 | import multiprocessing 19 | 20 | #多进程变成 21 | import time 22 | def get_html(n): 23 | time.sleep(n) 24 | return n 25 | 26 | if __name__=="__main__": 27 | # progress = multiprocessing.Process(target=get_html,args=(2,)) 28 | # print(progress.pid) 29 | # progress.start() 30 | # 等待所有任务完成 31 | # print(progress.pid) 32 | # progress.join() 33 | # print("main progress end") 34 | 35 | #使用进程池 36 | pool = multiprocessing.Pool(multiprocessing.cpu_count()) 37 | # result = pool.apply_async(get_html,args=(3,)) 38 | # pool.close() 39 | # pool.join() 40 | # print(result.get()) 41 | #imap 42 | for result in pool.imap(get_html,[1,5,3]): 43 | print("{} sleep success".format(result)) 44 | # imap_unordered 谁先完成就打印谁 45 | # for result in pool.imap_unordered(get_html,[1,5,3]): 46 | # print("{} sleep success".format(result)) 47 | -------------------------------------------------------------------------------- /第11章 多线程、多进程和线程池编程/11-11 进程间通信 - Queue、Pipe,Manager.md: -------------------------------------------------------------------------------- 1 | ``` 2 | import time 3 | from multiprocessing import Process,Queue,Pool,Manager,Pipe 4 | # from queue import Queue #多进程编程中 这个queue不能使用 5 | '''分隔符''' 6 | # def producer(queue): 7 | # queue.put("a") 8 | # time.sleep(2) 9 | 10 | # def consumer(queue): 11 | # time.sleep(2) 12 | # data = queue.get() 13 | # print(data) 14 | 15 | # if __name__ == "__main__": 16 | # queue = Queue(10) 17 | # my_producer = Process(target=producer,args=(queue,)) 18 | # my_consumer = Process(target=consumer,args=(queue,)) 19 | # my_producer.start() 20 | # my_consumer.start() 21 | # my_producer.join() 22 | # my_consumer.join() 23 | '''分隔符''' 24 | #共享全局变量通信 25 | #共享全局变量不能适用于多线程编程,可以适用于多线程,数据隔离 26 | 27 | # def producer(a): 28 | # a+=1 29 | # time.sleep(2) 30 | 31 | # def consumer(a): 32 | 33 | # time.sleep(2) 34 | # print(a) 35 | 36 | # if __name__ == "__main__": 37 | # a = 1 38 | # my_producer = Process(target=producer,args=(a,)) 39 | # my_consumer = Process(target=consumer,args=(a,)) 40 | # my_producer.start() 41 | # my_consumer.start() 42 | # my_producer.join() 43 | # my_consumer.join() 44 | 45 | # multiprocessing 中的queue不能用于pool进程池 46 | #pool中的进程间通信需要使用manager中的queue 47 | #需要对manager进行实例化的queue :Manager().Queue() 48 | 49 | # def producer(queue): 50 | # queue.put("a") 51 | # time.sleep(2) 52 | 53 | # def consumer(queue): 54 | # time.sleep(2) 55 | # data = queue.get() 56 | # print(data) 57 | 58 | # if __name__ == "__main__": 59 | # queue = Manager().Queue(10) 60 | # pool = Pool(2) 61 | # pool.apply_async(producer,args=(queue,)) 62 | # pool.apply_async(consumer,args=(queue,)) 63 | # pool.close() 64 | # pool.join() 65 | 66 | #通过pipe管道 实现进程间通信 67 | # def producer(pipe): 68 | # pipe.send("bobby") 69 | 70 | # def consumer(pipe): 71 | # print(pipe.recv()) 72 | 73 | # if __name__ == "__main__": 74 | # recevie_pipe,send_pipe = Pipe() 75 | # #pipe只能适用于两个进程 76 | # my_producer=Process(target=producer, args=(send_pipe,)) 77 | # my_consumer = Process(target=consumer, args=(recevie_pipe,)) 78 | # my_producer.start() 79 | # my_consumer.start() 80 | # my_producer.join() 81 | # my_consumer.join() 82 | '''分隔符''' 83 | def add_data(p_dict,key,value): 84 | p_dict[key] = value 85 | 86 | if __name__ =="__main__": 87 | progress_dict =Manager().dict() 88 | first_progress = Process(target=add_data,args=(progress_dict,"bobby1",22)) 89 | second_progress =Process(target=add_data,args=(progress_dict,"bobby2",23)) 90 | first_progress.start() 91 | second_progress.start() 92 | first_progress.join() 93 | second_progress.join() 94 | 95 | print(progress_dict) 96 | -------------------------------------------------------------------------------- /第11章 多线程、多进程和线程池编程/11-12 本章小结.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/love112358/AdvancePython/cff798a25979b33b9eda4af66698cfe3f78a3822/第11章 多线程、多进程和线程池编程/11-12 本章小结.md -------------------------------------------------------------------------------- /第11章 多线程、多进程和线程池编程/11-2 多线程编程 - threading.md: -------------------------------------------------------------------------------- 1 | ## 守护线程、线程阻塞 2 | - setDaemon 3 | - join 4 | 5 | ## 多线程实例 6 | ``` 7 | class GetDetailHtml(threading.Thread): 8 | def __init__(self, name): 9 | super().__init__(name=name) 10 | 11 | def run(self): 12 | print("get detail html started") 13 | time.sleep(2) 14 | print("get detail html end") 15 | 16 | class GetDetailUrl(threading.Thread): 17 | def __init__(self, name): 18 | super().__init__(name=name) 19 | 20 | def run(self): 21 | print("get detail url started") 22 | time.sleep(4) 23 | print("get detail url end") 24 | 25 | if __name__ == "__main__": 26 | thread1 = GetDetailHtml("get_detail_html") 27 | thread2 = GetDetailUrl("get_detail_url") 28 | start_time = time.time() 29 | thread1.start() 30 | thread2.start() 31 | 32 | # 等待线程执行完才执行主线程 33 | thread1.join() 34 | thread2.join() 35 | 36 | #当主线程退出的时候, 子线程kill掉 37 | print ("last time: {}".format(time.time()-start_time)) 38 | ``` 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /第11章 多线程、多进程和线程池编程/11-3 线程间通信 - 共享变量和 Queue.md: -------------------------------------------------------------------------------- 1 | ## 数据共享 2 | - 共享变量 3 | 4 | 使用一个全局变量, 然后不同线程可以访问并修改这个变量 5 | 6 | - queue 7 | ``` 8 | from queue import Queue 9 | 10 | detail_url_queue = Queue(maxsize=1000) 11 | 12 | queue.put("http://projectsedu.com/{id}".format(id=i)) 13 | url = queue.get() 14 | 15 | ``` 16 | ##线程间的通信 ##以下by me 17 | ``` 18 | variables.py 19 | detail_url_list=[] 20 | thread_queue.py 21 | import time 22 | import threading 23 | from xx import variables 24 | detail_url_list = [] 25 | def get_datail_html(): 26 | detail_url_list = variables.detail_url_list 27 | #爬取文章详情页 28 | while True: 29 | if len(variables.detail_url_list): 30 | url = detail_url_list.pop() 31 | # for url in detail_url_list: 32 | print("get detail html started") 33 | time.sleep(2) 34 | print("get detail html end") 35 | 36 | def get_detail_url(detail_url_list): 37 | #爬取文章列表页 38 | while True: 39 | print("get detail url started") 40 | time.sleep(4) 41 | for i in range(20): 42 | detail_url_list.append("http://projectsedu.com/{id}".format(id=i)) 43 | 44 | print("get detail url end") 45 | 46 | if __name__ == "__main__": 47 | thread_detail_url = threading.Thread(target=get_detail_url,args=(detail_url_list)) 48 | for i in range(10): 49 | html_thread = threading.Thread(target=get_ditail_url,args=(detail_url_list)) 50 | html_thread.start() 51 | start_time = time.time() 52 | print("last time:{}".format(time.time()-start_time)) 53 | 54 | thread_queue_test.py 55 | from queue import Queue 56 | import time 57 | import threading 58 | def get_datail_html(queue): 59 | #爬取文章详情页 60 | while True: 61 | url =queue.get() 62 | # for url in detail_url_list: 63 | print("get detail html started") 64 | time.sleep(2) 65 | print("get detail html end") 66 | 67 | def get_detail_url(queue): 68 | #爬取文章列表页 69 | while True: 70 | print("get detail url started") 71 | time.sleep(4) 72 | for i in range(20): 73 | queue.put("http://projectsedu.com/{id}".format(id=i)) 74 | 75 | print("get detail url end") 76 | 77 | if __name__ == "__main__": 78 | detail_url_queue = Queue(maxsize=1000) 79 | thread_detail_url = threading.Thread(target=get_detail_url,args=(detail_url_queue)) 80 | for i in range(10): 81 | html_thread = threading.Thread(target=get_ditail_url,args=(detail_url_queue)) 82 | html_thread.start() 83 | start_time = time.time() 84 | print("last time:{}".format(time.time()-start_time)) 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /第11章 多线程、多进程和线程池编程/11-4 线程同步 - Lock、RLock.md: -------------------------------------------------------------------------------- 1 | ``` 2 | #Lock Rlock semaphores condition 3 | from threading import Lock,RLock # 可重入的锁 4 | total = 0 5 | lock =Lock() 6 | def add(): 7 | global total 8 | global lock 9 | for i in range(1000000): 10 | lock.acquire() 11 | total += 1 12 | lock.release() 13 | def desc(): 14 | global total 15 | global lock 16 | for i in range(1000000): 17 | lock.acquire() 18 | total -= 1 19 | lock.release() 20 | 21 | import threading 22 | thread1 = threading.Thread(target=add) 23 | thread2 = threading.Thread(target=desc) 24 | thread1.start() 25 | thread2.start() 26 | def add1(a): 27 | a+=1 28 | def desc1(a): 29 | a-=1 30 | """ 31 | add 32 | 1. load a a =0 33 | 2. load 1 1 34 | 3. + 1 35 | 4. 赋值给a a=1 36 | """ 37 | 38 | """ 39 | desc 40 | """ 41 | 1. load a a =0 42 | 2. load 1 1 43 | 3. 1 -1 44 | 4. 赋值给a a=-1 45 | 所以 a=1 或者-1 46 | """ 47 | import dis 48 | print(dis.dis(add1)) 49 | print(dis.dis(desc1)) 50 | 51 | 52 | #thread1.join() 53 | #thread2.join() 54 | #print(total) 55 | -------------------------------------------------------------------------------- /第11章 多线程、多进程和线程池编程/11-5 线程同步 - condition 使用以及源码分析.md: -------------------------------------------------------------------------------- 1 | ``` 2 | """第一版本""" 3 | import threading 4 | class XiaoAi(threading.Thread): 5 | def __init__(self,lock): 6 | super().__init__(name="小爱") 7 | self.lock = lock 8 | def run(self): 9 | self.lock.acquire() 10 | print("{}: 在".format(self.name)) 11 | self.lock.release() 12 | self.lock.acquire() 13 | print("{}: 好啊".format(self.name)) 14 | self.lock.release() 15 | 16 | class TianMao(threading.Thread): 17 | def __init__(self,lock): 18 | super().__init__(name="天猫精灵") 19 | self.lock = lock 20 | def run(self): 21 | self.lock.acquire() 22 | print("{}:小爱同学 ".format(self.name)) 23 | self.lock.release() 24 | self.lock.acquire() 25 | print("{}:我们来对古诗吧 ".format(self.name)) 26 | self.lock.release() 27 | if __name__ =="__main___": 28 | lock = threading.Lock() 29 | xiaoai =XiaoAi() 30 | tianmao =TianMao() 31 | tianmao.start() 32 | xiaoai.start() 33 | 34 | """通过condition方法""" 35 | from threading import condition 36 | class XiaoAi(threading.Thread): 37 | def __init__(self,cond): 38 | super().__init__(name="小爱") 39 | self.cond = cond 40 | def run(self): 41 | with self.cond: 42 | self.cond.wait() 43 | print("{}: 在".format(self.name)) 44 | self.cond.notify() 45 | self.cond.wait() 46 | 47 | print("{}:好啊 ".format(self.name)) 48 | self.cond.notify() 49 | self.cond.wait() 50 | 51 | print("{}:君住长江尾 ".format(self.name)) 52 | self.cond.notify() 53 | self.cond.wait() 54 | 55 | print("{}:共饮长江水 ".format(self.name)) 56 | self.cond.notify() 57 | self.cond.wait() 58 | 59 | print("{}:此恨何时已 ".format(self.name)) 60 | self.cond.notify() 61 | self.cond.wait() 62 | 63 | print("{}:定不负相思意 ".format(self.name)) 64 | self.cond.notify() 65 | self.cond.wait() 66 | 67 | class TianMao(threading.Thread): 68 | def __init__(self,cond): 69 | super().__init__(name="天猫精灵") 70 | self.cond = cond 71 | def run(self): 72 | with self.cond: 73 | print("{}:小爱同学 ".format(self.name)) 74 | self.cond.notify() 75 | self.cond.wait() 76 | print("{}:我们来对古诗吧 ".format(self.name)) 77 | self.cond.notify() 78 | self.cond.wait() 79 | 80 | print("{}:我住长江头 ".format(self.name)) 81 | self.cond.notify() 82 | self.cond.wait() 83 | 84 | print("{}:日日思君不见君 ".format(self.name)) 85 | self.cond.notify() 86 | self.cond.wait() 87 | 88 | print("{}:此水几时休 ".format(self.name)) 89 | self.cond.notify() 90 | self.cond.wait() 91 | 92 | print("{}:只愿君心似我心 ".format(self.name)) 93 | self.cond.notify() 94 | self.cond.wait() 95 | 96 | 97 | if __name__ =="__main___": 98 | cond = threading.Condition() 99 | xiaoai =XiaoAi(cond) 100 | tianmao =TianMao(cond) 101 | xiaoai.start() 102 | tianmao.start() 103 | 104 | 105 | -------------------------------------------------------------------------------- /第11章 多线程、多进程和线程池编程/11-6 线程同步 - Semaphore 使用以及源码分析.md: -------------------------------------------------------------------------------- 1 | ``` 2 | # semaphore 是用于控制进入数量的锁 3 | #文件。读写,写一般只是用于一个协程写,读可以允许有多个 4 | #做爬虫, 5 | import threading 6 | import time 7 | 8 | class HtmlSpider(threading.Thread): 9 | def __init__(self,url,sem): 10 | super().__init__() 11 | self.url = url 12 | self.sem = sem 13 | def run(self): 14 | time.sleep(2) 15 | print("got html text success") 16 | self.sem.release() 17 | 18 | 19 | class UrlProducer(threading.Thread): 20 | def __init__(self,sem): 21 | super().__init__() 22 | self.sem = sem 23 | def run(self): 24 | for i in range(20): 25 | self.sem.acquire() 26 | html_thread = HtmlSpider("https://baidu.com/{}".format(i),self.sem) 27 | html_thread.start() 28 | 29 | 30 | if __name__=='__main__': 31 | sem = threading.Semaphore(3) 32 | url_producer = UrlProducer(sem) 33 | url_producer.start() 34 | #查看queue中的condition 35 | ``` 36 | -------------------------------------------------------------------------------- /第11章 多线程、多进程和线程池编程/11-7 ThreadPoolExecutor线程池.md: -------------------------------------------------------------------------------- 1 | ``` 2 | # from concurrent.futures import ThreadPoolExecutor 3 | # 未来对象,task的返回容器 4 | # #线程池,为什么用线程池 5 | # #主线程中获取某一个线程的状态或者某一个任务的状态,以及返回值 6 | # #当一个线程完成的时候我们的主线程能立即知道 7 | # #futures可以让多线程和多线程编码借口一致 8 | 9 | # import time 10 | 11 | # def get_html(times): 12 | # time.sleep(times) 13 | # print("get page {} success".format(times)) 14 | # return times 15 | 16 | # executor = ThreadPoolExecutor(max_workers=2) 17 | # #通过submit函数提交执行的函数到线程池中,submit是立即返回 18 | # task1 = executor.submit(get_html,(3)) 19 | # task2 = executor.submit(get_html,(2)) 20 | 21 | # #done方法用于判定某个任务是否已经完成 22 | # print(task1.done()) 23 | # print(task2.cancel()) 24 | # time.sleep(3) 25 | # print(task1.done()) 26 | # #result 方法可以获取task的执行结果 27 | # print(task1.result()) 28 | 29 | 30 | # '''分界线''' 31 | # from concurrent.futures import ThreadPoolExecutor,as_completed 32 | # #线程池,为什么用线程池 33 | # #主线程中获取某一个线程的状态或者某一个任务的状态,以及返回值 34 | # #当一个线程完成的时候我们的主线程能立即知道 35 | # #futures可以让多线程和多线程编码借口一致 36 | 37 | # import time 38 | 39 | # def get_html(times): 40 | # time.sleep(times) 41 | # print("get page {} success".format(times)) 42 | # return times 43 | 44 | # executor = ThreadPoolExecutor(max_workers=2) 45 | # #通过submit函数提交执行的函数到线程池中,submit是立即返回 46 | # # task1 = executor.submit(get_html,(3)) 47 | # # task2 = executor.submit(get_html,(2)) 48 | # #要获取已经成功的task的返回 49 | # urls = [3,2,4] 50 | # # all_task=[executor.submit(get_html,(url)) for url in urls] 51 | # # for future in as_completed(all_task): 52 | # # data = future.result() 53 | # # print("get {} page success".format(data)) 54 | # # 通过executor的map获取已经完成task的值 55 | # for data in executor.map(get_html,urls): 56 | # print("get {} page".format(data)) 57 | 58 | '''分界线''' 59 | from concurrent.futures import ThreadPoolExecutor,as_completed,wait,FIRST_COMPLETED 60 | #线程池,为什么用线程池 61 | #主线程中获取某一个线程的状态或者某一个任务的状态,以及返回值 62 | #当一个线程完成的时候我们的主线程能立即知道 63 | #futures可以让多线程和多线程编码借口一致 64 | 65 | import time 66 | 67 | def get_html(times): 68 | time.sleep(times) 69 | print("get page {} success".format(times)) 70 | return times 71 | 72 | executor = ThreadPoolExecutor(max_workers=2) 73 | #通过submit函数提交执行的函数到线程池中,submit是立即返回 74 | # task1 = executor.submit(get_html,(3)) 75 | # task2 = executor.submit(get_html,(2)) 76 | #要获取已经成功的task的返回 77 | urls = [3,2,4] 78 | all_task=[executor.submit(get_html,(url)) for url in urls] 79 | wait(all_task,return_when=FIRST_COMPLETED) 80 | print("main") 81 | # for future in as_completed(all_task): 82 | # data = future.result() 83 | # print("get {} page success".format(data)) 84 | # 通过executor的map获取已经完成task的值 85 | # for data in executor.map(get_html,urls): 86 | # print("get {} page".format(data)) 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /第11章 多线程、多进程和线程池编程/11-8 ThreadPoolExecutor源码分析.md: -------------------------------------------------------------------------------- 1 | 没有代码 2 | -------------------------------------------------------------------------------- /第11章 多线程、多进程和线程池编程/11-9 多线程和多进程对比.md: -------------------------------------------------------------------------------- 1 | ``` 2 | import time 3 | from concurrent.futures import ThreadPoolExecutor,as_completed 4 | from concurrent.futures import ProcessPoolExecutor 5 | #多进程编程 6 | #耗cpu的操作,充分利用多个CPU并发,对于io操作来说,使用多线程编程,进程切换代价高于线程 7 | 8 | #1.对于耗费cpu的操作,多进程优于多线程 9 | # def fib(n): 10 | # if n<=2: 11 | # return 1 12 | 13 | # return fib(n-1)+fib(n-2) 14 | 15 | # # print(fib(3)) 16 | # '''线程''' 17 | # if __name__ =="__main__": 18 | # # with ThreadPoolExecutor(3) as executor: 19 | # with ProcessPoolExecutor(3) as executor: 20 | # all_task =[executor.submit(fib,(num)) for num in range(25,35)] 21 | # start_time = time.time() 22 | # for future in as_completed(all_task): 23 | # data = future.result() 24 | # print("exe result: {}".format(data)) 25 | 26 | # print("last time is :{}".format(time.time()-start_time)) 27 | 28 | # 2.对于io操作来说,多线程优于多进程 29 | def random_sleep(n): 30 | time.sleep(n) 31 | return n 32 | 33 | if __name__=="__main__": 34 | # with ThreadPoolExecutor(3) as executor: 35 | with ThreadPoolExecutor(3) as executor: 36 | all_task =[executor.submit(random_sleep,(num)) for num in [2]*30] 37 | start_time = time.time() 38 | for future in as_completed(all_task): 39 | data = future.result() 40 | print("exe result: {}".format(data)) 41 | 42 | print("last time is :{}".format(time.time()-start_time)) 43 | -------------------------------------------------------------------------------- /第12章 协程和异步io/12-1 并发、并行、同步、异步、阻塞、非阻塞.md: -------------------------------------------------------------------------------- 1 | ``` 2 | #并发与并行 3 | #并发:一个时间段内,有几个程序在同一个CPU上运行,但是任意时刻只有一个程序在CPU上运行 4 | #并行:任意时刻点上,有多个程序同时运行在多个CPU上, 5 | #同步异步 6 | #同步:是指代码调用io操作时,必须等待io操作完成才返回的调用方式 7 | #异步:是指代码调用io操作时,不必等io操作完成就返回的调用方式 8 | 9 | #阻塞和非阻塞 10 | #阻塞:是指调用函数的时候当前线程被挂起 11 | #非阻塞:是指调用函数时候当前线程不会被挂起,而是立即返回 12 | #epoll并不代表一定比select好 13 | #在并发搞的情况下,连接活跃度不是很高,epoll比select并发性不高,同时连接很活跃,select比epoll好 14 | # PPT见github 15 | -------------------------------------------------------------------------------- /第12章 协程和异步io/12-10 生成器实现协程.md: -------------------------------------------------------------------------------- 1 | ``` 2 | #python 为了将语义变得更加明确,就引入了async和await关键词用于定义原生的协程 3 | import types 4 | 5 | @types.coroutine 6 | async def downloader(url): 7 | return "bobby" 8 | 9 | async def downloader_url(url): 10 | html = await downloader(url) 11 | return html 12 | 13 | if __name__ =="__main__": 14 | coro = downloader_url("http://www.imooc.com") 15 | coro.send(None) 16 | -------------------------------------------------------------------------------- /第12章 协程和异步io/12-11 async和await.md: -------------------------------------------------------------------------------- 1 | ``` 2 | # import inspect 3 | # def gen_func(): 4 | # value = yield 1 5 | # #第一返回值给调用方,第二调用方通过send方式返回值给gen 6 | # return "bobby" 7 | # # 1.用同步的方式编写异步的代码,在适当的时候暂停函数并在适当的时候启动函数 8 | 9 | # if __name__=='__main__': 10 | # gen = gen_func() 11 | # print(inspect.getgeneratorstate(gen)) 12 | # next(gen) 13 | # print(inspect.getgeneratorstate(gen)) 14 | # try: 15 | # next(gen) 16 | # except StopIteration: 17 | # pass 18 | # print(inspect.getgeneratorstate(gen)) 19 | 20 | '''分隔符 这部分代码不同 只做演示讲解而已''' 21 | import socket 22 | def get_socket_data(): 23 | yield "bobby" 24 | def downloader(url): 25 | client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 26 | client.setblocking(False) 27 | 28 | try: 29 | client.connect((host,80)) 30 | except BlockingIOError as e: 31 | pass 32 | 33 | selector.register(client.fileno(),EVENT_WRITE,connected) 34 | source = yield from get_socket_data() 35 | 36 | data = source.decode("utf8") 37 | html_data = data.split("\r\n\r\n")[1] 38 | print(html_data) 39 | 40 | def download_html(html): 41 | html =yield from downloader() 42 | 43 | if __name__=='__main__': 44 | #协程的调度依然是 事件循环+协程模式 ,协程是单线程模式 45 | 46 | -------------------------------------------------------------------------------- /第12章 协程和异步io/12-12 本章小节.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/love112358/AdvancePython/cff798a25979b33b9eda4af66698cfe3f78a3822/第12章 协程和异步io/12-12 本章小节.md -------------------------------------------------------------------------------- /第12章 协程和异步io/12-2 IO 多路复用 (select、poll 和 epoll).md: -------------------------------------------------------------------------------- 1 | ``` 2 | 理论部分自己学没有代码 3 | #unix下五种io模型:阻塞式io,非阻塞io,io复用,信号驱动式io,异步io 4 | -------------------------------------------------------------------------------- /第12章 协程和异步io/12-3 select+回调+事件循环获取html.md: -------------------------------------------------------------------------------- 1 | ``` 2 | #通过非阻塞io实现http请求 3 | #requests -> urlib -> socket 4 | #使用了非阻塞io完成http请求 5 | # import socket 6 | # from urllib.parse import urlparse 7 | 8 | 9 | # #使用了非阻塞io完成http请求 10 | # def get_url(url): 11 | # # 解析url 12 | # url = urlparse(url) 13 | # host = url.netloc 14 | # path = url.path 15 | # if path == "": 16 | # path = "/" 17 | 18 | # #建立socket连接 19 | # client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 20 | # client.setblocking(False) 21 | # try: 22 | # client.connect((host, 80)) 23 | # except BlockingIOError as e: 24 | # pass 25 | 26 | # # 发送请求的格式很重要 27 | # while True: 28 | # try: 29 | # client.send("GET {} HTTP/1.1\r\nHost:{}\r\nConnection:close\r\n\r\n".format(path, host).encode("utf8")) 30 | # break 31 | # except OSError as e: 32 | # pass 33 | # data = b"" 34 | # while True: 35 | # try : 36 | # d = client.recv(1024) 37 | # except BlockingIOError as e: 38 | # continue 39 | # if d: 40 | # data += d 41 | # else: 42 | # break 43 | 44 | # data = data.decode("utf8") 45 | # # 去掉request header 46 | # html_data = data.split("\r\n\r\n")[1] 47 | # print(html_data) 48 | # client.close() 49 | 50 | # if __name__ == "__main__": 51 | # import time 52 | # start_time = time.time() 53 | # for url in range(20): 54 | # url = "http://shop.projectsedu.com/goods/{}/".format(url) 55 | # get_url(url) 56 | # print(time.time()-start_time) 57 | '''分隔符''' 58 | #使用select完成http请求 59 | #select+回调+事件循环 60 | #并发性高 61 | #使用单线程 62 | import socket 63 | from urllib.parse import urlparse 64 | from selectors import DefaultSelector,EVENT_READ,EVENT_WRITE 65 | selector = DefaultSelector() 66 | urls = [] 67 | stop =False 68 | class Fetcher: 69 | def connected(self,key): 70 | selector.unregister(key.fd) 71 | self.client.send("GET {} HTTP/1.1\r\nHost:{}\r\nConnection:close\r\n\r\n".format(self.path, self.host).encode("utf8")) 72 | selector.register(self.client.fileno(),EVENT_READ,self.readable) 73 | 74 | def readable(self,key): 75 | d = self.client.recv(1024) 76 | if d: 77 | self.data += d 78 | else: 79 | selector.unregister(key.fd) 80 | data = self.data.decode("utf-8") 81 | # 去掉request header 82 | html_data = data.split("\r\n\r\n")[1] 83 | print(html_data) 84 | self.client.close() 85 | urls.remove(self.spider_url) 86 | if not urls: 87 | global stop 88 | stop =True 89 | 90 | 91 | def get_url(self,url): 92 | # 解析url 93 | self.spider_url = url 94 | url = urlparse(url) 95 | self.host = url.netloc 96 | self.path = url.path 97 | self.data = b"" 98 | if self.path == "": 99 | self.path = "/" 100 | 101 | #建立socket连接 102 | self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 103 | self.client.setblocking(False) 104 | 105 | try: 106 | self.client.connect((self.host, 80)) 107 | except BlockingIOError as e: 108 | pass 109 | 110 | 111 | #注册 112 | selector.register(self.client.fileno(),EVENT_WRITE,self.connected) 113 | 114 | def loop(): 115 | #事件循环,不停的请求socket的状态并调用对应的回调函数 116 | #1.select 本身是不支持register模式的 117 | #2.socket状态变化以后的回调是由程序员完成的 118 | while not stop: 119 | ready = selector.select() 120 | for key,mask in ready: 121 | call_back = key.data 122 | call_back(key) 123 | #回调+事件循环+select(poll\epoll) 124 | 125 | if __name__=='__main__': 126 | fetcher =Fetcher() 127 | import time 128 | start_time = time.time() 129 | for url in range(20): 130 | url = 'http://shop.projectsedu.com/goods/{}/'.format(url) 131 | urls.append(url) 132 | fetcher = Fetcher() 133 | fetcher.get_url(url) 134 | loop() 135 | print(time.time()-start_time) 136 | 137 | 138 | -------------------------------------------------------------------------------- /第12章 协程和异步io/12-5 回调之痛.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/love112358/AdvancePython/cff798a25979b33b9eda4af66698cfe3f78a3822/第12章 协程和异步io/12-5 回调之痛.md -------------------------------------------------------------------------------- /第12章 协程和异步io/12-6 协程是什么.md: -------------------------------------------------------------------------------- 1 | ``` 2 | #1.回调模式编程复杂度搞 3 | # 2.同步编程的并发性不高 4 | # 3.多线程编程需要线程间同步,lock 5 | 6 | 7 | # 1.采用同步的方式去编写异步的代码 8 | # 2.使用单线程去切换任务: 9 | # 1.线程是由操作系统切换的,单线程切换意味着我们需要程序员自己去调度任务 10 | # 2.不在需要锁,并发性高,如果单线程类切换函数,性能远高于线程切换,并发性更高 11 | 12 | def get_url(url): 13 | #do someting 1 14 | html = get_html(url)#此处暂停,切换到另外一个函数去执行 15 | #parse html 16 | urls = parse_url(html) 17 | 18 | def get_url(url): 19 | #do someting 1 20 | html = get_html(url)#此处暂停,切换到另外一个函数去执行 21 | #parse html 22 | urls = parse_url(html) 23 | 24 | #传统函数调用,过程A->B->C 25 | #我们需要一个可以暂停的函数,并且可以在适当的时候恢复该函数的继续执行 26 | #出现了协程->有多个入口的函数,可以暂停的函数(可以向暂停的地方传入值), 27 | -------------------------------------------------------------------------------- /第12章 协程和异步io/12-7 生成器进阶-send、close和throw方法.md: -------------------------------------------------------------------------------- 1 | ``` 2 | # def gen_func(): 3 | # #1.可以产出值,2.可以接受值(调用方传递进来的值) 4 | # html = yield "http://projectsedu.com" 5 | # print(html) 6 | # yield 2 7 | # yield 3 8 | # return "bobby" 9 | 10 | # #throw close 方法 11 | 12 | 13 | # if __name__=="__main__": 14 | # gen = gen_func() 15 | # #1.启动生成器有两种方法;next,send 16 | # #在调用send发送非none值之前,我们必须启动一次生成器,方式有两种:1.gen.send(none) 2.next(gen) 17 | # url = next(gen) 18 | # html ="bobby111" 19 | # print(gen.send(html)) 20 | # #send方法可以传递进入生成器内部,同时还可以重新启动生成器执行到下一个 21 | # print(next(gen)) 22 | # # print(next(gen)) 23 | # # print(next(gen)) 24 | 25 | ##throw close 方法 ---------- 26 | # def gen_func(): 27 | # #1.可以产出值,2.可以接受值(调用方传递进来的值) 28 | # try: 29 | # yield "http://projectsedu.com" 30 | # except Exception: 31 | # pass 32 | # yield 2 33 | # yield 3 34 | # return "bobby" 35 | 36 | # if __name__=="__main__": 37 | # gen = gen_func() 38 | # print(next(gen)) 39 | # gen.close() 40 | # print(next(gen)) 41 | # # generatorexit是继承自baseexception 而不是exception 42 | 43 | #gen throw 44 | 45 | def gen_func(): 46 | #1.可以产出值,2.可以接受值(调用方传递进来的值) 47 | try: 48 | yield "http://projectsedu.com" 49 | except Exception as e: 50 | pass 51 | yield 2 52 | yield 3 53 | return "bobby" 54 | 55 | if __name__=="__main__": 56 | gen = gen_func() 57 | print(next(gen)) 58 | gen.throw(Exception,"download error") 59 | print(next(gen)) 60 | # gen.throw(Exception,"download error") 61 | # generatorexit是继承自baseexception 而不是exception 62 | -------------------------------------------------------------------------------- /第12章 协程和异步io/12-8 生成器进阶-yield from.md: -------------------------------------------------------------------------------- 1 | ``` 2 | #python3 新增的yield from语法 3 | # from itertools import chain 4 | # my_list = [1,2,3] 5 | # my_dict = {"bobby1":"http://projectsedu.com", 6 | # "bobby2":"http://www.imooc.com",} 7 | 8 | 9 | # def my_chain(*args,**kwargs): 10 | # for my_iterable in args: 11 | # for value in my_iterable: 12 | # yield value 13 | 14 | # for value in chain(my_list,my_dict,range(5,10)): 15 | # print(value) 16 | # for value in my_chain(my_list,my_dict,range(5,10)): 17 | # print(value) 18 | 19 | #yield from iterable 20 | # def g1(iterable): 21 | # yield iterable 22 | 23 | # def g2(iterable): 24 | # yield from iterable 25 | 26 | # for value in g1(range(10)): 27 | # print(value) 28 | 29 | # for value in g2(range(10)): 30 | # print(value) 31 | 32 | # def my_chain(*args,**kwargs): 33 | # for my_iterable in args: 34 | # yield from my_iterable 35 | # # for value in my_iterable: 36 | # # yield value 37 | # for value in my_chain(my_list,my_dict,range(5,10)): 38 | # print(value) 39 | 40 | 41 | # def g1(gen): 42 | # yield from gen 43 | 44 | # def main(): 45 | # g = g1() 46 | # g.send(None) 47 | #main 调用方 g1(委托生成器)gan子生成器 48 | #1. yield from 会在调用与子生成器之间建立一个双向通道 49 | 50 | 51 | ##一个案例分析 52 | # final_result = {} 53 | 54 | # def sales_sum(pro_name): 55 | # total =0 56 | # nums=[] 57 | # while True: 58 | # x = yield 59 | # print(pro_name+"销量:",x) 60 | # if not x: 61 | # break 62 | # total +=x 63 | # nums.append(x) 64 | 65 | # return total,nums 66 | 67 | # def middle(key): 68 | # while True: 69 | # final_result[key] = yield from sales_sum(key) 70 | # print(key+"销量统计完成!!.") 71 | 72 | # def main(): 73 | # data_sets = { 74 | # "bobby牌面膜":[1200,1500,3000], 75 | # "bobby牌手机":[28,55,98,108], 76 | # "bobby牌大衣":[280,560,778,70], 77 | # } 78 | # for key,data_set in data_sets.items(): 79 | # print("start key:",key) 80 | # m=middle(key) 81 | # m.send(None) 82 | # for value in data_set: 83 | # m.send(None) #给协程传递每一组的值 84 | # m.send(None) 85 | 86 | # print("final_result:",final_result) 87 | # if __name__=="__main__": 88 | # main() 89 | 90 | '''fenggefu ''' 91 | 92 | # def sales_sum(pro_name): 93 | # total =0 94 | # nums=[] 95 | # while True: 96 | # x = yield 97 | # print(pro_name+"销量:",x) 98 | # if not x: 99 | # break 100 | # total +=x 101 | # nums.append(x) 102 | 103 | # return total,nums 104 | 105 | # if __name__=="__main__": 106 | # my_gen = sales_sum("bobby牌手机") 107 | # my_gen.send(None) 108 | # my_gen.send(1200) 109 | # my_gen.send(1500) 110 | # my_gen.send(3000) 111 | # try: 112 | # my_gen.send(None) 113 | # except StopIteration as e: 114 | # result = e.value 115 | # print(result) 116 | 117 | ##yield from how.py 118 | # 代码太多了 119 | -------------------------------------------------------------------------------- /第13章 asyncio并发编程/13-1 事件循环.md: -------------------------------------------------------------------------------- 1 | ``` 2 | #事件循环+回调(驱动生成器)+epoll(io多路复用) 3 | #asyncio是python用于解决异步io编程的一整套解决方案 4 | #tornado gevent twisted (scrapy,django,channels) 5 | #torando(实现web服务器),django+flask(uwsgi,gunicorn+nginx) 6 | #tornado 可以直接部署,nginx+tornado 7 | 8 | #使用asyncio 9 | # import asyncio 10 | # import time 11 | # async def get_html(url): 12 | # print("start get url") 13 | # await asyncio.sleep(2) #await 后面awaitable对象 14 | # print("end get url") 15 | 16 | # if __name__=="__main__": 17 | # start_time = time.time() 18 | # loop =asyncio.get_event_loop() 19 | # tasks = [get_html("http://www.imooc.com") for i in range(10)] 20 | # loop.run_until_complete(asyncio.wait(tasks)) 21 | # print(time.time()-start_time) 22 | 23 | '''分隔符''' 24 | # #获取协程的返回值 25 | # #使用asyncio 26 | # import asyncio 27 | # import time 28 | # from functools import partial # 29 | # async def get_html(url): 30 | # print("start get url") 31 | # await asyncio.sleep(2) #await 后面awaitable对象 32 | # return "bobby" 33 | 34 | # def callback(url,future): 35 | # print(url) 36 | # print("send email to bobby") 37 | 38 | # if __name__=="__main__": 39 | # start_time = time.time() 40 | # loop =asyncio.get_event_loop() 41 | # # get_future =asyncio.ensure_future(get_html("http://www.imooc.com")) 42 | # # loop.run_until_complete(get_future) 43 | # # print(get_future.result()) 44 | 45 | # task = loop.create_task(get_html("http://www.imooc.com")) 46 | # task.add_done_callback(partial(callback,"http://www.imooc.com")) 47 | # loop.run_until_complete(task) 48 | # print(task.result()) 49 | # print(time.time()-start_time) 50 | 51 | '''分隔符''' 52 | #获取协程的返回值 53 | #wait 和 54 | # import asyncio 55 | # import time 56 | # from functools import partial # 57 | # async def get_html(url): 58 | # print("start get url") 59 | # await asyncio.sleep(2) #await 后面awaitable对象 60 | # return "bobby" 61 | 62 | # def callback(url,future): 63 | # print(url) 64 | # print("send email to bobby") 65 | 66 | # if __name__=="__main__": 67 | # start_time = time.time() 68 | # loop =asyncio.get_event_loop() 69 | # # get_future =asyncio.ensure_future(get_html("http://www.imooc.com")) 70 | # # loop.run_until_complete(get_future) 71 | # # print(get_future.result()) 72 | 73 | # task = loop.create_task(get_html("http://www.imooc.com")) 74 | # task.add_done_callback(partial(callback,"http://www.imooc.com")) 75 | # loop.run_until_complete(task) 76 | # print(task.result()) 77 | # print(time.time()-start_time) 78 | 79 | 80 | '''分隔符''' 81 | 82 | 83 | # 使用wait和gather,gather更加高一成次 84 | import asyncio 85 | import time 86 | async def get_html(url): 87 | print("start get url") 88 | await asyncio.sleep(2) #await 后面awaitable对象 89 | print("end get url") 90 | 91 | if __name__=="__main__": 92 | start_time = time.time() 93 | loop =asyncio.get_event_loop() 94 | # tasks = [get_html("http://www.imooc.com") for i in range(10)] 95 | # loop.run_until_complete(asyncio.gather(*tasks)) 96 | # print(time.time()-start_time) 97 | group1=[get_html("http://projetsedu.com") for i in range(2)] 98 | group2=[get_html("http://www.imooc.com") for i in range(3)] 99 | group1 = asyncio.gather(*group1) 100 | group2 = asyncio.gather(*group2) 101 | # group2.cancel() 102 | loop.run_until_complete(asyncio.gather(group1,group2)) 103 | print(time.time()-start_time) 104 | -------------------------------------------------------------------------------- /第13章 asyncio并发编程/13-12 本章小节.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/love112358/AdvancePython/cff798a25979b33b9eda4af66698cfe3f78a3822/第13章 asyncio并发编程/13-12 本章小节.md -------------------------------------------------------------------------------- /第13章 asyncio并发编程/13-3 task取消和子协程调用原理.md: -------------------------------------------------------------------------------- 1 | ``` 2 | # import asyncio 3 | # loop = asyncio.get_event_loop() 4 | # loop.run_forever() 5 | # loop.run_until_complete() 6 | 7 | #1.loop 会被放到future中 8 | #2.取消future(task) 9 | import asyncio 10 | import time 11 | async def get_html(sleep_times): 12 | print("waiting") 13 | await asyncio.sleep(sleep_times) 14 | print("done after {}s".format(sleep_times)) 15 | 16 | if __name__=="__main__": 17 | task1 =get_html(2) 18 | task2 =get_html(2) 19 | task3 =get_html(2) 20 | tasks = [task1,task2,task3] 21 | loop = asyncio.get_event_loop() 22 | try: 23 | loop.run_until_complete(asyncio.wait(tasks)) 24 | except KeyboardInterrupt as e: 25 | all_tasks = asyncio.Task.all_tasks() 26 | for task in all_tasks: 27 | print("cancel task") 28 | print(task.cancel()) 29 | loop.stop() 30 | loop.run_forever() 31 | finally: 32 | loop.close() 33 | -------------------------------------------------------------------------------- /第13章 asyncio并发编程/13-4 call_soon、call_at、call_later、call_soon_threadsafe.md: -------------------------------------------------------------------------------- 1 | ``` 2 | import asyncio 3 | def callback(sleep_times,loop): 4 | print("sleep {} success {}".format(sleep_times,loop.time())) 5 | 6 | def stoploop(loop): 7 | loop.stop() 8 | 9 | if __name__=="__main__": 10 | loop = asyncio.get_event_loop() 11 | now = loop.time() 12 | #call_soon方法 13 | # loop.call_soon(callback,2) 14 | # loop.call_soon(callback,2) 15 | #call_later方法 16 | # loop.call_later(2,callback,2) 17 | # loop.call_later(1,callback,1) 18 | # loop.call_later(3,callback,3) 19 | 20 | #call_at 方法 21 | loop.call_at(now+2,callback,2,loop) 22 | loop.call_at(now+1,callback,1,loop) 23 | loop.call_at(now+3,callback,3,loop) 24 | loop.call_soon(callback,4,loop) 25 | # loop.call_soon(stoploop,loop) 26 | loop.run_forever() 27 | -------------------------------------------------------------------------------- /第13章 asyncio并发编程/13-5 ThreadPollExecutor 和 asycio 完成阻塞 IO 请求.md: -------------------------------------------------------------------------------- 1 | ``` 2 | 3 | #使用多线程:在协程中集成阻塞io 4 | import asyncio 5 | from concurrent.futures import ThreadPoolExecutor 6 | import socket 7 | from urllib.parse import urlparse 8 | import time 9 | def get_url(url): 10 | # 解析url 11 | url = urlparse(url) 12 | host = url.netloc 13 | path = url.path 14 | if path == "": 15 | path = "/" 16 | 17 | #建立socket连接 18 | client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 19 | client.connect((host, 80)) 20 | 21 | # 发送请求的格式很重要 22 | client.send("GET {} HTTP/1.1\r\nHost:{}\r\nConnection:close\r\n\r\n".format(path, host).encode("utf8")) 23 | 24 | data = b"" 25 | while True: 26 | d = client.recv(1024) 27 | if d: 28 | data += d 29 | else: 30 | break 31 | 32 | data = data.decode("utf8") 33 | # 去掉request header 34 | html_data = data.split("\r\n\r\n")[1] 35 | print(html_data) 36 | client.close() 37 | 38 | if __name__=="__main__": 39 | start_time = time.time() 40 | loop =asyncio.get_event_loop() 41 | executor = ThreadPoolExecutor(3) 42 | tasks= [] 43 | for url in range(20): 44 | url = "http://shop.projectsedu.com/goods/{}/".format(url) 45 | task = loop.run_in_executor(executor,get_url,url) 46 | tasks.append(task) 47 | loop.run_until_complete(asyncio.wait(tasks)) 48 | print("last time:{}".format(time.time()-start_time)) 49 | -------------------------------------------------------------------------------- /第13章 asyncio并发编程/13-6 asyncio 模拟 http 请求.md: -------------------------------------------------------------------------------- 1 | ``` 2 | #asyncio 没有提供http协议的接口 aiohttp 3 | import asyncio 4 | import socket 5 | from urllib.parse import urlparse 6 | import time 7 | async def get_url(url): 8 | # 解析url 9 | url = urlparse(url) 10 | host = url.netloc 11 | path = url.path 12 | if path == "": 13 | path = "/" 14 | 15 | #建立socket连接 16 | reader,writer = await asyncio.open_connection(host,port=80) 17 | writer.write("GET {} HTTP/1.1\r\nHost:{}\r\nConnection:close\r\n\r\n".format(path, host).encode("utf8")) 18 | all_lines=[] 19 | async for raw_line in reader: 20 | data =raw_line.decode("utf8") 21 | all_lines.append(data) 22 | html = "\n".join(all_lines) 23 | return html 24 | 25 | async def main(): 26 | tasks = [] 27 | for url in range(20): 28 | url = "http://shop.projectsedu.com/goods/{}/".format(url) 29 | tasks.append(asyncio.ensure_future(get_url(url))) 30 | 31 | for task in asyncio.as_completed(tasks): 32 | result = await task 33 | print(result) 34 | if __name__=='__main__': 35 | start_time = time.time() 36 | loop = asyncio.get_event_loop() 37 | loop.run_until_complete(main()) 38 | print("last time:{}".format(time.time()-start_time)) 39 | -------------------------------------------------------------------------------- /第13章 asyncio并发编程/13-7 future 和 task.md: -------------------------------------------------------------------------------- 1 | #只有讲解没有代码 2 | -------------------------------------------------------------------------------- /第13章 asyncio并发编程/13-8 asyncio同步和通信.md: -------------------------------------------------------------------------------- 1 | ``` 2 | # asyncio_lock 3 | # total =0 4 | 5 | # async def add(): 6 | # #1.dosomething1 7 | # #2.io操作 8 | # #1.dosomething3 9 | # global total 10 | # for i in range(1000000): 11 | # total +=1 12 | 13 | # async def desc(): 14 | # global total 15 | # for i in range(1000000): 16 | # total-=1 17 | 18 | # if __name__=="__main__": 19 | # import asyncio 20 | # tasks = [add(),desc()] 21 | # loop = asyncio.get_event_loop() 22 | # loop.run_until_complete(asyncio.wait(tasks)) 23 | # print(total) 24 | '''分隔符''' 25 | #以下是演示代码,跑不通 26 | import asyncio 27 | from asyncio import Lock,Queue 28 | # async def async with async for Lock Queue 29 | cache = {} 30 | lock =Lock() 31 | 32 | async def get_stuff(url): 33 | async with lock: 34 | if url in cache: 35 | return cache[url] 36 | stuff = await aiohttp.request("GET",url) 37 | cache[url]=stuff 38 | return stuff 39 | 40 | 41 | async def parse_stuff(): 42 | stuff = await get_stuff() 43 | # do some parsing 44 | 45 | async def use_stuff(): 46 | stuff = await get_stuff() 47 | # use stuff to do something interesting 48 | 49 | tasks = [parse_stuff(),use_stuff()] 50 | loop =asyncio.get_event_loop() 51 | loop.run_until_complete(asyncio.wait(tasks)) 52 | 53 | -------------------------------------------------------------------------------- /第13章 asyncio并发编程/13-9 aiohttp实现高并发爬虫.md: -------------------------------------------------------------------------------- 1 | ``` 2 | #aiohttp github中搜索aiohttp sanic 高并发服务器 github aiomysql 3 | #pip install aiohttp 4 | #pip install pyquery 5 | #pip install aiomysql 6 | #asyncio 爬虫,去重,入库 7 | import asyncio 8 | import re 9 | import aiohttp 10 | import aiomysql 11 | from pyquery import pyquery 12 | stopping = False 13 | start_url = "http://www.jobbole.com/" 14 | waitting_urls = [] 15 | seen_urls = set()#内存太大了 16 | 17 | sem = asyncio.Semaphore(1) 18 | 19 | async def fetch(url,session): 20 | async with sem: 21 | try: 22 | async with session.get(url) as resp: 23 | print("url status: {}".format(resp.status)) 24 | if resp.status in [200,201]: 25 | data = await resp.text() 26 | return data 27 | except Exception as e: 28 | print(e) 29 | 30 | def extract_urls(html): 31 | urls = [] 32 | pq = PyQuery(html) 33 | for link in pq.items("a"): 34 | url = link.attr("href") 35 | if url and url.startswith("http") and url not in seen_urls: 36 | urls.append(url) 37 | waitting_urls.append(url) 38 | return urls 39 | 40 | async def init_urls(url,session): 41 | html = await fetch(url,session) 42 | seen_urls.add(url) 43 | extract_urls(html) 44 | 45 | async def artitle_handler(url,session,pool): 46 | #获取文章详情,并解析入库 47 | html = await fetch(url,session) 48 | seen_urls.add(url) 49 | extract_urls(html) 50 | pq = PyQuery(html) 51 | title = pq("title").text() 52 | async with pool.acquire() as conn: 53 | async with conn.cursor() as cur: 54 | await cur.execute("SELECT 42;") 55 | #需要新建数据库aiomysql_test,-》新建表(名:title,类型:varchar,长度:200)-》表名为article_test, 56 | insert_sql = "insert into article_test(title) values('{}')".format(title) 57 | await cur.execute(insert_sql) 58 | 59 | async def consumer(pool): 60 | async with aiohttp.ClientSession() as session: 61 | while not stopping: 62 | if len(waitting_urls)==0: 63 | await asyncio.sleep(0.5) 64 | continue 65 | url = waitting_urls.pop() 66 | print("start get url:{}".format(url)) 67 | if re.match('http"//.*?jobbole.com/\d+/',url): 68 | if url not in seen_urls: 69 | asyncio.ensure_future(artitle_handler(url,session,pool)) 70 | else: 71 | if url not in seen_urls: 72 | asyncio.ensure_future(init_urls(url,session)) 73 | await asyncio.sleep(0.5) 74 | 75 | async def main(loop): 76 | #等待mysql连接建立 77 | pool=await aiomysql.create_pool(host='127.0.0.1',port=3306,user='root',password='root',db='aiomysql_test',loop=loop,charset='uft8',autocommit=True) 78 | async with aiohttp.ClientSession() as session: 79 | html = await fetch(start_url,session) 80 | seen_urls.add(start_url) 81 | extract_urls(html) 82 | 83 | asyncio.ensure_future(consumer(pool)) 84 | 85 | if __name__=="__main__": 86 | loop = asyncio.get_event_loop() 87 | asyncio.ensure_future(main(loop)) 88 | loop.run_forever() 89 | -------------------------------------------------------------------------------- /第1章 课程简介/1-1 导学.md: -------------------------------------------------------------------------------- 1 | ## 课程框架 2 | ![](http://qiniu.rearib.top/FlycViDiQjWF02vbcTKjiHORdiBk) 3 | 4 | -------------------------------------------------------------------------------- /第1章 课程简介/1-2 开发环境配置.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/love112358/AdvancePython/cff798a25979b33b9eda4af66698cfe3f78a3822/第1章 课程简介/1-2 开发环境配置.md -------------------------------------------------------------------------------- /第1章 课程简介/1-3 资源获取方式.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/love112358/AdvancePython/cff798a25979b33b9eda4af66698cfe3f78a3822/第1章 课程简介/1-3 资源获取方式.md -------------------------------------------------------------------------------- /第2章 python中一切皆对象/2-1 python中一切皆对象.md: -------------------------------------------------------------------------------- 1 | ## Python中一切皆对象 2 | - 元类编程 3 | - 猴子补丁 4 | 5 | ## 动态语言和静态语言的区别 6 | - python的面向对象更彻底 7 | - Java中object是class的一个实例 8 | - Python中class也是对象, 函数也是对象 9 | - Python中的代码和模块也是对象 10 | 11 | ## 函数和类也是对象,属于python的一等公民 12 | 1. 赋值给一个变量 13 | 2. 可以添加到集合对象中 14 | 3. 可以作为参数传递给函数 15 | 4. 可以当做函数的返回值 16 | 17 | 对类进行实例化的时候返回的是一个类的对象 18 | 19 | 20 | -------------------------------------------------------------------------------- /第2章 python中一切皆对象/2-2 type、object和class之间的关系.md: -------------------------------------------------------------------------------- 1 | ## type的两种用法 2 | - 生成一个类 3 | - 返回一个对象的类型 4 | 5 | ## type->int->1 6 | - type->class->obj 7 | ``` 8 | # 1是通过int这个类实例化的对象, int是通过type这个类实例化的对象 9 | >>> a = 1 10 | >>> type(1) 11 | 12 | >>> type(int) 13 | 14 | 15 | >>> class Student: 16 | ... pass 17 | ... 18 | >>> class MyStudent(Student): 19 | ... pass 20 | ... 21 | >>> stu = Student() 22 | 23 | >>> type(stu) 24 | 25 | >>> type(Student) 26 | 27 | >>> type(object) 28 | 29 | >>> type(type) 30 | 31 | 32 | >>> a = 'abc' 33 | >>> type(a) 34 | 35 | >>> type(str) 36 | 37 | >>> type(type) 38 | 39 | 40 | >>> Student.__bases__ 41 | (,) 42 | >>> MyStudent.__bases__ 43 | (,) 44 | >>> type.__bases__ 45 | (,) 46 | >>> object.__bases__ 47 | () 48 | ``` 49 | 50 | ## type、object和class的关系 51 | ![](http://qiniu.rearib.top/FuGb8QAEGTpbO7AyZtE8VreIHcGF) 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /第2章 python中一切皆对象/2-3 python中的内置类型.md: -------------------------------------------------------------------------------- 1 | ## python中对象的三个特征 2 | ### 身份 3 | - 对象在内存中的地址,可以通过id去查看 4 | ### 类型 5 | - int类型、字符串类型... 6 | ### 值 7 | `a = 1`, 1是指这个对象的值, 1会被python的int类型进行封装, 然后使用a指向1这个对象 8 | 9 | ## python中的常见内置类型 10 | - None(全局只有一个) 11 | ``` 12 | a = None 13 | b = None 14 | a和b都是指向同一个对象 15 | ``` 16 | - 数值 17 | ``` 18 | int 19 | float 20 | complex 21 | bool 22 | ``` 23 | - 迭代类型 24 | - 序列类型 25 | ``` 26 | list 27 | bytes、bytearray、memoryview(二进制序列) 28 | range 29 | tuple 30 | str 31 | array 32 | ``` 33 | - 映射(dict) 34 | - 集合 35 | ``` 36 | set 37 | frozenset 38 | ``` 39 | - 上下文管理类型(with) 40 | - 其他 41 | ``` 42 | 模块类型 43 | class和实例函数类型 44 | 方法类型 45 | 代码类型 46 | object对象 47 | type类型 48 | ellipsis类型 49 | notimplemented类对象 50 | ``` 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /第2章 python中一切皆对象/2-4 本章小结.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/love112358/AdvancePython/cff798a25979b33b9eda4af66698cfe3f78a3822/第2章 python中一切皆对象/2-4 本章小结.md -------------------------------------------------------------------------------- /第3章 魔法函数/3-1 什么是魔法函数.md: -------------------------------------------------------------------------------- 1 | ## 什么是魔法函数? 2 | - Python里面的魔法函数,是以双下划线开头和结尾 3 | - 魔法函数不依赖任何类,并且可以随时调用 4 | - 一旦类里面加上一些特定的魔法函数,整个类就被附加了一些特定的功能. 5 | - 魔法函数定义了我们不需要显式的调用它,Python解释器自己会知道什么情况下会调用,我们在使用相应的语法的时候就会自动调用。 6 | - 魔法函数和本身的类没有关系,和类的父类,object也没有关系。魔法函数可以写到任意一个类中,跟继不继承没有必然的关系。 7 | 8 | ## 实例 9 | - for循环的是可迭代对象, 首先通过\_\_iter\_\_得到一个迭代器, 然后不断调用迭代器的\_\_next\_\_, 但是如果对象没有实现 \_\_iter\_\_或\_\_next\_\_迭代器协议,Python的解释器就会去寻找\_\_getitem\_\_来迭代对象,如果连\_\_getitem\_\_都没有定义,这解释器就会报对象不是可迭代对象的错误. 10 | - 魔法函数是能影响到语法本身的, 本来company是无法进行切片操作, 但是由于实现了\_\_getitem\_\_, 所以在python的语法上我们可以对实例化的对象进行切片操作.(列表也是list这个类实例化得到的一个对象) 11 | ``` 12 | class Company(object): 13 | def __init__(self, employee__list): 14 | self.employee = employee__list 15 | # item将传入0、1、2... 16 | def __getitem__(self, item): 17 | return self.employee[item] 18 | 19 | def __len__(self): 20 | return len(self.employee) 21 | 22 | company = Company(["tom", "bob", "jane"]) 23 | 24 | for em in company: # __getitem__ 25 | print(em) 26 | 27 | for em in company[1:]: # __getitem__ 28 | print(em) 29 | 30 | print(len(company)) # __len__ 31 | ``` -------------------------------------------------------------------------------- /第3章 魔法函数/3-2 python数据模型对python的影响.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/love112358/AdvancePython/cff798a25979b33b9eda4af66698cfe3f78a3822/第3章 魔法函数/3-2 python数据模型对python的影响.md -------------------------------------------------------------------------------- /第3章 魔法函数/3-3 python魔法函数一览.md: -------------------------------------------------------------------------------- 1 | ## 常用魔法函数(非数学运算类型) 2 | ### 字符串表示 3 | - \_\_repr\_\_ 4 | - \_\_str\_\_ 5 | 6 | ### 集合序列相关 7 | - \_\_len\_\_ 8 | - \_\_getitem\_\_ 9 | - \_\_setitem\_\_ 10 | - \_\_delitem\_\_ 11 | - \_\_contains\_\_ 12 | 13 | ### 迭代相关 14 | - \_\_iter\_\_ 15 | - \_\_next\_\_ 16 | 17 | ### 可调用 18 | - \_\_call\_\_ 19 | 20 | ### with上下文管理器 21 | - \_\_enter\_\_ 22 | - \_\_exit\_\_ 23 | 24 | ### 数值转换 25 | - \_\_abs\_\_ 26 | - \_\_bool\_\_ 27 | - \_\_int\_\_ 28 | - \_\_float\_\_ 29 | - \_\_hash\_\_ 30 | - \_\_index\_\_ 31 | 32 | ### 元类相关 33 | - \_\_new\_\_ 34 | - \_\_init\_\_ 35 | 36 | ### 属性相关 37 | - \_\_getattr\_\_ 38 | - \_\_setattr\_\_ 39 | - \_\_getattribute\_\_ 40 | - \_\_setattribute\_\_ 41 | - \_\_dir\_\_ 42 | 43 | ### 属性描述符 44 | - \_\_get\_\_ 45 | - \_\_set\_\_ 46 | - \_\_delete\_\_ 47 | 48 | ### 协程 49 | - \_\_await\_\_ 50 | - \_\_aiter\_\_ 51 | - \_\_anext\_\_ 52 | - \_\_aenter\_\_ 53 | - \_\_aexit\_\_ 54 | 55 | ## 常用魔法函数(数学运算类型) 56 | ### 一元运算符 57 | - \_\_neg\_\_(-) 58 | - \_\_pos\_\_(+) 59 | - \_\_abs\_\_ 60 | 61 | ### 二元运算符 62 | - \_\_lt\_\_(<) 63 | - \_\_le\_\_ <= 64 | - \_\_eq\_\_ == 65 | - \_\_ne\_\_ != 66 | - \_\_gt\_\_ > 67 | - \_\_ge\_\_ >= 68 | 69 | ### 算术运算符 70 | - \_\_add\_\_ + 71 | - \_\_sub\_\_ - 72 | - \_\_mul\_\_ * 73 | - \_\_truediv\_\_ / 74 | - \_\_floordiv\_\_ // 75 | - \_\_mod\_\_ % 76 | - \_\_divmod\_\_ 或 divmod() 77 | - \_\_pow\_\_ 或 ** 或 pow() 78 | - \_\_round\_\_ 或 round() 79 | 80 | ### 反向算术运算符 81 | - \_\_radd\_\_ 82 | - \_\_rsub\_\_ 83 | - \_\_rmul\_\_ 84 | - \_\_rtruediv\_\_ 85 | - \_\_rfloordiv\_\_ 86 | - \_\_rmod\_\_ 87 | - \_\_rdivmod\_\_ 88 | - \_\_rpow\_\_ 89 | 90 | ### 增量赋值算术运算符 91 | - \_\_iadd\_\_ 92 | - \_\_isub\_\_ 93 | - \_\_imul\_\_ 94 | - \_\_itruediv\_\_ 95 | - \_\_ifloordiv\_\_ 96 | - \_\_imod\_\_ 97 | - \_\_ipow\_\_ 98 | 99 | ### 位运算符 100 | - \_\_invert\_\_ ~ 101 | - \_\_lshift\_\_ << 102 | - \_\_rshift\_\_ >> 103 | - \_\_and\_\_ & 104 | - \_\_or\_\_ | 105 | - \_\_xor\_\_ ^ 106 | 107 | ### 反向位运算符 108 | - \_\_rlshift\_\_ 109 | - \_\_rrshift\_\_ 110 | - \_\_rand\_\_ 111 | - \_\_rxor\_\_ 112 | - \_\_ror\_\_ 113 | 114 | ### 增量赋值位运算符 115 | - \_\_ilshift\_\_ 116 | - \_\_irshift\_\_ 117 | - \_\_iand\_\_ 118 | - \_\_ixor\_\_ 119 | - \_\_ior\_\_ 120 | 121 | 122 | ## 调试工具 123 | - notebook 124 | 125 | 首先使用`pip install -i https://douban.com/simple notebook`安装然后运行`ipython notebook` 126 | 127 | ## 字符串表示 128 | - \_\_str\_\_ 129 | 130 | 在打印一个实例化对象的时候, python默认会调用str(对象), 对应的魔法函数是\_\_str\_\_ 131 | ``` 132 | class Company(object): 133 | def __init__(self, employee__list): 134 | self.employee = employee__list 135 | 136 | company = Company(["tom", "bob", "jane"]) 137 | print(company) 138 | print(str(company)) 139 | 140 | <__main__.Company object at 0x000001CFA60BE748> 141 | <__main__.Company object at 0x000001CFA60BE748> 142 | ``` 143 | 144 | - \_\_repr\_\_ 145 | 146 | \_\_repr\_\_是在开发模式下调用的 147 | ``` 148 | class Company(object): 149 | def __init__(self, employee__list): 150 | self.employee = employee__list 151 | 152 | company = Company(["tom", "bob", "jane"]) 153 | print(company) 154 | company 155 | 156 | <__main__.Company object at 0x0000020A9D7672B0> 157 | <__main__.Company at 0x20a9d7672b0> 158 | ``` 159 | 160 | 再次强调, \_\_repr\_\_不是因为该类继承了某一个对象才能去写这个方法, 魔法函数可以写到任何一个定义的类中去, 然后python解释器就是识别出这个对象有该特性, 然后再调试模式下company会被解释器转换为repr(company), 然后再去调用company.\_\_repr\_\_(). 161 | 162 | ``` 163 | class Company(object): 164 | def __init__(self, employee__list): 165 | self.employee = employee__list 166 | 167 | def __str__(self): 168 | return ','.join(self.employee) 169 | 170 | def __repr__(self): 171 | return '.'.join(self.employee) 172 | 173 | company = Company(["tom", "bob", "jane"]) 174 | print(company) # str 输出 175 | company # repr输出 176 | 177 | tom,bob,jane # 打印对象 178 | tom.bob.jane # 调试模式 179 | ``` 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | -------------------------------------------------------------------------------- /第3章 魔法函数/3-4 len函数的特殊性.md: -------------------------------------------------------------------------------- 1 | ## len函数 2 | 之前提到len函数式会调用对象的\_\_len\_\_, 如果是使用遍历的方式求长度那么效率会很低, 但是在求python内置类型的长度比如len(list)、len(dict)、len(set)等的时候会很快, 因为在cpython中的list、dict、set等是通过c语言实现的, 在其内部会维护一个数据表示长度,所以就不需要进行遍历,能大大提高效率, 所以尽量使用python原生的数据类型 -------------------------------------------------------------------------------- /第3章 魔法函数/3-5 本章小结.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/love112358/AdvancePython/cff798a25979b33b9eda4af66698cfe3f78a3822/第3章 魔法函数/3-5 本章小结.md -------------------------------------------------------------------------------- /第4章 深入类和对象/4-1 鸭子类型和多态.md: -------------------------------------------------------------------------------- 1 | ## 什么是鸭子类型 2 | 当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子, 那么这只鸟就可以被称为鸭子. 3 | 4 | 在下面这段代码中, 所有的类实现了同一个方法, 这些类就可以归为同一种类型, 这样在调用的时候就可以都调用say方法, 从而实现了多态, 一种接口多种实现. 5 | ``` 6 | class Cat(object): 7 | def say(self): 8 | print("i am a cat") 9 | 10 | class Dog(object): 11 | def say(self): 12 | print("i am a fish") 13 | 14 | class Duck(object): 15 | def say(self): 16 | print("i am a duck") 17 | 18 | animal_list = [Cat, Dog, Duck] # 类也是对象, 可以被添加到列表中, 而且python是动态语言, 对于变量不需要指定类型 19 | for animal in animal_list: 20 | animal().say() 21 | ``` 22 | 23 | ### 列表的extend 24 | ``` 25 | def extend(self, iterable): # real signature unknown; restored from __doc__ 26 | """ L.extend(iterable) -> None -- extend list by appending elements from the iterable """ 27 | ``` 28 | list.extend() 29 | 因为传入的只需要是iterable类型即可, 所以list可以扩展tuple、set等都可以. 或者我们实现一个类可以迭代,也可以放到extend中. 30 | ``` 31 | class Company(object): 32 | def __init__(self, employee_list): 33 | self.employee = employee_list 34 | 35 | def __getitem__(self, item): # 可迭代 36 | return self.employee[item] 37 | 38 | company = Company(["tom", "bob", "jane"]) 39 | 40 | a = ["bobby1", "bobby2"] 41 | 42 | a.extend(company) 43 | print(a) 44 | ``` 45 | 46 | 我们在几个对象中都实现了某一个方法名, 这些类我们就可以通用, 比如上面的say和\_\_getitem\_\_, 而魔法函数也是利用的python的鸭子类型, 只要实现了\_\_getitem\_\_就可迭代, 就可以传入extend中. 47 | 48 | 49 | -------------------------------------------------------------------------------- /第4章 深入类和对象/4-10 super真的是调用父类吗?.md: -------------------------------------------------------------------------------- 1 | ## super真正调用的是什么? 2 | super真正调用的是MRO中的下一个类的函数 3 | ``` 4 | class A: 5 | def __init__(self): 6 | print ("A") 7 | 8 | class B(A): 9 | def __init__(self): 10 | print ("B") 11 | super().__init__() 12 | 13 | class C(A): 14 | def __init__(self): 15 | print ("C") 16 | super().__init__() 17 | 18 | class D(B, C): 19 | def __init__(self): 20 | print ("D") 21 | super(D, self).__init__() 22 | 23 | if __name__ == "__main__": 24 | print(D.__mro__) 25 | d = D() 26 | 27 | >>> (, , , , ) 28 | D 29 | B 30 | C 31 | A 32 | ``` -------------------------------------------------------------------------------- /第4章 深入类和对象/4-11 mixin继承案例-django rest framework.md: -------------------------------------------------------------------------------- 1 | ## Mixin类 2 | - Python是支持多继承的。我们可以利用 Python 的这种特性,实现一种叫做 Mixin 的类 3 | 4 | - **Mixin 类只包含了一组特定的函数集合,而我们将会将其与其他类进行混合,从而生成一个适用于实际需要的新类** 5 | 6 | ## Mixin模式特点 7 | 1. Mixin类功能单一 8 | 2. 不和基类关联,可以和任意基类组合, 基类可以不和mixin关联就能初始化成功 9 | 3. 在mixin中不要使用super这种用法 -------------------------------------------------------------------------------- /第4章 深入类和对象/4-12 python中的with语句.md: -------------------------------------------------------------------------------- 1 | ## 上下文管理器 2 | ### 异常捕捉中的return 3 | ``` 4 | def exe_try(): 5 | try: 6 | print ("code started") 7 | raise KeyError 8 | return 1 # 不会被执行 9 | except KeyError as e: 10 | print ("key error") 11 | return 2 # 压入堆栈 12 | else: 13 | print ("no error") 14 | return 3 15 | finally: 16 | print ("finally") 17 | return 4 # 压入堆栈, 最后取出栈顶 18 | 19 | print(exe_try()) 20 | 21 | 输出: 22 | code started 23 | key error 24 | finally 25 | 4 # 不是输出2, 而是4 26 | ``` 27 | 28 | ## 上下文管理器协议 29 | with语句后面的as得到的是是__enter__方法的返回值, 如果`__enter__`返回1, 那么sample就等于1. 30 | ``` 31 | class Sample: 32 | def __enter__(self): 33 | # 获取资源 34 | print ("enter") 35 | return self 36 | def __exit__(self, exc_type, exc_val, exc_tb): 37 | #释放资源 38 | print ("exit") 39 | def do_something(self): 40 | print ("doing something") 41 | 42 | with Sample() as sample: 43 | sample.do_something() 44 | 45 | 输出: 46 | enter 47 | doing something 48 | exit 49 | ``` 50 | 51 | 如果`__enter__`没有返回值, 那么无法使用as. 52 | ``` 53 | class Person: 54 | def __enter__(self): # 获取资源 55 | print("enter") 56 | 57 | def __exit__(self, exc_type, exc_val, exc_tb): # 释放资源 58 | print("exit") 59 | 60 | def said(self): 61 | print("said") 62 | 63 | 64 | with Person() as P: 65 | P.said() 66 | 67 | >>> AttributeError: 'NoneType' object has no attribute 'said' 68 | ``` 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /第4章 深入类和对象/4-13 contextlib简化上下文管理器.md: -------------------------------------------------------------------------------- 1 | ## contextlib简化上下文管理器 2 | contextmanager可以简化上下文管理器,不需要我们编写`__enter__`和`__exit__`函数。他给了我们一个机会,让我们把之前一个不是上下文管理器的类变成一个上下文管理器,而不需要我们去修改这个类的源代码. 3 | 4 | 其中的yield的作用,是中断当前函数执行流程,先去执行yield出去的部分的代码执行流程 5 | 6 | ``` 7 | import contextlib 8 | 9 | @contextlib.contextmanager 10 | def file_open(file_name): 11 | print ("file open") 12 | yield 13 | print ("file end") 14 | 15 | with file_open("bobby.txt") as f_opened: 16 | print ("file processing") 17 | 18 | 输出: 19 | file open 20 | file processing 21 | file end 22 | ``` 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /第4章 深入类和对象/4-14 本章小结.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/love112358/AdvancePython/cff798a25979b33b9eda4af66698cfe3f78a3822/第4章 深入类和对象/4-14 本章小结.md -------------------------------------------------------------------------------- /第4章 深入类和对象/4-2 抽象基类(abc模块).md: -------------------------------------------------------------------------------- 1 | ## 抽象基类 2 | - 抽象基类是一个虚拟的类, 相当于一个模板, 定义一些方法, 所有继承这个基类的类必须覆盖抽象基类里面的方法 3 | - 抽象基类是无法用来实例化的 4 | 5 | ### 为什么要有抽象基类 6 | 因为python是基于鸭子类型的, 所以其实只要实现某些方法就可以了, 那为什么还要抽象基类呢? 7 | - 第一种用法:我们去检查某个类是否有某一种方法 8 | 9 | 某些情况之下希望判定某个对象的类型, 可以使用`hasattr`判断是否实现某方法或者使用`isinstance`(推荐)去判断一个类是否是指定的类型, `Sized`就是一个实现`__len__`的抽象基类. 10 | ``` 11 | class Company(object): 12 | def __init__(self, employee_list): 13 | self.employee = employee_list 14 | 15 | def __len__(self): 16 | return len(self.employee) 17 | 18 | com = Company(["bobby1","bobby2"]) 19 | print(hasattr(com, "__len__")) 20 | 21 | from collections.abc import Sized 22 | print(isinstance(com, Sized)) 23 | >>> True 24 | 25 | # Sized内部的类方法, 在调用isinstance(com, Sized)时cls就是Sized对象, C就是com对象,然后判断com对象有没有实现__len__方法. 26 | @classmethod 27 | def __subclasshook__(cls, C): 28 | if cls is Sized: 29 | return _check_methods(C, "__len__") 30 | return NotImplemented 31 | 32 | # isinstance还会找到继承链去进行判断 33 | class A: 34 | pass 35 | 36 | class B(A): 37 | pass 38 | 39 | b = B() 40 | print(isinstance(b, A)) 41 | >>> True 42 | ``` 43 | - 第二种用法: 强制某个子类必须实现某些方法 44 | ``` 45 | # 模拟抽象基类, 只有在调用set方法的时候才会抛出异常 46 | class CacheBase(): 47 | def get(self, key): 48 | raise NotImplementedError 49 | def set(self, key, value): 50 | raise NotImplementedError 51 | 52 | class RedisCache(CacheBase): 53 | def set(self, key, value): 54 | pass 55 | 56 | redis_cache = RedisCache() 57 | redis_cache.set("key", "value") 58 | 59 | # 使用abc模块, 在初始化的时候就会去判断有没有重载基类的方法,没有就抛异常 60 | import abc 61 | 62 | class CacheBase(metaclass=abc.ABCMeta): 63 | @abc.abstractmethod 64 | def get(self, key): 65 | pass 66 | 67 | @abc.abstractmethod 68 | def set(self, key, value): 69 | pass 70 | 71 | class RedisCache(CacheBase): 72 | def set(self, key, value): 73 | pass 74 | def get(self, key): 75 | pass 76 | 77 | redis_cache = RedisCache() 78 | ``` 79 | 80 | ### collection.abc模块 81 | 在这个模块中定义了很多通用的抽象基类, 比如Sized. 但是这些抽象基类定义出来并不是用来继承的, 更多的是让我们理解接口的一些定义. 推荐使用鸭子类型或者多继承(Mixin)实现, 而少用抽象基类. 82 | ``` 83 | __all__ = ["Awaitable", "Coroutine", 84 | "AsyncIterable", "AsyncIterator", "AsyncGenerator", 85 | "Hashable", "Iterable", "Iterator", "Generator", "Reversible", 86 | "Sized", "Container", "Callable", "Collection", 87 | "Set", "MutableSet", 88 | "Mapping", "MutableMapping", 89 | "MappingView", "KeysView", "ItemsView", "ValuesView", 90 | "Sequence", "MutableSequence", 91 | "ByteString", 92 | ] 93 | ``` 94 | 95 | ### 声明抽象基类 96 | - metaclass = abc.ABCMeta 97 | - @abc.abstractmethod 98 | 99 | -------------------------------------------------------------------------------- /第4章 深入类和对象/4-4 isinstance和type的区别.md: -------------------------------------------------------------------------------- 1 | ## type与isinstance区别: 2 | 1. type用于求一个未知数据类型的对象,isinstance用于判断一个对象是否是已知类型; 3 | 2. type不认为子类是父类的一种类型,isinstance认为子类是父类的一种类型,即子类对象也属于父类类型. 4 | ``` 5 | class A: 6 | pass 7 | 8 | class B(A): 9 | pass 10 | 11 | b = B() 12 | 13 | # instance用于判断一个对象是否是已知类型 14 | print(isinstance(b, B)) # True 15 | print(isinstance(b, A)) # True isinstance会根据继承链去判断 16 | 17 | # 求一个未知数据类型的对象 18 | print(type(b)) # 19 | 20 | # type不认为子类是父类的一种类型,isinstance认为子类是父类的一种类型,即子类对象也属于父类类型. 21 | 22 | # is是去判断这两个是不是一个对象, 即id是否相同 23 | # ==是判断值是否相等 24 | print(type(b) is B) # True 得到的是B的地址 25 | print(type(b) is A) # False 26 | 27 | print(id(B)) # 1943999460392 28 | print(id(type(b))) # 1943999460392 29 | print(B) # 30 | 31 | a=[1,2,3] 32 | b=[1,2,3] 33 | c=a 34 | 35 | print(id(a)) # 2065494827720 36 | print(id(b)) # 2065493557192 37 | print(id(c)) # 2065494827720 38 | 39 | print(a is b) # False 40 | print(c is a) # True 41 | print((a==b)) # True 42 | ``` -------------------------------------------------------------------------------- /第4章 深入类和对象/4-5 类变量和实例变量.md: -------------------------------------------------------------------------------- 1 | ## 类变量和实例变量 2 | ``` 3 | class A: 4 | aa = 1 # 类变量 5 | def __init__(self, x, y): 6 | self.x = x # 实例变量 7 | self.y = y 8 | 9 | a = A(2,3) 10 | 11 | A.aa = 11 # 会将类A内存中的的aa修改为11 12 | a.aa = 22 # 会在实例a内存中创建一个变量aa赋值22, 类A内存中的aa还是11 13 | print(a.x, a.y, a.aa) # a.aa首先会去实例a的内存中找是否有aa, 如果没有再去类A的内存中找 14 | print(A.aa) # 去类A的内存中找aa, 值为11 15 | 16 | b = A(3,5) 17 | print(b.aa) # 类A内存中aa已经修改为11 18 | 19 | >>> 2 3 22 20 | >>> 11 21 | >>> 11 22 | ``` -------------------------------------------------------------------------------- /第4章 深入类和对象/4-6 类和实例属性的查找顺序—mro查找.md: -------------------------------------------------------------------------------- 1 | ## MRO算法 2 | ### 为什么不单纯使用深度优先或者广度优先 3 | - 深度优先搜寻 4 | 5 | 查找顺序是A->B->D->C, 但是如果C重载了D的某个方法(B没有重载该方法), 由于深度优先所以将会使用D中的方法, 这是不合理的 6 | 7 | ![](http://qiniu.rearib.top/FoNwbOtk2Lb9gNBfQMbTk3SQYP8G) 8 | 9 | - 广度优先 10 | 11 | 查找顺序是A->B->C->D->E, 由于优先级关系, B和D的优先级高于C, 但是如果C和D中定义了同一个方法, 由于广度优先所以将会使用C中的方法, 这是不合理的 12 | 13 | ![](http://qiniu.rearib.top/Fg5VSJjYJjJRJrVawHIfj8PoawGm) 14 | 15 | ### C3算法 16 | ``` 17 | class D: 18 | pass 19 | 20 | class E: 21 | pass 22 | 23 | class C(E): 24 | pass 25 | 26 | class B(D): 27 | pass 28 | 29 | class A(B, C): 30 | pass 31 | 32 | print(A.__mro__) 33 | >>> (, , , , , ) 34 | ``` 35 | ``` 36 | class D: 37 | pass 38 | 39 | class C(D): 40 | pass 41 | 42 | class B(D): 43 | pass 44 | 45 | class A(B, C): 46 | pass 47 | 48 | print(A.__mro__) 49 | >>> (, , , , ) 50 | 51 | ``` 52 | 53 | 54 | -------------------------------------------------------------------------------- /第4章 深入类和对象/4-7 类方法、静态方法和实例方法.md: -------------------------------------------------------------------------------- 1 | ### 实例方法 2 | - 可以访问实例变量和类变量 3 | - 只能实例对象调用 4 | 5 | ### 静态方法 6 | - @staticmethod 7 | - 静态方法是不可以访问实例变量或类变量,不会主动传入self,传入什么参数才能获取到什么参数. 8 | - 可通过实例对象或类对象调用 9 | 10 | ### 类方法 11 | - @classmethod 12 | - 类方法只能访问类变量,不能访问实例变量 13 | - 可通过实例对象或类对象调用 14 | - 需要传入cls参数, cls参数指向的是一开始定义的类对象(不是实例对象) 15 | 16 | ### 对比 17 | 1. 类方法无须创建实例对象调用,所以类方法的调用较实例方法更为灵活 18 | 2. 静态方法有点像附属于类对象的“工具”, 将对象的相关处理逻辑“束缚”在对象体内,这样封装得会更好些。 19 | 3. 实例方法只能通过实例对象调用;类方法和静态方法可以通过类对象或者实例对象调用,如果是使用实例对象调用的类方法或静态方法,最终都会转而通过类对象调用。 20 | 4. 实例方法使用最多,可以直接处理实例对象的逻辑;类方法不需要创建实例对象,直接处理类对象的逻辑;静态方法将与类对象相关的某些逻辑抽离出来,不仅可以用于测试,还能便于代码后期维护。 21 | 5. 实例方法和类方法,能够改变实例对象或类对象的状态,而静态方法不能。 -------------------------------------------------------------------------------- /第4章 深入类和对象/4-8 数据封装和私有属性.md: -------------------------------------------------------------------------------- 1 | ## 私有属性 2 | ``` 3 | # 类中所有双下划线开头的名称如__x都会在类定义时自动变形成:_类名__x的形式 4 | class A(): 5 | __N = 0 6 | _M = 1 # 可以在外部调用, 只是给程序员提示 7 | 8 | def __init__(self): 9 | self.__N = 10 # _A__N 10 | 11 | def read(self): 12 | print(self.__N) 13 | 14 | def __write(self): # _A__write 15 | self.__N = 20 16 | print(self.__N) 17 | 18 | def write(self): 19 | self.__write() # 可以在内部调用 20 | 21 | print(dir(A)) 22 | a = A() 23 | print(a._M) 24 | a.read() 25 | # a.__write() # 无法调用 26 | a.write() 27 | print(a._A__N) # 可以调用 28 | a._A__write() # 可以调用 29 | 30 | ['_A__N', '_A__write', '_M', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'read', 'write'] 31 | 1 32 | 10 33 | 20 34 | 20 35 | 20 36 | ``` -------------------------------------------------------------------------------- /第4章 深入类和对象/4-9 python对象的自省机制.md: -------------------------------------------------------------------------------- 1 | ## python对象的自省机制 2 | 自省是通过一定的机制查询到对象的内部机制, **编程中,自省的能力:检查某些事物以确定它是什么,它知道什么以及它能做什么。** 3 | 4 | - \_\_dict\_\_返回的是字典, dir返回的是列表 5 | - \_\_dict\_\_查看对象的所有属性(可写属性), dir查看类本身的所有属性。 6 | ``` 7 | class Person: 8 | name = "Person_name" 9 | 10 | class Student(Person): 11 | student_name = 'student_name' 12 | def __init__(self, school_name): 13 | self.school_name = school_name 14 | 15 | if __name__ == "__main__": 16 | user = Student("慕课网") 17 | 18 | print(user.__dict__) # 通过__dict__查询属性 19 | print(user.name) 20 | 21 | # 通过user.name可以读取到, 但是通过__dict__无法获取的原因 22 | # name是属于Person的属性, 并不是Student的属性, 但是使用点的时候会向上查找. 23 | >>> {'school_name': '慕课网'} 24 | >>> Person_name 25 | 26 | print(Student.__dict__) 27 | print(Person.__dict__) 28 | >>> {'__module__': '__main__', 'student_name': 'student_name', '__init__': , '__doc__': None} 29 | >>> {'__module__': '__main__', 'name': 'Person_name', '__dict__': , '__weakref__': , '__doc__': None} 30 | 31 | # 通过__dict__赋值 32 | user.__dict__["school_addr"] = "北京市" 33 | print(user.school_addr) 34 | >>> 北京市 35 | 36 | # 通过dir查询属性(只有属性名称) 37 | print(dir(user)) 38 | print(dir(Student)) 39 | print(dir(Person)) 40 | # 公共部分 41 | >>> ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', ] 42 | # 不同部分 43 | >>> ...'__weakref__', 'name', 'school_name', 'student_name'] 44 | >>> ...'__weakref__', 'name', 'student_name'] 45 | >>> ...'__weakref__', 'name'] 46 | ``` 47 | 48 | ## __bases__和issubclass 49 | ``` 50 | class A: 51 | pass 52 | 53 | class B(A): 54 | pass 55 | 56 | class C(B): 57 | pass 58 | 59 | print(C.__bases__) # (,) 60 | print(issubclass(C,B)) # True 61 | print(issubclass(C,A)) # True 62 | ``` -------------------------------------------------------------------------------- /第5章 自定义序列类/5-1 python中的序列分类.md: -------------------------------------------------------------------------------- 1 | ## 序列类型的分类 2 | ``` 3 | # 存储数据类型区别 4 | **容器序列** 5 | list, tuple, deque 6 | **扁平序列** 7 | str, bytes, bytearray, array.array 8 | 9 | # 可变性 10 | **可变序列** 11 | list, deque, bytearray, array 12 | **不可变序列** 13 | str, tuple, bytes 14 | ``` 15 | 16 | - 容器序列(可以放置任意类型数据) 17 | - 扁平序列 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /第5章 自定义序列类/5-2 python中序列类型的abc继承关系.md: -------------------------------------------------------------------------------- 1 | ## 序列类型的协议 2 | 和容器相关的数据结构的抽象基类都在`from collections import abc`这个模块,我们打开`from _collections_abc import all`,在`_collections_abc.py`模块里面可以看到内容如下: 3 | ``` 4 | __all__ = ["Awaitable", "Coroutine", 5 | "AsyncIterable", "AsyncIterator", "AsyncGenerator", 6 | "Hashable", "Iterable", "Iterator", "Generator", "Reversible", 7 | "Sized", "Container", "Callable", "Collection", 8 | "Set", "MutableSet", 9 | "Mapping", "MutableMapping", 10 | "MappingView", "KeysView", "ItemsView", "ValuesView", 11 | "Sequence", "MutableSequence", 12 | "ByteString", 13 | ] 14 | ``` 15 | 咱们只需要关注“Sequence”, “MutableSequence”, Sequence 是不可变序列类型,MutableSequence 是可变序列类型 16 | 17 | ## Sequence 18 | ### Sequence 继承的类 19 | ``` 20 | # 继承了两个类 Reversible, Collection 21 | class Sequence(Reversible, Collection): 22 | # 抽象方法的标识,如果用他必须重写这个方法 23 | @abstractmethod 24 | ``` 25 | Reversible是序列的翻转,例如ABC变成CBA 26 | ``` 27 | class Collection(Sized, Iterable, Container): 28 | # Sized里面有魔法函数__len__,可以计算序列的长度 29 | # Iterable是个迭代对象, 有了它可以进行for循环 30 | # Container里面有魔法函数__contains__,我们就可以用in这个字段,例如 if i in list() 31 | 32 | __slots__ = () 33 | 34 | @classmethod 35 | def __subclasshook__(cls, C): 36 | if cls is Collection: 37 | return _check_methods(C, "__len__", "__iter__", "__contains__") 38 | return NotImplemented 39 | ``` 40 | Sequence的所有魔法函数构成了序列的协议, 打开Sequence类我们可以看到里面重写了所继承的抽象基类的方法,包括`__len__`,`__iter__`和`__contains__`. 41 | 42 | ## MutableSequence 43 | MutableSequence是可变的序列, 他继承了Sequence并新加了一些特性. 如 44 | setitem, delitem, insert, append, clear, reverse, extend, pop, remove, iadd等, 这些都是可变序列的特性. 45 | ``` 46 | class MutableSequence(Sequence): 47 | 48 | __slots__ = () 49 | 50 | """All the operations on a read-write sequence. 51 | 52 | Concrete subclasses must provide __new__ or __init__, 53 | __getitem__, __setitem__, __delitem__, __len__, and insert(). 54 | 55 | """ 56 | 57 | @abstractmethod 58 | def __setitem__(self, index, value): 59 | raise IndexError 60 | 61 | @abstractmethod 62 | def __delitem__(self, index): 63 | raise IndexError 64 | 65 | @abstractmethod 66 | def insert(self, index, value): 67 | 'S.insert(index, value) -- insert value before index' 68 | raise IndexError 69 | ``` 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /第5章 自定义序列类/5-3 list中extend方法区别.md: -------------------------------------------------------------------------------- 1 | ## 序列的+、+=和extend的区别 2 | 这三个都可以把list进行连接 3 | - 区别一: + 和 +=占用空间不一样 4 | 5 | ``` 6 | a=[1,2,3] 7 | b=[4,5,6] 8 | 9 | c=a+b 10 | print(c) # c是产生的新的list 11 | 12 | a+=b 13 | print(a) # a还是原来那个list 14 | ``` 15 | 16 | - 区别二: + 两边的数据类型要一致 17 | ``` 18 | a=[1,2,3] 19 | b=(4,5,6) 20 | 21 | a+=b 22 | print(a) # a = [1, 2, 3, 4, 5, 6] 23 | 24 | c=a+b 25 | 26 | # TypeError: can only concatenate list (not "tuple") to list 27 | print(c) 28 | ``` 29 | 原因是因为+=是调用`MutableSequence`中的`__iadd__`, 它是调用`extend`, 接收一个`iterable`并通过for循环append. 30 | 31 | - entend和append的区别 32 | ``` 33 | a=[1,2,3] 34 | b=(4,5,6) 35 | 36 | a.extend((9,10)) # 利用for循环内的append进行连接 37 | print(a) 38 | 39 | a.append(b) # 直接连接的是整体不会拆开合并 40 | print(a) 41 | 42 | 输出: 43 | [1, 2, 3, 9, 10] 44 | [1, 2, 3, 9, 10, (4, 5, 6)] 45 | ``` 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /第5章 自定义序列类/5-4 实现可切片的对象.md: -------------------------------------------------------------------------------- 1 | ## 切片神操作,你会多少? 2 | 首先先讲下切片的公式, 模式[start : end : step] 3 | 1. start是切片的起始位置, 不填默认为0 4 | 2. end是切片的截至位置, 不填默认为列表的长度 5 | 3. step是切片的跨度, 也就是切片跳跃的长度,官方说法是步长,如果不指定值就是默认是1 6 | 7 | ### 切片取值 8 | - 对列表进行切片操作是会返回一个新的列表 9 | ``` 10 | alist=[1,2,3,4,5,6,7,8,9] 11 | print(alist[::]) # 打印全部 12 | >>> [1, 2, 3, 4, 5, 6, 7, 8, 9] 13 | print(alist[:]) # 打印全部 14 | >>> [1, 2, 3, 4, 5, 6, 7, 8, 9] 15 | print(alist[::-1]) # 对列表进行反转 16 | >>> [9, 8, 7, 6, 5, 4, 3, 2, 1] 17 | print(alist[1::2]) # 取奇数 18 | >>> [2, 4, 6, 8] 19 | print(alist[::2]) # 取偶数 20 | >>> [1, 3, 5, 7, 9] 21 | print(alist[1:4]) # 取列表位置1到4(不包括4的位置) 22 | >>> [2, 3, 4] 23 | print(alist[1:100]) # 如果截至位置大于列表长度取列表的长度。 24 | >>> [2, 3, 4, 5, 6, 7, 8, 9] 25 | print(alist[100:]) # 如果起始位置大于列表长度取值为空 26 | >>> [] 27 | ``` 28 | 29 | ### 切片赋值 30 | ``` 31 | alist=[1,2,3,4,5,6,7,8,9] 32 | print(len(alist)) # 打印长度 33 | >>> 9 34 | print(alist[0]) # 取第0个元素 35 | >>> 1 36 | alist[len(alist):]=[10] # 在尾部增加列表 37 | alist[:0]=[0] # 在开始位置前增加列表 38 | print(alist) 39 | >>> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 40 | print(alist[2:2]) # 空值 41 | >>> [] 42 | alist[2:2]=[3.3] # 在第3位置插入列表 43 | print(alist) 44 | >>> [0, 1, 3.3, 2, 3, 4, 5, 6, 7, 8, 9, 10] 45 | alist[:8]=[12] # 前8个元素全变成[12] 46 | print(alist) 47 | >>> [12, 7, 8, 9, 10] 48 | alist[2:]=[13] # 从第三个位置到结尾变成[13] 49 | print(alist) 50 | >>> [12, 7, 13] 51 | 52 | alist=[1,2,3,4,5,6,7,8,9] 53 | alist[::2]=[0]*5 # 偶数前5个为修改成0, 左边要修改的数量和右边的数量要相等,如果不等就报错 54 | print(alist) 55 | >>> [0, 2, 0, 4, 0, 6, 0, 8, 0] 56 | 57 | alist=[1,2,3,4,5,6,7,8,9] 58 | alist[:3]=[] # 删除前三个元素 59 | print(alist) 60 | >>> [4, 5, 6, 7, 8, 9] 61 | del alist[:3] # 用del删除前三个 62 | print(alist) 63 | >>> [7, 8, 9] 64 | alist=[1,2,3,4,5,6,7,8,9] 65 | del alist[::2] # 奇数位置都要删除 66 | print(alist) 67 | >>> [2, 4, 6, 8] 68 | ``` 69 | 70 | ## 编写一个不可变的序列类 71 | 之前提到的`Sequence`就是一个不可变序列的抽象基类, 所以我们只要实现了它内部的魔法函数, 就能实现一个不可变的序列类. 72 | ``` 73 | from collections import Sequence 74 | 75 | class Group(Sequence): 76 | def __init__(self, group_name, staffs): 77 | self.group_name = group_name 78 | self.staffs = staffs 79 | 80 | def __getitem__(self, item): 81 | pass 82 | 83 | def __len__(self): 84 | return len(self.staffs) 85 | 86 | group = Group(group_name='user', staffs=['rib1', 'rib2', 'rib3']) 87 | 88 | print(group[1]) 89 | 90 | ``` 91 | 首先根据源码可知我们必须实现`__getitem__`和`__len__`, 我们来好好研究一下`__getitem__`这个魔法函数. 92 | 如果是group[1], 那么item是int(1), 如果group[:2], 那么item是一个`slice(None, 2, None)`, 所以我们可以通过item进行切片返回. 93 | ``` 94 | def __getitem__(self, item): 95 | return self.staffs[item] 96 | ``` 97 | 但是如果想返回的还是Group对象: 98 | ``` 99 | return Group(group_name='user',staffs = self.staffs[item]) 100 | ``` 101 | 但是Group直接写死了不好, 因为是通过group调用, 所以self指向group对象, 而且传入的是int的时候我们需要返回[]: 102 | ``` 103 | def __getitem__(self, item): 104 | cls = type(self) 105 | if isinstance(item, slice): 106 | return cls(group_name='user',staffs = self.staffs[item]) 107 | if isinstance(item, int): 108 | return cls(group_name='user',staffs = [self.staffs[item]]) 109 | ``` 110 | 同理我们如果还需要实现其他功能: 111 | ``` 112 | def __reversed__(self): 113 | self.staffs.reverse() 114 | 115 | def __iter__(self): 116 | return iter(self.staffs) 117 | 118 | def __contains__(self, item): 119 | if item in self.staffs: 120 | return True 121 | else: 122 | return False 123 | 124 | >>> reversed(group) 125 | >>> print('rib1' in group) 126 | ``` 127 | 128 | 129 | -------------------------------------------------------------------------------- /第5章 自定义序列类/5-5 bisect维护已排序序列.md: -------------------------------------------------------------------------------- 1 | ## 序列 2 | - 首先需要有序列的概念, list只是序列的一种 3 | 4 | ## bisect用于维护已排序序列 5 | - 使用bisect插入数据会将数据按顺序排序(升序) 6 | - bisect利用二分查找来维护排序序列 7 | 8 | ``` 9 | import bisect 10 | 11 | inter_list = [] 12 | bisect.insort(inter_list, 3) 13 | bisect.insort(inter_list, 2) 14 | bisect.insort(inter_list, 5) 15 | bisect.insort(inter_list, 1) 16 | bisect.insort(inter_list, 6) 17 | print(inter_list) 18 | >>> [1, 2, 3, 5, 6] 19 | 20 | print(bisect.insort_left(inter_list, 4)) 21 | >>> None 22 | print(inter_list) 23 | >>> [1, 2, 3, 4, 5, 6] 24 | print(bisect.insort_left(inter_list, 3.0)) 25 | print(inter_list) 26 | [1, 2, 3.0, 3, 4, 5, 6] 27 | ``` 28 | 其中默认插入是右边插入`insort = insort_right` 29 | 30 | - 查找将会插入的位置 31 | ``` 32 | inter_list = [1, 2, 3.0, 3, 4, 5, 6] 33 | print(bisect.bisect(inter_list,2.0)) 34 | >>> 2 35 | ``` 36 | 其中默认插入是右边插入`bisect = bisect_right` -------------------------------------------------------------------------------- /第5章 自定义序列类/5-6 什么时候我们不该使用列表.md: -------------------------------------------------------------------------------- 1 | ## array 2 | 前面在序列分类的时候提到了一种array类型, 它其实是C语言中的数组, 与list主要有如下区别: 3 | - array只能存放指定的数据类型 4 | - array的数据在内存中是连续的 5 | - array的效率和性能会比list更高 6 | 7 | ``` 8 | import array 9 | 10 | my_array = array.array("i") 11 | my_array.append(1) 12 | my_array.append(2) 13 | 14 | print(my_array) 15 | 16 | >>> array('i', [1, 2]) 17 | ``` 18 | 19 | 在官方文档中可以查看array的声明方式 20 | - [官方文档](https://docs.python.org/zh-cn/3/library/array.html?highlight=array#module-array) -------------------------------------------------------------------------------- /第5章 自定义序列类/5-7 列表推导式、生成器表达式、字典推导式.md: -------------------------------------------------------------------------------- 1 | ## 列表推导式, 生成器表达式, 字典推导式 2 | - 简单的for循环都可以用推导式进行完成,性能高比较高,但是如果场景过于复杂就不要用,可读性要排在第一位. 3 | 4 | ``` 5 | # 列表生成式的性能高于列表操作 6 | list1 = [i for i in range(20) if i % 2 == 1] 7 | list2 = [i * i for i in range(10)] 8 | print(list1) 9 | print(list2) 10 | 11 | # 生成器表达式 12 | gen1 = (i for i in range(20) if i % 2 == 1) 13 | print(type(gen1)) 14 | list3 = list(gen1) 15 | print(list3) 16 | 17 | # 字典推导式 18 | b={"boby1":30,"boby2":60} 19 | dict={value:(key+1) for value,key in b.items() } 20 | print(dict) 21 | 22 | # 集合推导式 23 | my_set =set(my_dictkeys()) 24 | my_set ={key for key,value in my_dict.items()} 25 | print(type(my_set)) 26 | print(my_set) 27 | ``` 28 | -------------------------------------------------------------------------------- /第5章 自定义序列类/5-8本章小结.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/love112358/AdvancePython/cff798a25979b33b9eda4af66698cfe3f78a3822/第5章 自定义序列类/5-8本章小结.md -------------------------------------------------------------------------------- /第6章 深入python的set和dict/6-1 dict的abc继承关系.md: -------------------------------------------------------------------------------- 1 | ## dict 2 | 通过抽象基类来理解python中dict的继承关系, 3 | ``` 4 | __all__ = ["Awaitable", "Coroutine", 5 | "AsyncIterable", "AsyncIterator", "AsyncGenerator", 6 | "Hashable", "Iterable", "Iterator", "Generator", "Reversible", 7 | "Sized", "Container", "Callable", "Collection", 8 | "Set", "MutableSet", 9 | "Mapping", "MutableMapping", 10 | "MappingView", "KeysView", "ItemsView", "ValuesView", 11 | "Sequence", "MutableSequence", 12 | "ByteString", 13 | ] 14 | ``` 15 | dict其实是属于`MutableMapping`, 它继承`Mapping`, `Mapping`继承`Collection`, 里面包括`__len__`,`__iter__`, `__contains__`, 所以dict和序列有很多接近的地方. 16 | 17 | a是一个dict对象, 它并不是继承了`MutableMapping`, 而是实现了`MutableMapping`中的方法和魔法函数. 18 | ``` 19 | from collections.abc import Mapping, MutableMapping 20 | #dict属于mapping类型 21 | 22 | a = {} 23 | print (isinstance(a, MutableMapping)) 24 | >>> True 25 | ``` 26 | 27 | -------------------------------------------------------------------------------- /第6章 深入python的set和dict/6-2 dict的常用方法.md: -------------------------------------------------------------------------------- 1 | ## dict的常用操作 2 | - clear 3 | 4 | clear的功能是对dict的内容进行清除.没有任何的返回值 5 | ``` 6 | a={"person1":{"Andy":30},"person12":{"Lady":45}} 7 | a.clear() 8 | print(a) 9 | >>> {} 10 | ``` 11 | 12 | - 浅copy和深copy 13 | 14 | - fromkeys 15 | new_list = ["bobby1",'bobby2'] 16 | mew_dict = dicet.fromkeys(new_list,{"company":"imooc"}) 17 | 首先这是一个静态方法, 可以直接使用类名调用 18 | ``` 19 | @staticmethod # known case 20 | def fromkeys(*args, **kwargs): # real signature unknown 21 | """ Returns a new dict with keys from iterable and values equal to value. """ 22 | pass 23 | ``` 24 | ``` 25 | a=["person1","person2"] 26 | 27 | b=dict.fromkeys(a,"company") 28 | print(b) 29 | >>> {'person1': 'company', 'person2': 'company'} 30 | ``` 31 | 32 | - get 33 | 34 | 解决key没有对应的value报错的问题 35 | ``` 36 | print(a.get("person",{})) 37 | ``` 38 | 39 | - items, keys, values 40 | for key,value in new_dict.items(): 41 | print(key) 42 | 取值 43 | 44 | - pop,popitem 45 | 46 | 删除并返回 47 | 48 | - setdefault 49 | 50 | 如果key存在使用get方法, 如果key不存在使用set方法 51 | default_value=new_dict.setdefault("bobby","imooc") 52 | 53 | - update 54 | 两个字典合并 55 | ``` 56 | a={"person1":{"Andy":30},"person12":{"Lady":45}} 57 | b={"person1":{"Andy":40},"person20":{"Lady":80}} 58 | print(b.update(a)) # 没有返回值 59 | >>> None 60 | print(b) # 如果key重复, 使用a的value 61 | >>> {'person1': {'Andy': 30}, 'person20': {'Lady': 80}, 'person12': {'Lady': 45}} 62 | ``` 63 | -------------------------------------------------------------------------------- /第6章 深入python的set和dict/6-3 dict的子类.md: -------------------------------------------------------------------------------- 1 | ## dict的子类 2 | ### UserDict 3 | dict是一个类, 我们就可以尝试继承它: 4 | ``` 5 | class My_dict(dict): 6 | def __setitem__(self, key, value): 7 | super().__setitem__(key,value*value) 8 | 9 | a=My_dict(one=2) 10 | print(a["one"]) 11 | >>> 2 12 | ``` 13 | 发现值没有变化, 我们去查看dict的源码, 并没有实现`__setitem__`, 这个方法没有做任何处理,并不适用继承: 14 | ``` 15 | def __setitem__(self, *args, **kwargs): # real signature unknown 16 | """ Set self[key] to value. """ 17 | pass 18 | ``` 19 | 这个时候我们需要继承UserDict, 它是继承于`MutableMapping`: 20 | ``` 21 | from collections import UserDict 22 | class My_dict(UserDict): 23 | def __setitem__(self, key, value): 24 | super().__setitem__(key,value*value) 25 | 26 | a=My_dict(one=2) 27 | print(a["one"]) 28 | >>> 4 29 | ``` 30 | 在UserDict的源码中是实现了: 31 | ``` 32 | def __setitem__(self, key, item): self.data[key] = item 33 | ``` 34 | 所以如果需要继承dict, 我们应该去继承UserDict. 我们可以理解为dict是使用c语言去实现, 而UserDict是使用python语言去实现了一遍dict. 35 | 36 | ### defaultdict 37 | defaultdict是dict的一个子类, 38 | 39 | 我们来看一下`UserDict`中的`__getitem__`的: 40 | ``` 41 | def __getitem__(self, key): 42 | if key in self.data: 43 | return self.data[key] 44 | if hasattr(self.__class__, "__missing__"): 45 | return self.__class__.__missing__(self, key) 46 | raise KeyError(key) 47 | ``` 48 | 如果key不存在就查看有没有`__missing__`, 如果有就调用该方法, 而在`defaultdict`中重载了该方法. 49 | ``` 50 | def __missing__(self, key): # real signature unknown; restored from __doc__ 51 | """ 52 | __missing__(key) # Called by __getitem__ for missing key; pseudo-code: 53 | if self.default_factory is None: raise KeyError((key,)) 54 | self[key] = value = self.default_factory() 55 | return value 56 | """ 57 | pass 58 | ``` 59 | 使用: 60 | ``` 61 | from collections import defaultdict 62 | 63 | my_dict = defaultdict(dict) 64 | my_value = my_dict["bobby"] 65 | >>> defaultdict(, {'bobby': {}}) 66 | 67 | fruit=["apple","banana","orange"] 68 | v=defaultdict(int) 69 | for i in fruit: 70 | v[i]+=1 71 | print(v) 72 | >>> defaultdict(, {'default_factory': 0, 'apple': 1, 'banana': 1, 'orange': 1}) 73 | ``` 74 | -------------------------------------------------------------------------------- /第6章 深入python的set和dict/6-4 set和frozenset.md: -------------------------------------------------------------------------------- 1 | ## set 和 frozenset的应用场景及区别 2 | - set是集合,frozenset是不可变集合。 3 | - set最大的特性是不重合,在去重的时候用的最多。 4 | - set是无序的 5 | - set的性能比较高, 因为他用到了哈希编码 6 | ``` 7 | def __init__(self, seq=()): # known special case of set.__init__ 8 | """ 9 | set() -> new empty set object 10 | set(iterable) -> new set object 11 | 12 | Build an unordered collection of unique elements. 13 | # (copied from class doc) 14 | """ 15 | pass 16 | ``` 17 | set初始化是接收一个可迭代对象, 比如str, list, dict, tuple... 18 | 19 | set的另一种初始化方式是{'a','b','c'} 20 | 21 | ### frozenset 22 | 不可变集合是无法修改的, 可以作为dict的key 23 | ``` 24 | a={"a","b","c"} 25 | a.add("d") # 正常 26 | 27 | a=frozenset("abcd") 28 | a.add("d") # 报错 29 | ``` 30 | 31 | ### 常用方法 32 | - update 方法 33 | ``` 34 | a=set("abc") 35 | a.update("bcd") # 取的是总集 36 | print(a) 37 | >>> {'b', 'd', 'a', 'c'} 38 | ``` 39 | - 集合运算(|,&,-) 40 | ``` 41 | a=set("abc") 42 | b=set("bcd") 43 | print(a - b) # 对a进行去重 44 | print(a | b) # 并集 45 | print(a & b) # 交集 46 | 47 | {'a'} 48 | {'c', 'b', 'd', 'a'} 49 | {'c', 'b'} 50 | ``` 51 | 原理是调用了相应的魔法函数 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /第6章 深入python的set和dict/6-5 dict和set的实现原理.md: -------------------------------------------------------------------------------- 1 | ##advancepython_resource 项目 2 | ## 效率 3 | - dict查找的性能远远大于list 4 | - 在list中查找元素时间会随着list的增大而增大 5 | - 在dict中查找元素时间不会随着dict的增大而增大 6 | 7 | - 哈希表 8 | 9 | ![](http://qiniu.rearib.top/FkAaL7P2cDUdEPyd812DzGZLAGMC) 10 | 11 | - 哈希表查找 12 | 13 | ![](http://qiniu.rearib.top/FgfZpFaH8FB0mtw5sHchevL0TrUA) 14 | 15 | 16 | 1. dict的key或者set的值都必须是可以hash的 17 | 2. 不可变对象都是可hash的, str,fronzenset,tuple 18 | 3. 自己实现的类使用魔法函数`__hash__`实现哈希 19 | 4. dict的内存花销大,但是查询速度快,自定义的对象或者python内部的对象都是用dict包装的 20 | 5. dict的存储顺序和元素添加顺序有关 21 | 6. 添加数据有可能改变已有数据的顺序, 最开始会申请内存, 然后随着数据的不断添加, 当剩余空间小于三分之一的时候会申请新的内存然后进行数据迁移, 这个时候存储顺序可能会发生改变. 22 | -------------------------------------------------------------------------------- /第6章 深入python的set和dict/6-6 本章小结.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/love112358/AdvancePython/cff798a25979b33b9eda4af66698cfe3f78a3822/第6章 深入python的set和dict/6-6 本章小结.md -------------------------------------------------------------------------------- /第7章 对象引用、可变性和垃圾回收/7-1 python中的变量是什么.md: -------------------------------------------------------------------------------- 1 | ## python中的变量 2 | - python是动态语言, 变量是没有类型的 3 | - java中声明变量是需要指定类型, 然后虚拟机根据类型申请空间, 但是python的变量实质是指针(首先生成对象然后指针指向对象) 4 | ``` 5 | # 不可变类型 6 | a = 1 7 | b = 1 8 | print(id(a)) 9 | print(id(b)) # 相等 10 | 首先实例化一个int对象1, 然后将变量a指向这个对象, 然后将变量b指向对象1,a和b指向的是同一个对象 11 | 12 | # 可变类型 13 | a=[1,2,3] 14 | b=[1,2,3] 15 | print(id(a)) 16 | print(id(b)) # 不相等 17 | 首先实例化一个list对象, 然后将a指向该对象, 然后再实例化一个list对象将b指向该对象, a和b指向的是不同的对象 18 | 19 | # 可变类型 20 | a=[1,2,3] 21 | b=a 22 | print(id(a)) 23 | print(id(b)) # 相等 24 | 首先实例化一个list对象, 然后将a指向该对象, 然后将a赋值给b, a和b指向的是相同的对象 25 | ``` 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /第7章 对象引用、可变性和垃圾回收/7-2 ==和is的区别.md: -------------------------------------------------------------------------------- 1 | ## == 和 is的区别 2 | - is也被叫做同一性运算符,这个运算符比较判断的是对象间的唯一身份标识,也就是id是否相同 3 | - ==是利用魔法函数`__eq__`, 用来比较判断两个对象的value(值)是否相等 -------------------------------------------------------------------------------- /第7章 对象引用、可变性和垃圾回收/7-3 del语句和垃圾回收.md: -------------------------------------------------------------------------------- 1 | ## Python的垃圾回收机制 2 | - 垃圾回收机制算法采用的是**引用计数** 3 | ``` 4 | a=[1,2,3] # 声明变量后,引用计数 +1 5 | b=a # 增加一个引用,引用计数 +1 6 | c=b # 增加一个引用,引用计数 +1 7 | del a # 删除a这个指针,引用计数 -1 8 | ``` 9 | 当计数器保存的值为0的时候,也就是意味着没有任何指针指向这块存储。解释器开始清除这块没有任何指针的存储。 10 | 11 | ## 垃圾回收魔法函数 12 | `__del__`可以添加该对象被垃圾回收时的逻辑. 13 | ``` 14 | class A: 15 | def __del__(self): 16 | print("开始回收了") 17 | 18 | a=A() 19 | b=a 20 | c=b 21 | 22 | del a 23 | del b 24 | del c 25 | >>> 开始执行`del c`时打印`开始回收了` 26 | ``` 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /第7章 对象引用、可变性和垃圾回收/7-4 一个经典的参数错误.md: -------------------------------------------------------------------------------- 1 | ## 经典参数传递错误 2 | ### 传入int值 3 | ``` 4 | def add(a,b): 5 | a+=b 6 | return a 7 | a=1 8 | b=2 9 | c=add(a,b) 10 | 11 | print(a,b,c) 12 | >>> 1 2 3 13 | ``` 14 | 15 | ### 传入list 16 | ``` 17 | def add(a,b): 18 | a+=b 19 | return a 20 | a=[1] 21 | b=[2] 22 | c=add(a,b) 23 | 24 | print(a,b,c) 25 | >>> [1, 2] [2] [1, 2] 26 | ``` 27 | 内部使用的是+=, 所以内存地址不变, 所以在执行`a+=b`的前后a指向的是同一个地址, 只不过地址里面的内容发生改变. 28 | 29 | ### 传入元组 30 | ``` 31 | def add(a,b): 32 | a+=b 33 | return a 34 | a=(1) 35 | b=(2) 36 | c=add(a,b) 37 | 38 | print(a,b,c) 39 | >>> 1 2 3 40 | ``` 41 | 42 | ``` 43 | class Company: 44 | def __init__(self,name,staffs=[]): 45 | self.name= name 46 | self.staffs = staffs 47 | def add(self,staff_name): 48 | self.staffs.append(staff_name) 49 | def remove(self,staff_name): 50 | self.staffs.remove(staff_name) 51 | if __name__=="__main__": 52 | com1 = Company("com1",["bobby1",bobby2]) 53 | com1.add("bobby3") 54 | com1.remove("bobby1") 55 | print(com1.staffs) 56 | com2 = Company(""com2) 57 | com2.add("bobby") 58 | print(com2.staffs) 59 | com3 =Company("com3") 60 | com3.add("bobby5") 61 | print(com2.staffs) 62 | print(com3.staffs) 63 | print(com2.staffs is com3.staffs) 64 | print(Company.__init__.defaults__) 65 | ### 总结 66 | 在**传入参数为列表等可变序列**时要注意传入参数有可能在函数内部被改变. 67 | -------------------------------------------------------------------------------- /第7章 对象引用、可变性和垃圾回收/7-5 本章小结.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/love112358/AdvancePython/cff798a25979b33b9eda4af66698cfe3f78a3822/第7章 对象引用、可变性和垃圾回收/7-5 本章小结.md -------------------------------------------------------------------------------- /第8章 元类编程/8-1 property动态属性.md: -------------------------------------------------------------------------------- 1 | ## 模块的导入 2 | ``` 3 | from datetime import date, datetime 4 | class User: 5 | def __init__(self, name, birthday): 6 | self.name = name 7 | self.birthday = birthday 8 | 9 | user = User("bobby", date(year=1987, month=1, day=1)) 10 | print ("in {} file" . format(__file__)) 11 | 12 | # 在另一个py文件中导入User类, 连同print也一起被执行了 13 | from chapter08.text import User 14 | ``` 15 | 16 | ## property装饰器(属性方法) 17 | 现在假如一个类有年龄属性, 我们需要设置值并能获取值 18 | - 方法一: 在`__init__()`中设置age, 但是问题是对于赋值无法添加处理或者校验 19 | ``` 20 | class Student: 21 | def __init__(self,name,age): 22 | self.name=name 23 | self.age=age 24 | stu = Student('Tom', 12) 25 | stu.age = 20 26 | ``` 27 | - 方法二: 使用set_age和get_age 28 | ``` 29 | class Student: 30 | def __init__(self, name): 31 | self.name = name 32 | 33 | def set_age(self,age): 34 | if isinstance(age,int): 35 | if 0>> AttributeError: 'A' object has no attribute 'age' 12 | ``` 13 | ``` 14 | class A: 15 | def __init__(self): 16 | pass 17 | def __getattr__(self, item): 18 | print("即使你没有属性也不会报错") 19 | 20 | a=A() 21 | print(a.age) 22 | >>> 即使你没有属性也不会报错 23 | >>> None 24 | ``` 25 | 作用: 我们可以指定在找不到该属性的时候实现的操作, 比如修改查找的名称, 重新指定查找的区域等 26 | 27 | ### \_\_getattribute__ 28 | 执行查找, 无条件进入该魔法函数, 即使所查找的属性不存在 29 | ``` 30 | ### 31 | class User: 32 | def __init__(self,info ={}): 33 | self.info = info 34 | def __getattr__(self,item): 35 | return self.info[item] 36 | # def __getattribute__(self,item): 37 | # return "bobby 38 | if __name__=="__main__": 39 | user = User(info={"company_name":"imooc","name":bobby}) 40 | 41 | ``` 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /第8章 元类编程/8-3 属性描述符和属性查找过程.md: -------------------------------------------------------------------------------- 1 | ## 属性描述符 2 | 前面提到的age在输入的时候需要校验, 实现是通过property的setter, 但是如果很多输入字段那么就要写很多重复的代码.这里就要用到属性描述符 3 | ``` 4 | # 一个对象只要实现__get__、__set__或者__delete__就是一个属性描述符对象 5 | class IntField: 6 | # 数据描述符 7 | def __get__(self, instance, owner): 8 | return self.value 9 | def __set__(self, instance, value): 10 | if not isinstance(value, numbers.Integral): 11 | raise ValueError("int value need") 12 | if value < 0: 13 | raise ValueError("positive value need") 14 | self.value = value 15 | def __delete__(self, instance): 16 | pass 17 | 18 | class NonDataIntField: 19 | # 非数据属性描述符 20 | def __get__(self, instance, owner): 21 | return self.value 22 | 23 | class User: 24 | age = IntField() # age本来是个对象,放在类里当作了User类属性 25 | 26 | user = User() 27 | user.age = 12 # 会进入IntField的__set__ 28 | 29 | instance 30 | >>> <__main__.User object at 0x00000259359F9128> 31 | self 32 | >>> <__main__.IntField object at 0x00000259359F9E48> 33 | ``` 34 | 35 | ### user.age的查找顺序 36 | - 如果user是某个类的实例,那么`user.age`(以及等价的`getattr(user,’age’)`) 37 | - 首先调用`__getattribute__`, 如果在`__getattribute__`找不到属性就会抛出`AttributeError` 38 | - 如果类定义了`__getattr__`方法,在抛出`AttributeError`的时候就会调用到`__getattr__` 39 | - 而对于描述符`__get__`的调用,则是发生在`__getattribute__`内部的。 40 | 41 | ------ 42 | user = User(), 那么user.age 顺序如下: 43 | 1. 如果“age”是出现在User或其基类的`__dict__`中,且age是data descriptor,那么调用其`__get__`方法 44 | 2. 如果“age”出现在user(对象)的`__dict__`中, 那么直接返回 `obj.__dict__[‘age’]` 45 | 3. 如果“age”出现在User(类)或其基类的`__dict__`中 46 | - 如果age是non-data descriptor,那么调用其`__get__`方法 47 | - 返回`__dict__[‘age’]` 48 | 4. 如果User有`__getattr__`方法,调用`__getattr__`方法,否则 49 | 5. 抛出AttributeError 50 | 51 | - 类的静态函数、类函数、普通函数、全局变量以及一些内置的属性都是放在类.__dict__里的 52 | - 对象.__dict__中存储了一些self.xxx的一些东西 53 | 54 | ``` 55 | import numbers 56 | 57 | class IntField: 58 | #数据描述符 59 | def __get__(self, instance, owner): 60 | return self.value 61 | def __set__(self, instance, value): 62 | if not isinstance(value, numbers.Integral): 63 | raise ValueError("int value need") 64 | if value < 0: 65 | raise ValueError("positive value need") 66 | self.value = value 67 | def __delete__(self, instance): 68 | pass 69 | 70 | class User: 71 | age = IntField() 72 | 73 | 74 | if __name__ == "__main__": 75 | user = User() 76 | # user.age = 30 # 进入数据描述符的__set__ 77 | # setattr(user, 'age',18) # 进入数据描述符的__get__ 78 | # print(user.age) # 进入数据描述符的__get__ 79 | user.__dict__["age"] = 18 80 | print(user.__dict__["age"]) 81 | 82 | user.__dict__["age"] = 18 83 | print(user.age) 84 | >>> 'IntField' object has no attribute 'value' 85 | ``` 86 | 87 | ``` 88 | class User: 89 | age = 1 90 | 91 | if __name__ == "__main__": 92 | user = User() 93 | user.name = 30 # 保存在user对象的内存中 94 | print(user.name) # 从user对象的内存中去取 95 | user.age = 30 # 保存在user对象的内存中, 不影响类的内存中的值 96 | print(user.age) # 进入数据描述符的__get__ 97 | user.__dict__["age"] = 18 98 | print(user.__dict__["age"]) 99 | print (user.__dict__) 100 | ``` 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /第8章 元类编程/8-4 __new__和__init__的区别.md: -------------------------------------------------------------------------------- 1 | ## __new__和__init__魔法函数区别 2 | - \_\_new\_\_的功能是在生成对象之前所做的动作, 接受的参数是cls 类 3 | - \_\_init\_\_是在对象生成之后完善对象的属性, 它接受的是self 对象 4 | - 对象生成是在new里面return(返回一个对象) 5 | ``` 6 | class User: 7 | def __new__(cls, *args, **kwargs): 8 | print("new") 9 | # return super().__new__(cls) 创建并返回一个类对象 10 | 11 | def __init__(self,name): 12 | self.name=name 13 | print("init") 14 | 15 | user=User() 16 | >>> new 17 | print(type(user)) 18 | >>> 19 | cls 20 | >>> 21 | ``` 22 | 在执行user = User时, 首先调用User类中的\_\_new\_\_, 其中cls就是User类, 然后继承父类object的中\_\_new\_\_将创建并返回一个类对象, 然后再执行\_\_init\_\_完善对象属性. 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /第8章 元类编程/8-5 自定义元类.md: -------------------------------------------------------------------------------- 1 | ## 创建类的方法 2 | ### Type动态创建类 3 | ``` 4 | Company=type(“类名称”,(继承的基类),{类的属性 }) 5 | 6 | class Baseclass: 7 | def say(self): 8 | print("basecalss say") 9 | 10 | # 要有self 11 | def run(self): 12 | return "i am running" 13 | 14 | Company=type("Company",(Baseclass, ),{"name":"ebaotech","Adress":"杨浦区","run":run}) 15 | co=Company() 16 | print(co.name, co.Adress, co.run()) 17 | co.say() 18 | 19 | >>> ebaotech 杨浦区 i am running 20 | >>> basecalss say 21 | ``` 22 | **元类就是创建类的类, 刚才的type就是一个元类.** 23 | 24 | ### 自定义元类 25 | ``` 26 | # 控制User类实例化的过程 27 | class Metaclass(type): 28 | def __new__(cls, *args, **kwargs): 29 | return super().__new__(cls, *args, **kwargs) 30 | 31 | class User(metaclass=Metaclass): 32 | pass 33 | ``` 34 | 35 | ``` 36 | class Foo(Bar): 37 | pass 38 | ``` 39 | 创建Foo会先寻找Foo中有`__metaclass__`这个属性吗?如果是,Python会在内存中通过`__metaclass__`创建一个名字为Foo的类对象。如果Python没有找到`__metaclass__`,它会继续在Bar(父类)中寻找`__metaclass__`属性,并尝试做和前面同样的操作。如果Python在任何父类中都找不到`__metaclass__`,它就会在模块层次中去寻找`__metaclass__`,并尝试做同样的操作。如果还是找不到`__metaclass__`,Python就会用内置的type来创建这个类对象。 40 | 41 | - 之前写抽象接口就使用了metaclass=ABCMeta, 其实在ABCMeta里面就是重写了\_\_new\_\_方法. 然后再\_\_new\_\_里面检查被标记为@abstractmethod的方法有没有重载. 42 | 43 | ## 参考 44 | - [深刻理解Python中的元类(metaclass)](http://blog.jobbole.com/21351/) 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /第8章 元类编程/8-6 通过元类实现orm.md: -------------------------------------------------------------------------------- 1 | ## 学习Django中ORM的实现 2 | - 创建类的时候对min_value, max_value等进行检查, 在__init__中 3 | - 对类赋值的时候对min_value, max_value等进行检查, 在__get__中 4 | ``` 5 | import numbers 6 | 7 | class Field: 8 | pass 9 | 10 | class IntField(Field): 11 | # 数据描述符 12 | def __init__(self, db_column, min_value=None, max_value=None): 13 | self._value = None 14 | self.min_value = min_value 15 | self.max_value = max_value 16 | self.db_column = db_column 17 | if min_value is not None: 18 | if not isinstance(min_value, numbers.Integral): 19 | raise ValueError("min_value must be int") 20 | elif min_value < 0: 21 | raise ValueError("min_value must be positive int") 22 | if max_value is not None: 23 | if not isinstance(max_value, numbers.Integral): 24 | raise ValueError("max_value must be int") 25 | elif max_value < 0: 26 | raise ValueError("max_value must be positive int") 27 | if min_value is not None and max_value is not None: 28 | if min_value > max_value: 29 | raise ValueError("min_value must be smaller than max_value") 30 | 31 | def __get__(self, instance, owner): 32 | return self._value 33 | 34 | def __set__(self, instance, value): 35 | if not isinstance(value, numbers.Integral): 36 | raise ValueError("int value need") 37 | if value < self.min_value or value > self.max_value: 38 | raise ValueError("value must between min_value and max_value") 39 | self._value = value 40 | 41 | 42 | class CharField(Field): 43 | def __init__(self, db_column, max_length=None): 44 | self._value = None 45 | self.db_column = db_column 46 | if max_length is None: 47 | raise ValueError("you must spcify max_lenth for charfiled") 48 | self.max_length = max_length 49 | 50 | def __get__(self, instance, owner): 51 | return self._value 52 | 53 | def __set__(self, instance, value): 54 | if not isinstance(value, str): 55 | raise ValueError("string value need") 56 | if len(value) > self.max_length: 57 | raise ValueError("value len excess len of max_length") 58 | self._value = value 59 | 60 | 61 | class ModelMetaClass(type): 62 | def __new__(cls, name, bases, attrs, **kwargs): 63 | # BaseModel类的创建也是通过该元类, 但是不需要执行下面的内容 64 | if name == "BaseModel": 65 | return super().__new__(cls, name, bases, attrs, **kwargs) 66 | # 在attrs中有传入的参数, Meta等, 需要进行处理 67 | fields = {} 68 | for key, value in attrs.items(): 69 | if isinstance(value, Field): 70 | fields[key] = value 71 | attrs_meta = attrs.get("Meta", None) 72 | _meta = {} 73 | db_table = name.lower() 74 | if attrs_meta is not None: 75 | table = getattr(attrs_meta, "db_table", None) 76 | if table is not None: 77 | db_table = table 78 | _meta["db_table"] = db_table 79 | attrs["_meta"] = _meta 80 | attrs["fields"] = fields 81 | del attrs["Meta"] 82 | return super().__new__(cls, name, bases, attrs, **kwargs) 83 | 84 | 85 | class BaseModel(metaclass=ModelMetaClass): 86 | # 在__new__中只是对参数进行处理, 并返回cls, 并没有赋给user对象 87 | def __init__(self, *args, **kwargs): 88 | for key, value in kwargs.items(): 89 | setattr(self, key, value) 90 | return super().__init__() 91 | 92 | # 生成sql语句保存到数据库中 93 | def save(self): 94 | fields = [] 95 | values = [] 96 | for key, value in self.fields.items(): 97 | db_column = value.db_column 98 | if db_column is None: 99 | db_column = key.lower() 100 | fields.append(db_column) 101 | value = getattr(self, key) 102 | values.append(str(value)) 103 | 104 | sql = "insert {db_table}({fields}) value({values})".format(db_table=self._meta["db_table"], 105 | fields=",".join(fields), values=",".join(values)) 106 | pass 107 | 108 | class User(BaseModel): 109 | name = CharField(db_column="name", max_length=10) 110 | age = IntField(db_column="age", min_value=1, max_value=100) 111 | 112 | class Meta: 113 | db_table = "user" 114 | 115 | 116 | if __name__ == "__main__": 117 | # user = User(name="bobby", age=28) 118 | user = User() 119 | user.name = "bobby" 120 | user.age = 28 121 | user.save() 122 | ``` -------------------------------------------------------------------------------- /第8章 元类编程/8-8 本章小结.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/love112358/AdvancePython/cff798a25979b33b9eda4af66698cfe3f78a3822/第8章 元类编程/8-8 本章小结.md -------------------------------------------------------------------------------- /第9章 迭代器和生成器/9-1 python中的迭代协议.md: -------------------------------------------------------------------------------- 1 | ## 什么是迭代协议 2 | ### 迭代器是什么? 3 | - 迭代器是访问集合内元素的一种方式,一般用来遍历数据 4 | - 迭代器和以下标的访问方式不一样,迭代器是不能后退的, 迭代器提供了一种惰性方式数据的方式 5 | - list可以先取第1个然后再取第0个, 但是迭代器不可以. 6 | - 可迭代对象必须实现`__iter__`, 迭代器必须实现`__iter__`和`__next__` 7 | - list中有`__iter__`, 是一个可迭代对象, 但不是迭代器 8 | - 可迭代对象调用`iter(a)`返回一个迭代器 9 | 10 | ### for循环 11 | 在调用for循环的时候会尝试调用`iter()`, 然后`iter()`首先会去找有没有`__iter__`, 如果有将返回一个迭代器, 如果没有将查看有没有`__getitem__`, 如果有将创建默认的迭代器使用`__getitem__`进行迭代输出. 12 | 13 | ### 自己实现一个迭代器和可迭代对象 14 | 把迭代器和可迭代对象分开, 把维护取值放在迭代器中 15 | ``` 16 | from collections.abc import Iterator 17 | 18 | class Company(object): 19 | def __init__(self, employee_list): 20 | self.employee = employee_list 21 | 22 | # 可迭代对象中的__iter__返回迭代器 23 | def __iter__(self): 24 | return MyIterator(self.employee) 25 | 26 | class MyIterator(Iterator): 27 | def __init__(self, employee_list): 28 | self.iter_list = employee_list 29 | self.index = 0 # 需要在内部维护一个取值位置 30 | 31 | # 继承了Iterator可以不写该方法, 如果重写那么return self 32 | # def __iter__(self): 33 | # return self 34 | 35 | def __next__(self): 36 | #真正返回迭代值的逻辑 37 | try: 38 | word = self.iter_list[self.index] 39 | except IndexError: 40 | raise StopIteration # 抛出的异常应该是StopIteration 41 | self.index += 1 42 | return word 43 | ``` 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /第9章 迭代器和生成器/9-2 什么是迭代器和可迭代对象.md: -------------------------------------------------------------------------------- 1 | ``` 2 | from collections.abc import Iterator 3 | class Company(object): 4 | def __init__(self,employee_list): 5 | self.employee = employee_list 6 | #def __iter__(self): 7 | return MyIterator(self.employee) 8 | #def __getitem__(self,item): 9 | # return self.employee[item] 10 | 11 | class MyIterator(Iterator): 12 | def __next__(self): 13 | #真正返回迭代值的逻辑 14 | try: 15 | word = self.iter_list[self.index] 16 | except IndexError: 17 | taise StopIteration 18 | self.index+=1 19 | return word 20 | 21 | 22 | if __name__ == "__main__": 23 | company =Company(["tom","bob","jane"]) 24 | my_itor = iter(company) 25 | while True: 26 | try: 27 | next(my_itor) 28 | except SeopIteration: 29 | pass 30 | 31 | next(my_itor) 32 | for item in company: 33 | print(item) 34 | ''' 35 | -------------------------------------------------------------------------------- /第9章 迭代器和生成器/9-3 生成器函数的使用.md: -------------------------------------------------------------------------------- 1 | ## 什么是生成器函数? 2 | 只要方法里有yield这个关键字, 那么这个方法就不是普通的函数,就可以认为是生成器函数. 3 | ``` 4 | # gen_func()返回的是一个对象 5 | def gen_func(): 6 | yield 1 7 | 8 | def func(): 9 | return 1 10 | 11 | print(gen_func(),func()) 12 | >>> 1 13 | ``` 14 | 15 | ### 斐波那契实现 16 | > 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377 17 | 18 | - 普通函数 19 | ``` 20 | def func(index): 21 | a, b = 0, 1 22 | i = 0 23 | print(a) 24 | while i < index: 25 | print(b) 26 | a, b = b, a + b 27 | i += 1 28 | 29 | func(10) 30 | ``` 31 | - 生成器 32 | ``` 33 | def func(index): 34 | a, b = 0, 1 35 | i = 0 36 | print(a) 37 | while i < index: 38 | yield b 39 | a, b = b, a + b 40 | i += 1 41 | 42 | for i in func(10): 43 | print(i) 44 | ``` 45 | 46 | ### 生成器返回值 47 | 生成器函数式可以return一个值(python后期版本) 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /第9章 迭代器和生成器/9-4 python是如何实现生成器的.md: -------------------------------------------------------------------------------- 1 | ## python中函数的工作原理 2 | ``` 3 | def foo(): 4 | bar() 5 | def bar(): 6 | pass 7 | foo() 8 | ``` 9 | - python的解释器会用`PyEval_EvalFramEx(C语言)`函数去执行我们的foo函数. 10 | - 在运行foo函数的时候首先会创建一个栈帧(Stack frame), 这个栈帧是一个上下文, 也是一个对象. 11 | - 栈帧会将foo函数变成一个字节码对象, 使用dis查看字节码 12 | - 然后栈帧的上下文中去运行字节码(字节码是全局唯一的) 13 | ``` 14 | def foo(): 15 | bar() 16 | def bar(): 17 | pass 18 | 19 | import dis 20 | print(dis.dis(foo)) 21 | 22 | 2 0 LOAD_GLOBAL 0 (bar) 23 | 2 CALL_FUNCTION 0 24 | 4 POP_TOP 25 | 6 LOAD_CONST 0 (None) 26 | 8 RETURN_VALUE 27 | None 28 | ``` 29 | - 当foo调用bar, 又会创建一个新的栈帧, 然后运行bar的字节码 30 | - 所有的栈帧都是分配在堆的内存上, 如果不释放会一直存在, 所以栈帧可以独立于调用者存在, 就比如调用者foo不存在也没关系, 只要指针指向bar的栈帧就可以控制 31 | ``` 32 | import inspect 33 | frame = None 34 | def foo(): 35 | bar() 36 | def bar(): 37 | pass 38 | global frame 39 | # 获取当前函数的栈帧并赋给全局变量frame 40 | frame = inspect.currentframe() 41 | 42 | foo() 43 | print(frame.f_code.co_name) 44 | >>> bar 45 | caller_frame = frame.f_back 46 | print(caller_frame.f_code.co_name) 47 | >>> foo 48 | ``` 49 | 50 | ![](http://qiniu.rearib.top/FiCM74pMYvC5Xz3gPHcSVLs5SFZt) 51 | 52 | - python解释器会编译字节码, 如果发现有yeild, 就会标记该函数, 然后再调用的时候会返回一个生成器对象. 而这个生成器对象实际上是把这个frame对象做了一个封装 53 | 54 | ![](http://qiniu.rearib.top/FvNYTPLMxcqeAfZruBN-2CoaHOKV) 55 | 56 | - 生成器可以在任何时候、任何函数中恢复运行,因为它的栈帧并不在真正的栈中,而是堆中 57 | - f_lasti指向“最后执行指令”的指针。初始化为 -1,意味着它没开始运行 58 | 59 | ``` 60 | 61 | 62 | def gen_func(): 63 | yield 1 64 | name ="bobby" 65 | yield 2 66 | age =30 67 | return "imooc" 68 | import dis 69 | gen = gen_func() 70 | print(dis.dis(gen)) 71 | print(gen.gi_frame.f_lasti) 72 | print(gen.gi_frame.f_locals) 73 | next(gen) 74 | print(gen.gi_frame.f_lasti) 75 | print(gen.gi_frame.f_locals) 76 | next(gen) 77 | print(gen.gi_frame.f_lasti) 78 | print(gen.gi_frame.f_locals) 79 | next(gen) 80 | ``` 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /第9章 迭代器和生成器/9-5 生成器在UserList中的应用.md: -------------------------------------------------------------------------------- 1 | ## 生成器在List应用 2 | ### 生成器是一个迭代器 3 | ``` 4 | def gen_func(): 5 | yield 1 6 | 7 | print(isinstance(gen_func(),Iterator)) 8 | >>> True 9 | ``` 10 | 11 | ### 查看list的源码 12 | 直接dian`a=list`查看list源码发现里面并没有实现方法, 因为list是使用c语言实现的, 但是python中的UserList, 它是python的方式去解释List. 13 | ``` 14 | from collections import UserList 15 | 16 | class UserList(MutableSequence): 17 | def __getitem__(self, i): return self.data[i] 18 | 19 | class MutableSequence(Sequence): 20 | 21 | class Sequence(Reversible, Collection): 22 | def __iter__(self): 23 | i = 0 24 | try: 25 | while True: 26 | v = self[i] # 调用__getitem__ 27 | yield v 28 | i += 1 29 | except IndexError: 30 | return 31 | 32 | ``` 33 | **for循环本质上调用了可迭代对象的`__iter__()`方法,得到了该对象对应的迭代器对象,然后无限调用`__next__()`方法,得到对象中的每一个元素。直到`StopIteration`异常,代表迭代器中已无下一个元素,for循环自动处理该异常,跳出循环。** 34 | 35 | - for循环调用list中的`__iter__()` 36 | - 第一次调用`__iter__()`会启动生成器, 执行到yeild, 返回一个生成器对象, v的值保存在生成器对象中. 37 | - for循环拿到值并不断对迭代器调用next, 直到返回异常跳出. 38 | ``` 39 | from collections import UserList 40 | 41 | class gen_func(UserList): 42 | def __init__(self, list): 43 | self.list = list 44 | 45 | def __getitem__(self, item): 46 | return self.list[item] 47 | 48 | def __iter__(self): 49 | i = 0 50 | try: 51 | while True: 52 | v = self[i] 53 | yield v 54 | i += 1 55 | except IndexError: 56 | raise StopIteration 57 | 58 | a = gen_func([1,2,3]) 59 | 60 | for i in a: 61 | print(i) 62 | ``` 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /第9章 迭代器和生成器/9-6 生成器如何读取大文件.md: -------------------------------------------------------------------------------- 1 | ## 读取大文件 2 | 有一个文件 大概有500G,并且只有一行,行之间有分隔符,我们需要把文件内的数据一行一行的读取出来,然后写入数据库里面。 3 | 4 | - file.read() 5 | 6 | 可以传入 int 参数,代表读取的字符数 7 | 8 | - 代码 9 | ``` 10 | f = open('input.txt','r') 11 | 12 | def myreadline(new_line): 13 | buf = '' 14 | while True: 15 | # 如果现在的缓存中有了分隔符, 取出前面的数据发送出去 16 | while new_line in buf: 17 | line_index = buf.index(new_line) 18 | yield buf[:line_index] 19 | # 去掉已经发送出去的数据并去掉分隔符 20 | buf = buf[line_index + len(new_line):] 21 | 22 | # 读取1024个字节数据并判断, 如果读到结尾那么把剩余buf发送出去并break 23 | check = f.read(1024) 24 | if not check: 25 | yield buf 26 | break 27 | buf += check 28 | 29 | 30 | for i in myreadline('{|}'): 31 | print(i) 32 | ``` 33 | -------------------------------------------------------------------------------- /第9章 迭代器和生成器/9-7 本章小结.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/love112358/AdvancePython/cff798a25979b33b9eda4af66698cfe3f78a3822/第9章 迭代器和生成器/9-7 本章小结.md --------------------------------------------------------------------------------