赞
踩
分布式爬虫是指在多个计算机上部署爬虫程序,共享队列,去重,让多个爬虫不爬取其他爬虫爬取过的内容,从而实现实现联合采集,是一种提高爬取效率的方法
(1)用户输入网址,浏览器发起请求
(2)WSGI(服务器网关接口)创建socket服务端,接受请求
(3)中间件处理请求
(4)url路由,根据当前请求的url找到相应的视图函数
(5)进入view,进行业务处理,执行类或者函数,返回字符串
(6)再次通过中间件处理相应
(7)WSGI返回响应
(8)浏览器渲染
- copy.copy 浅拷贝 只拷贝父对象,不会拷贝对象的内部的子对象。好处:只拷贝引用,不增加内存
- copy.deepcopy 深拷贝 拷贝对象及其子对象 好处:可用于备份,源数据被修改它不会被影响
可变类型(list,dict):浅拷贝只拷贝第一层,深拷贝会拷贝所有层
不可变类型(int,string,float,tuple):深浅拷贝都一样,只拷贝引用
注意:
可变类型里嵌套不可变类型或不可变里面嵌套可变类型:浅拷贝只拷贝引用,而深拷贝为保证数据的独立性,它会从最外层到不可变类型都复制一遍
作用:浅拷贝可以节省内存空间,pytho中大多数都是浅拷贝。可以根据需求进行浅拷贝还是深拷贝。例如是备份重要数据,不想被修改就采用深拷贝。(因为浅拷贝指向同一个地址,不会增加内存,相当于桌面快捷方式一样.)
import copy
a=[1,2,3,4]
#赋值拷贝
b=a # 赋值拷贝内存地址一致,有一方改动另一方跟着改动
#浅拷贝
c=copy.copy(a)#只拷贝a子元素的引用,当该子元素有变动他也跟着变动,但原列表增删元素不会影响浅拷贝的个数,只是元素引用一致,内存地址不一致
#深拷贝
d=copy.deepcopy(a) #引用和值一起拷贝,双方互不影响
*args: 可变位置参数。
*kwargs: 可变关键字参数。
Python中的装饰器其实也是一种函数, 它可以在不修改原函数代码情况下扩展原函数功能。装饰器函数与普通函数不同之处就在于装饰器函数返回了一个函数对象,装饰器利用了闭包的原理来实现。主要用于日志插入,权限管理等等。
垃圾回收机制:
作为Python的使用者来说,Python中的垃圾回收主要以引用计数为主,再引入标记、清除,分代为辅来解决循环引用的问题。
一个对象被引用时,引用计数加1,当对象被del时,引用计数减去1,为0时,对象就被清除,一般情况下用户不会去操作Python 的垃圾回收机制,但它留有API接口。
内存管理:
Python使用了内存池机制来管理内存,其内存以金字塔的形式对内存功能进行划分,-1、-2层主要用于对操作系统进行操作, 0层中是C的malloc,、free等等内存分配和释放函数。1、2层是一个内存池, 当对象小于265K时将直接由这片内存池进行分配内存,否则将调用第0层中的C函数来分配内存,当小于265K的对象被销毁时, 其内存也不会被销毁, 只是返回给了内存池以便二次利用。2层是对Python对象进行操作。
Python中多线程由于有GIL的影响, 导致在任意时间内只有一个线程在运行,所以Python的多线程在处理计算密集型任务上效果反而不如单线程, 只有在处理IO密集型任务上多线程才能发挥实力,在等待IO过程中Python C源码会释放GIL, 最终会导致线程在等待IO过程中会被暂停去执行其他的线程。python中GIL主要是由于历史原因导致Cpython虚拟机中的GIL难以移除,同时GIL的存在保证了多线程之间数据完整性以及状态同步。
os: 提供了对使用操作系统函数的高度封装
sys: 提供由解释器访问或者维护的变量以及与解释器交互的一些函数os模块只负责程序与操作系统交互, 提供了访问操作系统底层的接口封装。
sys模块负责程序与解释器交互, 提供了一系列的函数用于操控Python运行的环境设置。
os模块常用方法:
os.getcwd() # 获取当前运行路径
os.remove() # 删除指定的文件
os.walk() # 生成指定目录下的文件夹以及文件
os.makedirs() # 生成多成目录
os.mkdir() # 生成目录
os.rmdir() # 删除指定目录
os.removedir() # 删除多层目录
os.listdir() # 列出指定目录下所有的文件夹以及文件
os.path.join() # 将分离的各部分组合成一个路径名
os.path.getsize() # 获取指定文件大小
os.path.exists() # 查看指定目录或者文件是否存在
os.path.isabs() # 查看指定目录是否为绝对路径
…
sys模块常用方法:
sys.argv# 命令行参数列表
sys.exit() # 退出程序并返回指定的整数
sys.maxunicode # 最大的Unicode值
sys.modules # 系统导入的模块名称
sys.path # python搜索模块时的路径
sys.stdout # 标准输出
sys.stdin # 标准输入
sys.stderr # 错误输出
…
lambda也是函数的一种, 在处理一些简单的操作时可以使用该表达式, 其好处是不用为一些实现简单功能的函数命名,毕竟编程只有两个难点: 缓存失效, 命名。
Python中拷贝分为深拷贝、浅拷贝。浅拷贝只拷贝父级对象, 不会拷贝对象内部的子对象,使用copy模块中的copy。深拷贝则会完全拷贝父对象以及子对象, 使用copy模块中的deepcopy。
__new__负责构建一个类对象并将其返回,init则负责初始化一些变量,不返回任何对象。在实例化一个类时, __new__方法将会先被运行, 其次才运行__init__方法。
协程是一种线程工作的机制。正常情况下,一个线程处理一个函数或者是一个程序,但是协程是在处理函数的时候,这个函数还有调用其他函数,也就是还有子函数,所以协程在处理的时候使用这一个线程去处理这两个函数,在处理的时候呢,并不是按顺序执行完一个函数再去执行另一个函数,而是执行A函数到一半的时候又去执行函数,这两个函数相互交替执行,这么个机制,叫做协程。
之前说过多线程在执行的时候,是抢夺资源式的执行任务,在读取同一个变量的时候可能会发生冲突,所以为了防止发生冲突,我们用到了线程锁。通过队列,一个线程写信息,一个线程读消息,线程锁控制线程的等待和队列的读写。
但是协程不会发生这种冲突,因为只有一个线程在进行读取数据的操作,不存在同时读写冲突。
所以协程是控制自身,在子程序之间进行切换
协程的作用:当遇到阻塞就去执行其他的程序,例如遇到yield语句就跳出去执行其他函数
import time def task_1(): while True: print('----1-----') time.sleep(3) yield print('++++++1++++++') def task_2(): while True: print('*****2******') time.sleep(3) yield print('++++++2++++++') def main(): t1 = task_1() t2 = task_2() while True: next(t1)#执行到t1的yield时,函数暂停,跳出t1的循环,进行到next(t2) next(t2)#执行到t2的yield时,函数暂停,跳出t2的循环,继续往下循环,即next(t1) # 以上在t1/t2两个线程间来回切换,实现了协程的原理,它比线程还小更有效率 if __name__ == '__main__': main()
Python中异常也是一个对象, 所有的异常的基类都是Exception。捕获异常使用try…except…语法,如果要try与except之间的代码出现了错误并且我们将其异常类型捕获了那么代码将会跳转代except中去执行。还可以使用raise 去手动的触发一个错误,也可以使用assert来触发异常, 只不过assert经常用来在测试中, 并且assert对程序的性能有着极大影响,只有内置的__debug__为True时assert才会执行。
经典类与新式类的区别是:继承搜索的顺序发生了改变,经典类多继承搜索顺序是深度优先, 按照从左至右的查找,并且将每一个父类的基类都查找一遍。新式类则是, 先从左至右的查找, 然后再向每一个父类的基类进行查找。(都是从左至右的顺序查找, 经典类查找一个父类时同时向上查找,新式类则是先查找所有的父类然后再向上查找)
classmethod,staticmethod,property都是装饰器, 他们都作用在类的方法上。
classmethod:使得被装饰的方法成为一个类方法既不需要实例化类就可以直接调用的方法,第一个参数为cls。
staticmethod: 使得被装饰的方法成为一个静态函数既与普通的函数无区别。
property: 将一个方法变成一个属性来使用。
绑定方法:绑定了实例化的方法既第一个参数是self
未绑定方法:没有绑定实例化的方法既类方法、静态方法
Python中上下文管理器使用with来调用主要用于数据库连接,文件操作, 网络操作。
其作用是: 如果在进行一些打开资源操作时出现了异常,上下文管理器将会自动的执行一些资源清理操作。在进入上下文管理器时, Python会先调用对象的__enter__方法, 该方法返回一个对象用于进行一些操作,如果在进行一些操作时发生了异常Python则调用__exit__该对象接受三个参数第一个参数异常类,第二个参数异常提示字符串, 第三个参数traceback对象。
wraps是一个装饰器功能是: 由于被装饰的函数传入到装饰器中时已经不是原函数了, 而是一个新的函数, 并且丢失一些原函数的属性, 为了不影响函数的使用, 可以使用wraps来抵消这种副作用。
ORM使用了Python的属性描述符协议实现,通过另外一个类来描述类变量的属性类型, 再给这个属性进行赋值时(对应数据库中的字段名称)会调用__set__方法,访问属性则会调用__get__方法删除则调用__delete__方法。
迭代器:
1、是一个可以记住遍历的位置的对象,迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束,迭代器只能往前不会后退。
2、因为迭代器需要 next 和 iter 两个方法,所以除了调用next()方法,以及捕获StopIteration异常之外,没有办法检查是否还有遗留元素。此外,也没有办法“还原”迭代器。如果想再次迭代,那就要调用iter(…),传入之前构造迭代器的可迭代对象。传入迭代器本身没用,因为前面说过Iterator.iter 方法的实现方式是返回实例本身,所以传入迭代器无法还原已耗尽的迭代器。
3、 所以迭代器是这样的对象:实现了无参数的 next 方法,返回序列中的下一个元素;如果没有元素了,那么抛出StopIteration异常。Python中的迭代器还实现了 iter 方法,因此迭代器也可以迭代
生成器:
1、一种特殊的迭代器, 生成器自动实现了迭代器协议, 不需要手动的实现__iter__以及next方法,生成器在迭代的过程中可以改变当前的迭代值, 而普通的迭代器改变当前值时往往会发生错。迭代器必须实现__iter__以及next方法。
2、在调用生成器运行的过程中,每次遇到 yield 关键字时函数会暂停并保存当前所有的运行信息,返回 yield 语句的值, 并在下一次执行 next() 方法时从当前位置继续运行,带有 yield 语句的函数不再是一个普通函数,python 解释器会将其视为一个 生成器(generator),所以只要python函数的定义体中有yield关键字,该函数就是生成器函数。
生成器示例
def yield_test():
print('这一行被执行')
yield 1
yield 2
run_test = yield_test()
print(next(run_test)) # 输出:这一行被执行 1
print(next(run_test)) # 输出:2
yield
包含 yield 关键字的函数体,返回的是一个生成器对象,该对象可以迭代遍历和通过 next() 方法取出对象中的值。能节省内存空间,可以达到随用随取的效果。
return
用于结束函数体的运行,return 后面的代码块不会执行,返回该函数的执行结果。
在一个生成器函数中,如果没有 return,则默认执行至函数完毕,如果在执行过程中 return,则直接抛出 StopIteration 终止迭代。
当type只传入一个参数时将返回该参数的类型,如果传入了三个参数则返回一个类对象,同时Python中的所有类的基类都是type
相同: 列表和元组都是容器并且是可迭代对象,二者可以包含任意类型的对象。
不同:列表是可变的, 元组是不可变。
Python中的列表使用了分离式技术实现的动态顺序表。
O(1)
Python的字典使用了哈希表来储存key、value,当添加一个数据时首先会把key通过哈希函数转换成一个数字, 然后将该数字对存放value的数组长度取余并将取余结果当做数组的下标, 将value存放在该取余结果为下标的数组中。数据查询时将key转换为对应的数组下标,并定位到数组的位置获取value。
Pickle模块读入任何Python对象,将它们转换成字符串,然后使用dump函数将其转储到一个文件中——这个过程叫做pickling,反之从存储的字符串文件中提取原始Python对象的过程,叫做unpickling。
PyChecker是一个静态分析工具,它不仅能报告源代码中的错误,并且会报告错误类型和复杂度。
Pylint是检验模块是否达到代码标准的另一个工具。
dis用来查看Python对象的字节码。
在Python中,一个对象的作用于总是由代码被赋值的地方所决定的。当遇见一个变量时Python会按照: 本地作用域→ 当前作用域被嵌入的本地作用域→ 全局/模块作用域→ 内置作用域顺序搜索。
可变对象使用引用传递, 不可变对象使用值传递
def reverse(text):
return text[::-1]
is比较的是对象在内存的地址, ==比较的对象中的值
内层函数引用了其外部作用域的变量,然后返回内层函数的情况,称为闭包,创建一个闭包必须满足以下几点:
\1. 必须有一个内嵌函数
\2. 内嵌函数必须引用外部函数中的变量,外层空间中被引用的变量叫做层函数的环境变量
\3. 外部函数的返回值必须是内嵌函数
\4. 环境变量和内层非全局函数一起构成了闭包
type(),dir(),getattr(),hasattr(),isinstance()
Twisted是一个事件驱动型的网络引擎,不同于单线程和多线程模式,这种模式不需要过多去关心线程锁的问题,当遇到高并发问题时候,采用twisted会很好解决数据共享的问题。
Tornado既是一个web server,也是web framework。就是说这个web框架有自己内置的web server,在写web时候可以用到它的高性能网络库,甚至有公司拿这个来做游戏的服务器,可以用它处理高并发问题。
Gevent是基于协程的Python网络库,基于libev的快速事件循环,基于greenlet的轻量级执行单元,API的概念和Python标准库一致。
sanic基于uvloop和httptools实现高并发异步网络框架
进程有5种状态:
运行态:该进程正在执行。
就绪态:进程已经做好了准备,只要有机会就开始执行。
阻塞态(等待态):进程在某些事情发生前不能执行,等待阻塞进程的事件完成。
新建态:刚刚创建的进程,操作系统还没有把它加入到可执行进程组中,通常是进程控制块已经创建但是还没有加载到内存中的进程。
退出态:操作系统从可执行进程组中释放出的进程,由于自身或某种原因停止运行。
导致转换的事件:
\1. 空->新建:创建执行一个程序的新进程,可能的事件有:新的批处理作业、交互登录(终端用户登录到系统)、操作系统因为提供一项服务而创建、由现有的进程派生等。
\2. 新建->就绪:操作系统准备好再接纳一个进程时,把一个进程从新建态转换为就绪态。
\3. 就绪->运行:需要选择一个新进程运行时,操作系统的调度器或分配器根据某种调度算法选择一个处于就绪态的进程。
\4. 运行->退出:导致进程终止的原因有:正常完成、超过时限、系统无法满足进程需要的内存空间、进程试图访问不允许访问的内存单元(越界)、算术错误(如除以0或存储大于硬件可以接纳的数字)、父进程终止(操作系统可能会自动终止该进程所有的后代进程)、父进程请求终止后代进程等。
\5. 运行->就绪:最常见的原因是,正在运行的进程到达了“允许不中断执行”的最大时间段,该把处理器的资源释放给其他在就绪态的进程使用了;还有一中原因可能是由于具有更改优先级的就绪态进程抢占了该进程的资源,使其被中断转换到就绪态。
6.运行->阻塞:如果进程请求它必须等待的某些事件,例如一个无法立即得到的资源(如I/O操作),只有在获得等待的资源后才能继续进程的执行,则进入等待态(阻塞态)。
7.阻塞->就绪:当等待的事件发生时,处于阻塞态的进程转换到就绪态。
8.就绪->退出:在上图中没有标出这种转换,在某些进程中,父进程可以在任何时刻终止一个子进程,如果一个父进程终止,所有相关的子进程都被终止。
9.阻塞->退出:跟上一项原因类似。
进程是资源分配的最小单位,线程是程序执行的最小单位。
进程有自己的独立的地址空间, 线程共享进程中的数据,使用相同的地址空间。
进程自己通信方式主要使用特别的方式来进行通信。线程之间的通信非常的方便, 同一进程下的线程共享全局变量、静态变量等数据。
多进程程序更加的健壮,其中一个进程死掉了并不影响其他的进程,多线程中只要有一个线程死掉,那么整个进程也死掉了。
进程之间进行通信常用的有几种方式:管道,消息队列, 信号量, 共享内存
管道通常指无名管道, 他的特点包括:
1.半双工:数据只能在一个方向流动,一端为读端,一端为写端
2.有关系进程通信: 管道只能在具有亲缘关系的进程之间进行通信,如父子进程、兄弟进程
3.文件: 管道是一种特殊的文件它有着像普通文件读写一样的API, 它只存在于内存中。
Python实现:
import os from time import sleep def child(wpipe): while 1: msg = "hello world!".encode() os.write(wpipe, msg) sleep(2) def parent(): rpipe, wpipe = os.pipe() pid = os.fork() if pid == 0: child(wpipe) else: os.close(wpipe) fb = os.fdopen(rpipe, 'r') while 1: recv = os.read(rpipe, 1024) print(recv.decode()) parent() # 输出 """ >>> python3.6 ./pipe.py hello world! hello world! hello wor
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。