'''
python
一、进程理论
1. 前置知识
程序:存放在硬盘上的一大堆代码,是'死'的
进程:程序正在运行的过程,是'活'的
2. 进程调度
对于多进程我们需要合理的分配CPU资源,这依赖于进程调度,常见的进程调度算法有:
先来先服务调度算法
根据进程抢到CPU资源的先后顺序,先抢到CPU资源的先执行
短作业优先调度算法
根据调度算法计算出每个进程的长度,然后优先分配CPU资源给短进程
时间片轮转调度算法
将CPU的可处理时间分为一个一个固定大小的时间片,系统分配给每个进程不同数量的时间片
如果一个进程在消耗完时间片的情况下,依然没有执行完成,那么进入就绪队列,重新等待时间片分配
多级反馈优先队列
将CPU的可处理时间分为一个一个队列,每个队列的优先级各不相同,高优先级队列时间要小于低优先级队列
对于每个新创建的进程,都按照先来先服务原则,并分配到高优先级队列中,如果在高优先级队列依然没有执行完毕
那么分配到低优先级队列
如果低优先级队列中的任务正在执行,且高优先级队列中存在任务的话,会立刻跳转到高优先级队列,去执行
时间片轮转+多级反馈队列
3. 进程运行的三状态图
创建 --提交--》 就绪态 --进程调度--》 运行态 --释放--》 退出
运行态 --任务未执行完--》 就绪态 --等待时间片分配--》 运行态
运行态 --任务中途发生事件--》 阻塞态 --事件完成--》 就绪态
就绪态:进程任务已经获取到除CPU以外的所有必要资源,等待进程调度
运行态:进程任务已经获取到CPU资源,正在执行任务
阻塞态:进程任务中途触发事件,如IO操作,申请缓冲区满等,从而释放CPU资源
4. 同步/异步
同步:任务提交后,原地阻塞等待任务返回结果
异步:任务提交后,不会原地阻塞(依靠回调机制获取返回结果),去执行其他任务
5. 阻塞/非阻塞
阻塞:三状态图中的阻塞态
非阻塞:三状态图中的就绪态和运行态
二、进程操作
1. 创建进程的两种方式
类的继承
from multiprocessing import Process
class zzw(Process):
def __init__(self):
super().__init__()
def run(self):
xxx
if __name__ == '__main__':
p = zzw()
p.start()
类的实例化
from multiprocessing import Process
def zzw():
pass
if __name__ == '__main__':
p = Process(target=zzw, args=(), kwargs={}, name=Process-N, group=None)
p.start()
2. multiprocessing模块
Process类
p = Process(target=func, args=(), kwargs={}, name=, group=None, daemon=False)
p.start() 创建子进程
p.join([timeout]) 阻塞主进程,等待子进程运行结束
p.terminate() 立即终结当前进程
p.is_alive() 获取进程存活状态,True/False
p.name 获取进程别名,默认Process-N
p.pid 获取进程id
p.exitcode 获取进程退出状态码,正常退出为0
p.authkey 获取用户验证吗 os.urandom(32)
current_process().pid() 获取当前进程的pid
3. 进程间通信IPC
默认进程间相互隔离,这体现在内存空间上的隔离
如果要实现进程间相互通信,有两种方法:
队列 = 管道 + 锁
管道
队列Queue-先入先出
from multiprocessing import Queue, JoinableQueue
q = Queue(队列长度,不填默认几乎无限)
q.qsize() 返回当前队列长度
q.empty() 如果队列为空,返回True
q.full() 如果队列满了,返回True
q.put(obj, block=True, timeout=None)
向队列存入数据,如果队列满,则阻塞原地,等待队列能够存入数据
q.put_nowait(obj) --> 相当于 .put(obj, block=False)
向队列存入数据,如果队列满,则直接报错
q.get(block=True, timeout=None)
q.get_nowait(block=False)
q.task_done()
q.join()
JoinableQueue()类存在一个计数器,当调用一次task_done计数器-1,调用一次put计数器+1
当计数器为0时,join方法才不会阻塞当前进程
如果使用进程池时,需要使用from multiprocessing import Manager(Manager.Queue)
管道-Pipe
from multiprocessing import Pipe
a, b = Pipe(duplex=False)
设置管道的工作模式 duplex=False为半双工,duplex=True为全双工
a.send(obj)
b.recv()
阻塞原地等待数据,如果对端关闭端口,则会抛出异常EOFError
a.close()
4. windows创建进程操作需要写入到 __name__语句中,因为对于windows来说,创建进程
相当于使用import语句将父进程代码导入到子进程,因此,如果不将创建进程代码写入__name__
语句中,则会不停递归创建
5. 僵尸进程
子进程运行结束后,会留下一个Zombie僵尸进程的数据结构,其中包含进程ID、运行事件、退出状态等
如果父进程没有调用wait/waitpid方法来查看子进程状态,从而回收进程资源,那么Zombie数据结构
就会一直占用进程资源,损耗进程资源
解决方法:
1. 杀死父进程
2. 对开启的子进程使用.join()方法,因为该方法内部调用了wait方法
6. 孤儿进程
父进程创建子进程后突然死亡,子进程还在运行状态,此刻的子进程就是一个孤儿进程
在linux中,孤儿进程会统一被init进程1收养,init进程会不停循环调用wait/waitpid
方法,因此,子进程一旦执行完任务,则会被立刻回收进程资源
7. 守护进程
p.daemon = True
设置子进程为守护进程,则子进程随父进程的结束而结束运行,且守护进程不可继续创建进程
8. 互斥锁Lock
对于多进程同时访问同一个公共资源的情况,需要保证公共资源的数据安全,因此引入了互斥锁
互斥锁原理是同一时刻只能有一个进程对公共资源进行操作,将并行变为串行,保证数据的安全性
from multiprocessing import Lock
mutex = Lock() 生成一个锁对象
mutex.acquire() 加锁
mutex.release() 释放锁
9. 递归锁RLock
对于多个进程同时访问同一份公共资源时,如果使用Lock进行多重锁,那么会容易出现死锁现象
RLock提供多重锁机制,其内部存在一个计数器,没调用一次acquire,那么计数器+1,每调用一次
release计数器-1,只有当计数器为0时,锁才能被抢,否则一直锁定公共资源
from multiprocessing import RLock
mutex = RLock()
mutex.acquire()
mutex.release()
10. 进程池Pool
无需手动创建进程,只需将需要执行的任务丢入进程池即可手动创建进程
from multiprocessing import Pool
p = Pool(Processes=os.cpu_count())
p.apply_async(func, *args, **kwargs)
异步提交进程任务,返回ApplyResult对象
.get([timeout]) 原地阻塞获取返回结果
.ready() 进程任务执行完成返回True
.successful() 进程任务正常执行完成返回True,如果在进程任务还未执行完毕使用该方法,则会抛出异常
.wait([timeout]) 等待结果变为可用
p.apply(func, *args, **kwargs)
同步提交,原地阻塞等待返回结果
源码:apply_async().get()
p.close() 关闭进程池
p.terminate() 立刻终结进程池中所有任务
p.join([timeout]) 原地阻塞等待进程池任务执行完毕,需要在close/terminate方法之后
11. 进程池ProcessPoolExecutor
from concurrent.futures import ProcessPoolExecutor
p = ProcessPoolExecutor(int=os.cpu_count())
p.submit(func, *args, **kwargs)
异步提交,返回future类
p.shutdown()
等价于 close join,关闭进程池,并原地阻塞等待进程任务执行完毕
.cancel() 终结当前进程任务,如果终结成功,返回True,否则Fasle
.cancelled() 如果当前进程任务终结成功,则返回True
.running() 如果当前进程正在运行,则返回True
.done() 如果当前进程运行结束或者被终结,返回Fasle
.result(timeout) 原地阻塞,获取进程任务的返回结果
.exception([timeout]) 原地阻塞获取当前进程异常,如果进程正常结束,则返回None
.add_done_callback(fn) 回调函数,进程任务执行完毕自动触发,将future类传递给
回调函数
p.map(func, iterable, timeout=None, chunksize=1)
三 线程理论
1. 线程/进程
进程:资源单位,创建一个进程就是向系统申请各种资源
线程:执行单位,线程就是程序的执行过程,执行过程中所需资源都向进程索要
2. 每一个进程内部都有一个主线程,负责进程任务的执行
3. 线程模块 _thread(作为thread的兼容),threading(建议使用)
4. 内核线程/用户线程
内核线程:由操作系统内核创建 撤销
用户线程:由用户在进程内部手动创建 撤销
四 线程操作
1. 开启线程的两种方式
类的继承
from threading import Thread
class zzw(Thread):
def __init__(self):
super().__init__()
def run(self):
pass
if __name__ == '__main__':
p = Thread(target=zzw, args=(), kwargs={}, name=Thread-N, daemon=False, group=None)
p.start()
类的实例化
from threading import Thread
def zzw():
pass
if __name__ == '__main__':
p = Thread(target=zzw, args=(), kwargs={}, name=Thread-N, daemon=False, group=None)
p.start()
2. threading模块
Thread类
p = Thread(target=func, args=(), kwargs={}, name=Thread-N, daemon=False, group=None)
p.start() 创建线程
p.join() 阻塞当前线程,等待子线程执行完毕
p.is_alive()/isAlive() 子线程存活返回True
p.name/getName()/setName() 获取name参数值,默认Thread-N,N从1开始
p.daemon/isDaemon()/setDaemon() 默认为False,设置守护线程
current_thread()/currentThread()
获取当前线程对象
enumerate()
[父线程, 子线程,...]
active_count()/activeCount()
获取存活线程数
3. 同进程下子线程共享全局变量
4. 守护线程
p = Thread()
p.daemon = True
设置线程为守护线程,随父线程的结束而结束,守护线程无法继续创建子线程
5. 互斥锁Lock
多个线程同时访问同一个全局变量时,会引起数据安全问题,为了保证数据的安全性
我们需要给公共资源加上一把锁,从而实现同一时间只能有一个线程能够操作公共资源
mutex = Lock()
mutex.acquire()
mutex.release()
6. GIL全局解释器锁
GIL不是python解释器的特点,而是CPython解释器的特点
GIL全局解释器锁是对解释器级数据的安全防护
解释器语言的通病:同一进程下的多线程无法利用多核优势
GIL实现在同一时间只能有一个线程获取到解释器的执行权限
7. 多进程/多线程的优势
多进程:适用于计算密集型,效率远远超于多线程
多线程:适用于IO密集型,开销小,效率不差于进程
8. 死锁现象/递归锁
当我们使用Lock锁实现重锁时,极容易出现死锁现象,即:
线程A获取到锁B,需要获取锁A才能继续执行
线程B获取到锁A,需要获取到锁B才能继续执行
因此进入到死锁现象,从而停滞在当前局面
递归锁RLock,可以实现创建重锁,每当调用一次acquire时,计数+1,
每当调用一次release时,计数-1,只有当计数为0时,才能抢锁,否则阻塞
from threading import RLock
mutex = RLock()
mutex.acquire()
mutex.acquire()
mutex.release()
mutex.release()
9. 信号量 Semaphore
在并发编程中 Semaphore代表锁概念
from threading import Semaphore
mutex = Semaphore(value)
mutex.acquire()
mutex.release()
Semaphore可以创建多个锁,每当调用一次acquire方法,value-1
每当调用一次release方法,value+1,当value为0时,acquire将阻塞线程,直到其他线程
调用release方法
10. 线程同步 Event
对于多线程,每个线程内的状态都是不可预料的,如果对于某个线程需要依赖另外一个线程的莫个状态
才能继续执行,此刻就需要到Event来传递状态
from threading import Event
event = Event()
event.set() 设置Event状态为True
event.clear() 设置Event状态为False
event.wait() 当Event状态为True,则激活线程,进入就绪态
event.isSet()/is_set() 返回Event的状态
对于多进程同步,Event需要使用到队列来传递Event状态
11. 线程queue队列
Queue 先入先出队列/LifoQueue 先入后出队列/PriorityQueue 优先级队列
from queue import Queue, LifoQueue, PriorityQueue
q = Queue()
q = LifoQueue()
q = PriorityQueue()
q.put((优先级别, obj))
优先级别,填入int类型,值越小越优先,可以为负数
通用方法:
q.qsize()
q.empty()
q.full()
q.put(obj, block=True, timeout=None)
q.put_nowait(obj) --> put(obj, block=False)
q.get(block=True, timeout=None)
q.get_nowait() --> get(block=False)
q.join()
q.task_done()
12. 线程池ThreadPoolExecutor
from concurrent.futures import ThreadPoolExecutor
p = ThreadPoolExecutor()
p.submit(func, *args, **kwargs)
异步提交,返回future类
.cancel() 立即终结当前线程,如果线程正在运行无法终结,则返回False,否则True
.cancelled() 如果终结线程成功,则返回True,否则False
.running() 正在运行,返回True
.done() 运行结束/被终结,返回False
.result([timeout]) 阻塞原地,等待返回结果
.exception([timeout]) 阻塞原地,获取线程执行中抛出异常,如果正常执行完毕,返回None
.add_done_callback(func) 回调函数,线程执行完毕立刻触发,将future作为参数传递给回调函数
p.shutdown()
关闭线程池,并原地阻塞等待其他线程任务执行完毕
close join
p.map(func, iterable, timeout=None, chunksize=1)
13. 协程
核心思想:实现单线程的高并发
1. 监测IO操作 gevent模块 spawn()
2. 及时切换 greenlet模块 greenlet, switch()
3. 记录状态 yield
from gevent import spawn
from gevent import monkey;monkey.patch_all()
p = spawn(func, *args, **kwargs)
p --> Greenlet对象
p.join()
from greenlet import greenlet
g = greenlet(fn)
g.switch(参数)
14. IO模型
阻塞IO
阻塞于等待数据和拷贝数据阶段
非阻塞IO
阻塞于拷贝数据阶段,在等待数据阶段直接返回一个值
recvfrom会不断的向内核请求数据,造成内核负载
多路复用IO
使用select监管机制来代替socket进行数据获取和等待,当内核中存在数据时
再使用recv来获取数据,对于单个链接,效率甚至不如,但是多个链接,可以节省出等待数据的阶段事件
异步IO
向内核提交获取数据请求后,不再原地等待,而是立即去执行其他任务,
当内核将数据拷贝到进程中,使用回调机制触发接收数据,并提醒当前进程
进程再过来处理数据
信号驱动IO
网络编程
一 客户端与服务端架构
C/S:Client --> Server
用户需要下载指定的客户端app,才能访问服务端
B/S:Browser --> Server
用户只需要通过浏览器就可以访问服务端
二 OSI七层模型
应用层:为应用程序提供网络服务
数据层:数据格式化 加密 解密
会话层:创建 维护 管理 会话连接
传输层:创建 维护 管理 端到端链接
网络层:IP寻址和路由选择
数据链路层:控制数据帧在数据链路上的传输
物理层:传输比特流
三 Socket简介
1. Socket就是将传输层及以下的数据传输过程封装成一个Socket模块
我们只需要调用这个模块即可实现基于IP+PORT的网络通信
2. Socket模块用法
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket.AF_INET:网络通信
socket.AF_UNIX:本地主机上的不同端口间通信
SOCK_STREAM:TCP链接
SOCK_DGRAM:UDP链接
s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
s.bind(('IP',Port))
s.listen(128)
a, b = accept()
a.send(byte)
a.recv(1024)
a.close()
s.close()
s.sendto(byte, ('ip', port))
s.connect(('IP',Port))
s.setblocking(False) 关闭阻塞,开启非阻塞IO
a, b = recvfrom(1024)
3. TCP服务器/客户端书写方式
TCP服务器
import socket
s = socket.socket()
s.bind('0.0.0.0', 8000)
s.listen(128)
while True:
a, b = s.accept()
while True:
data = a.recv(1024)
if not data:
break
print(data.decode('utf8'), b)
a.send(data.upper())
a.close()
s.close()
TCP客户端
import socket
s = socket.socket()
s.connect(('127.0.0.1',8000))
while True:
inp = input('输入>>>: ')
if not inp:
break
s.send(inp.encode('utf8'))
print(s.recv(1024).decode('utf8'))
s.close()
4. UDP客户端/服务器
UDP服务端
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(('0.0.0.0', 8000))
while True:
a, b = s.recvfrom(1024)
print(a.decode('utf8'), b)
s.sendto(a.upper(), b)
s.close()
UDP客户端
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(('127.0.0.1', 8000))
while True:
inp = input('输入>>>: ')
if not inp:
break
s.send(inp.encode('utf8'))
print(s.recv(1024).decode('utf8'))
5. socketserver实现并发
TCP服务器并发
from socketserver import BaseRequestHandler, ThreadingTCPServer
class ceshi(BaseRequestHandler):
def handle(self):
a = self.request
b = self.client_address
while True:
data = a.recv(1024)
if not data:
break
print(data.decode('utf8'), b)
a.send(data.upper())
a.close()
if __name__ == '__main__':
s = ThreadingTCPServer(('0.0.0.0', 8000), ceshi)
s.serve_forever()
UDP服务器
from socketserver import BaseRequestHandler, ThreadingUDPSever
class ceshi(BaseRequestHandler):
def handle(self):
a, b = self.request
c = self.client_address
b.sendto(a.upper(), c)
print(a.decode('utf8'))
s = ThreadingUDPServer(('127.0.0.1', 8000), ceshi)
s.serve_forever()
6. TCP粘包问题解决
使用struct模块,在传入数据之前,先传入固定长度的数据,数据中包含了后面数据的长度即可
import struct
pack(模式, 数字)
unpack(模式, 数字)
四 HTTP协议
超文本传输协议,用于规定浏览器与服务端之间通信的数据格式
超文本传输协议是用来传输超文本标记语言
1. 四大特性
基于请求响应
基于TCP协议,处于应用层之上
无状态,不保存用户状态
随机字符串:用户相关信息(k:v)
session 将数据保存到服务端
cookie 将数据保存到浏览器
短链接,来一次我响应一次,之后不再建立关系
长连接:双方建立链接后不会断开链接,websocket
2. HTTP请求/响应格式
请求首行(标识请求方式,HTTP版本)
GET / HTTP/1.1
Host:ip地址
请求头 一大堆k-v键值对,需要使用\r\n结尾
\r\n
请求体:浏览器发送给服务端的敏感数据
响应首行(标识HTTP协议版本,状态码)
HTTP/1.1 200 OK
响应头(一大堆k-v键值对)
Content-Type:text/html
Charset:utf8
\r\n
响应体:服务端发送给浏览器用于展示给用户观看的数据
3.请求方式:
GET 浏览器向服务器请求数据
POST 浏览器向服务器提交数据
PUT 浏览器向服务器提交数据,用于全局更新数据
PATCH 浏览器向服务器提交数据,用于局部更新数据
DELETE 浏览器向服务器提交删除数据请求
HEAD OPTIONS TRACE
4. 响应状态码
1xx
2xx
200 OK
201 CREATE
204 NO CONTENT
202 Accepted
3xx
4xx
400 INVALID REQUEST
422 Unprocesable entity
401 Unauthorized
403 Forbidden
404 NOT FOUND
406 Not Acceptable
410 Gone
5xx
500 INTERNAL SERVER ERROR
5. URL
统一资源定位符
第一部分:协议
第二部分:ip/域名
第三部分:站点目录
第四部分:站点资源
绝对URL:HTTP://www.baidu.com/...
相对URL
锚URL
WSGI
WSGI是将socket进一步封装,使用户只需考虑逻辑业务的书写
原理:
第一步:浏览器向服务端发起请求,其中包含HTTP协议以及请求数据
第二步:WSGI Server将请求数据拆包,重新封装为一个environ字典,其中包含了服务器的系统环境变量,请求头,WSGI信息等
第三步:将environ和start_response函数传递给我们自定义的业务函数中,即WSGI APP
第四步:由start_response提供规范化HTTP响应头,并将我们逻辑业务函数的返回正文一同发送给浏览器
from wsgiref.simple_server import make_server
def xxx(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html'), ('Charset', 'utf8')])
return [byte,...]
if __name__ == '__main__':
s = make_server('ip', port, xxx)
s.serve_forever()
异常处理:
try:
检测代码,报错则跳转exception语句
except ... as :
异常跳转后,执行的代码
finally:
必定被执行
else:语句
with语句,使用with语句操作一个对象,就是调用该对象的__enter__()方法和__exit__()方法
raise语句,手动抛出异常
自定义异常
class xxx(Exception):
def __init__(self, a)
self.a = a
raise xxx('')
可迭代对象
对于序列类型,我们可以依据序号进行迭代取值
但是对于非序列类型,就需要使用一种不依赖于序号的方式来迭代取值,因此出现迭代器
只要重写了__iter__()方法,就可以看成是一个可迭代对象
1. 迭代器
迭代器是用于迭代取值的工具,对于迭代就是为了逼近某个目标,从而一次又一次重复过程
将每次迭代获取的值作为下一次迭代的初始值,从而一步一步获取到最终值
from collections.abs import Iterable
class zzw(Iterable):
def __iter__(self):
return self
def __next__(self):
pass
print(issubclass(zzw, Iterable))
for in 方法就是调用对象的__iter__()方法,获取到一个迭代器对象
然后不断重复调用这个对象的__next__()方法,获取到每次__next__()方法的返回值
1. 停止迭代器
在__next__()方法内设置停止条件,使用raise关键字,当条件触发时,抛出异常,停止程序
raise StopIteration
2. 迭代器的优缺点
优点:
1)统一序列和非序列类型的迭代取值方式
2)惰性计算:迭代器对象代表的是一个数据流,对于同一时刻其在内存中只对应当前迭代的值,
这意味着,他的数据流对于内存的限制很小,可以无限大,当我们需要迭代取值时,再调用
__next__()方法获取到迭代值,而容器对象是将所有的元素都存在内存中的,元素个数受
内存大小限制
缺点
1)在迭代到最后一个值之前,无法获取到迭代器数据长度
2)迭代器只能基于当前状态,获取下一个迭代的值,不能获取初始值
3)迭代器会记录当前状态,如果未取尽迭代器对象的值,那么下次调用该对象时,依然是从上次状态开始,而不是重新开始
4)一个迭代器对象只能被一个循环取值
2. 生成器
生成器是一种特殊的迭代器,它内部提供了保存状态的机制,实现迭代取值过程中状态的保存
1. 生成器的创建方式1
函数内部使用yield语句,就是生成器
def zzw():
a = yield
a = zzw()
next(a)
a.send(None)
2. 创建生成器的方式2
列表推导式变为元组推导式
l = (i for i in range(1, 10))
l.__next__()
next(l)
l.send(None)
3. 对可迭代对象的操作
filter(func, iterable) 过滤
map(func, iterable) 加工
import functools import reduce
reduce(func, iterable, 初始值) 返回可迭代对象相加/相减值,可以设置初始值
魔术方法
1. 内置属性
__class__ 返回类名+类类型
__module__ 返回当前类所处模块名
__dict__ 返回字典,类属性名-属性值
__doc__ 返回多行文本注释
__mro__ 返回继承调用顺序,元组
__slots__ = () 设置类内局部名称空间
2. 基础魔术方法
__init__() 实例化对象触发
__new__() 实例化对象触发,new方法是一个静态方法
__call__() class()
__str__()/__repr__() print(class) str(class), 返回结果需要是字符串,str、repr存在时优先触发str
__dir__() dir(class)
__del__() py文件执行完毕/del class 自动触发
__len__() len(class)
__hash__() hash(class)
3. 涉及比较运算符
> __gt__()
>= __ge__()
< __lt__()
<= __le__()
!= __ne__()
==/is __eq__()
4. 涉及算术运算符
+ __add__()
- __sub__()
* __mul__()
/ __truediv__()
** __pow__()
5. 涉及数据类型转换的魔术方法
str() __str__()
int() __int__()
__setitem__(key, value) obj['name'] = value
__getitem__(key) obj['name']
__delitem__(key) del obj['name']
6. 上下文管理魔术方法
__enter__() 当对象被with语句指定时,触发调用,并将__enter__()方法的返回值作为as f变量的值
__exit__() 当with语句执行完毕后,自动触发
面对对象基础:
1. 类的基础语法
定义类名:
class xxx:
pass
实例化对象
a = xxx()
a.属性名
a.方法名
2. self语句的使用
谁调用了,self就代表那个对象
3. 属性在类外赋值
class.属性名 = 属性值
可以在类外对类内的属性进行值修改,创建
4. 对象属性和类属性
类属性:类的属性
对象属性:对象的属性
5. 私有方法/属性
__以双下划线开始的作为私有
私有属性无法无法被子类继承
调用私有属性或方法
_类名__名称()
6. 类方法和静态方法
对象方法
def xxx(self):
pass
类方法
@classmethod
def xxx(cls):
pass
静态方法
@staticmethod
def xxx():
pass
7. 单例设计模式
多个实例化对象指向同一块对象内存地址
class xxx(object):
instance = None
@classmethod
def __new__(cls, *args, **kwargs):
if not instance:
cls.instance = object.__new__(cls)
return cls.instance
8. 面对对象的三大特征
继承:子类可以有条件的继承父类的方法和属性
class(a,b,c,d)
__mro__
遵循第一个父类找到死,再找第二个父类
封装:将一大堆代码(函数和变量)封装到一个类中,调用这个类就相当于调用这些方法和属性
多态:子类可以在父类的基础上进行重写,延申出自身的特色功能
新式类:
继承object的就是新式类,在python3中默认继承object
经典类:
不继承object的就是经典类
9. 反射
反射原理:使用字符串的形式操作对象相关的属性
a = getattr(self, '', None)
python其他模块
网络工程师模块了解:
netmiko
paramiko
textfsm
ntc-templates
Napalm
pythonping
正则表达式
1. re模块方法
.match('re', str)
.search('re', str)
.finditer('re', str)
.findall('re', str)
.fullmatch('re', str)
.compile('re')
.sub('re', str/func, str)
2. re.Match对象
属性
.pos
.endpos
.string
.re
.lastindex
.lastgroup
方法
.group(index=0)
.groups()
.groupdict()
.span(group)
.start(group)
.end(group)
.expand(template)
正则修饰符
re.M
re.I
re.S
正则表达式规则:
1. 数字、字母代表它本身
2. 注意转义字符具有正则意义
3. 标点符号具有正则意义
正则匹配模式
非打印字符
\cL \f 换页符
\cI \t 制表符
\cJ \n 换行符
\cK \v 垂直制表符
\cL \r 回车符
\s 任何空白字符
\S !\s
\w 字母、数字、下划线、中文
\W !\w
\d 数字0-9
\D !\d
\b 单词边界字符
\B 非单词边界字符
特殊字符
()
[]
{}
|
.
\
定位符
^
$
\b
\B
限定符
*
+
?
{n}
{n,}
{,m}
{n,m}
贪婪模式和非贪婪模式
关闭贪婪模式?
分组别名:?<name>
分组编号:0代表正则全部,1代表分组1
其他模块
import subprocess
.Popen()
import copy
.copy()
.deepcopy()
import importlib
.import_module('')
import uuid
.uuid1()
.uuid2()
.uuid3()
.uuid4()
.uuid5()
常用模块
1. os
import os
.name nt posix
.sep \ /
.linesep \r\n \n
.pathsep ; :
.environ environ({k-v})
.removedirs()
.makedirs()
.rmdir()
.mkdir()
.chdir()
.listdir()
.rename(oldname,newname)
.remove(file)
.stat(path)
st_uid
st_gid
st_size
st_ctime
st_atime
st_mtime
.getpid()
.getppid()
.getcwd()
.system()
.popen().read().print
.urandom(int)
from os import path
.abspath()
.split()
.dirname()
.basename()
.splitext()
.exists()
.isabs()
.isdir()
.isfile()
.getctime()
.getatime()
.getmtime()
.getsize()
2. sys
import sys
.argv[]
.version
.path
.platform
.exit()
.stdout
.stdin
.stderr
3. math
import math
.fabs()
.pi
.pow()
.ceil()
.floor()
.sin()
.cos()
.tan()
4. random
import random
.random() 0-1
.randint(start, end) start-end int
.uniform(start, end) start-end float
.randrange(start, end, step) start-end,step,int
.choice(iterable)
.sample(iterable, int)
.shuffle(iterable)
5. datetime
import datetime
datetime()
.now()
.today()
.utcnow()
date()
.today()
time()
.year
.month
.day
.weekday()
.isoweekday()
6. time
import time
.sleep()
time stamp
.time()
.localtime()
.gmtime()
.ctime()
format string
%Y %m %d %H %M %S
.strptime()
struct_time
.mktime()
.strftime()
.asctime()
tm_year
tm_mon
tm_mday
tm_yday
tm_hour
tm_min
tm_sec
tm_wday
tm_isdst
7. json
dumps(obj)
loads(obj)
dump(obj, file)
load(file)
8. pickle
dumps(obj)
loads(bytes)
dump(obj, file)
load(file)
9. collections
from collections import namedtuple, deque, OrderDict, defaultdict, Counter
a = namedtuple('a', '字段名 ...')
b = a(tuple)
b.字段名
a = deque(iterable)
a.append()
a.pop()
a.appendleft()
a.popleft()
a = QrderDict(**kwargs/[(k,v),...])
a = defaultdict(func, **kwargs/[(k,v,...)])
a = Counter(iterable)
Counter({'k':count,...})
10. hashlib
import hashlib
.md5(bytes)
.sha1/224/256/384(bytes)
.update(bytes)
.hexdigest()
11. configparser
from configparser import ConfigParser
必要三件套
c = ConfigParser()
c.read('.ini', encoding='utf8')
增:
c[''] = {'':v,...}
c.add_section('')
删除
c.remove_section('')
c.remove_option('', '')
修改
c.set('','','')
查看
c.sections()
c.options('')
c.items('')
c.get('','')
getint
getfloat
getboolean
c.has_section('')
c.has_option('','')
c.write(open())
12. struct
import struct
pack('I', int) --> 4bytes
unpack('I', int) --> int
13. csv
import csv
w = csv.writer(file)
w.writerow([])
w.writerows([[]])
r = csv.reader(file)
print(list(r))
14. StringIO
from io import StringIO
a = StringIO()
a.write(str)
a.getvalue()
a.close()
15. BytesIO
from io import BytesIO
a = BytesIO()
a.write(bytes)
a.getvalue()
a.close()
模块基础
1. 导入模块语法
import module
from path import module
path:
绝对路径
C:\\\\\
相对路径
.当前 ..上一级 以此类推
from module import *
from module import class_name
from module import class_name as xxx
不管使用何种语句导入模块,都会将模块文件执行一遍
2. 搜索模块路径
搜索模块路径:sys.path
可以使用 sys.path.append(path)添加路径
3. __开头作用
使用 from 语法无法导入私有
使用 import 语法可以导入私有
解决方法:
if __name__ == '__main__':
del __xxx
4. __all__属性的作用
__all__ = [xxx,xxx]
规定可以被导入的名称
5. __name__属性
在当前模块下,__name__ == '__main__'
在被当作模块导入后,__name__ == 文件名
6. 包概念
多个模块合并成一个包,包内存在__init__.py模块在包被导入时自动触发
python常用内置函数
1. 数学计算
abs()
round(float, int)
divmod(a, b)
pow(a, b)
sum(纯数字iterable)
max(iterable)
min(iterable)
int(unicode, 进制)
float(number)
complex(number)
hex()
oct()
bin()
2. 数据类型转换
str(obj)
bool(obj)
list(iter)
tuple(iter)
set(iter)
dict([(),..],**kwargs)
3. 字符串相关
format()
bytes()
bytearray()
repr()
ascii(str)
memoryview(bytes).tolist().tobytes()
ord()
chr()
4. 可迭代对象相关
all()
any()
len()
sorted()
iter()
next()
zip()
5. 返回迭代器
reversed()
map()
filter()
range()
6. 作用域相关
globals()
locals()
7. 输入输出
input()
print()
8. 字符串类型代码的执行
eval()
exec()
compile('', '', 'eval/exec')
9. 判断对象继承相关
isinstance()
issubclass()
super()
10. 针对对象通用方法
hasattr(obj ,name)
getattr(obj ,name, default=None)
setattr(obj, name, value)
delattr(obj, name)
11. 对象修饰符
@classmethod
@staticmethod
@property
12. 常用基本方法
id()
type()
help()
13. 返回一个特殊对象
slice()
frozenset(iterable)
enumerate(iterable)
open()
__import__()
14. 对象有关
object()
dir()
vars()
callable()
property(get, set, del, doc)
15. 其他
hash()
exit()
高阶函数
递归函数
def ceshi():
pass
ceshi()
ceshi()
匿名函数
lmbda x,y:x+y
闭包函数
def zzw():
def ceshi():
pass
return ceshi
__closure__可以获取当前对象调用的自己外层局部变量,以元组形式返回
__closure__[0].cell_contents
装饰器
def xx(a ,b)
def zzw(func):
from functools import wraps
@wraps(func)
def ceshi(*args, **kwargs):
func()
ceshi.__name__ = func.__name__
ceshi.__doc__ = func.__doc__
return ceshi
return zzw
@xx(1,2)
def haha(*args, **kwargs):
pass
高级装饰器
@property
class C():
@property
def x(self):
pass
@x.getter
def x(self):
pass
@x.setter
def x(self):
pass
@x.deleter
def x(self):
pass
函数基础
1. 基本语法
def xxx():
pass
xxx()
2. 函数的参数
位置参数,默认参数,可变长参数,命名关键字参数,可变长关键字参数
3. 函数的返回值
return a,b,c --> (a,b,c)
4. 函数的注释
help()
5. 全局变量和局部变量
全局变量:定义在全局空间的变量,就是全局变量,在全局有效
局部变量:定义在函数内部的变量,就是局部变量,仅在函数内部有效
global nonlocal
globals locals
6. 名称空间
内建名称空间:随python解释器的启动、创建,关闭、回收,存放python解释器内置的名称
全局名称空间:随py文件的启动、创建,运行结束、回收,存放py文件下定义的名称
局部名称空间。随函数的执行,创建,执行结束、回收,存放函数内部定义的名称
7. 作用域
全局作用域:由内建名称空间和全局名称空间组合,在该两个名称空间存在的名字在全局生效
局部作用域:在局部名称空间内的名字仅在函数执行时生效,函数执行完毕回收
文件处理
open(file_path, mode='', encoding='')
mode: r w a t b + U
encoding: utf8 gbk big5
read(int) 读取全部内容
readline(int) 读取单行内容
readlines(int) 读取全部内容,每行作为一个元素存入列表返回
读取文件内容,如果open打开文件模式为rt,那么int代表字符限制
如果open打开文件模式为rb,则int代表字节限制
write(str/bytes) 写入文件内容
wt 填入字符串即可,系统内部自动转换为bytes
wb 填入bytes
seek(offset, mode)
offset填写字节数
mode:
0:光标以首行首位为标准,偏移offset字节,可在rt\rb
1:光标以当前位置为标准,偏移offset字节,仅在rb
2:光标以文件末尾为标准,偏移offset字节,仅在rb
tell()
获取当前光标想对文件首行首位的字节数
close() 关闭文件
绝对路径:以磁盘根目录为根,书写绝对路径
相对路径:以当前目录为根,书写相对路径
.当前目录 ..上一级目录
流程控制
分支结构
if ... elif ... else
隐士类型转换
区间判断
三元表达式
a if a > b else b
循环结构
while True:
for in
for in ... else
while ... else
break,continue
pass
基本运算符
算术运算符
+ - * / ** // % ()
比较运算符
> >= < <= != ==
赋值运算符
=
增量赋值
-= += *= /= **= //= %=
链式赋值
a = b = 12
交叉赋值
a,b = b,a
解压赋值
a, *b = [1,2,3]
逻辑运算符
and or not
逻辑运算符遵循,结果一出,立马结束判断
成员运算符
in
not in
身份运算符
is
is not
位运算符
& 按位与 都为1 才为1
| 按位或 一个为1,即为1
^ 按位异或 一个为1,即唯一,不能同时为1
~ 按位取反,~x相当于 -x-1
<< 左移
>> 右移
输入输出语句
输入:input('提示信息')
输出:print(obj,...,sep=' ',end='\n',file=sys.stdout, flush=False)
深浅复制
深浅复制的根本就是在于浅复制仅能复制容器对象表面一层数据,对于内存继续嵌套容器对象的情况,无法复制数据
浅复制:
切片操作
obj.copy()
copy.copy(obj)
深复制
import copy
copy.deepcopy(obj)
可变数据类型与不可变数据类型
可变/不可变的数据类型的根本原因是在于:我们无法直接修改对应内存地址存储的值,只能
通过减少其的引用关系,来达到删除它的动作
可变数据类型:
修改变量值,内存地址不会发生改变
不可变数据类型:
修改变量值,内存地址会发生改变
如果两个不可变数据类型的值一致,那么他们指向同一块内存
垃圾回收机制
堆区:存放变量值的
栈区:存放变量名与变量值在内存空间中的地址之间的映射关系
直接引用:从栈区出来,第一跳就是变量值本身
间接引用:从栈区出来,第一跳不是变量本身
引用计数
如果一个变量值被直接或间接引用一次,那么计数+1
如果一个变量值减少了一次引用关系,则计数-1
当计数为0时,我们应该回收该变量值的内存空间
--循环引用
--效率问题
标记-清除
当内存空间满时,立即停止程序,执行一下两个步骤
标记:遍历所有栈区对象,对于栈区中存在直接、间接引用关系的变量值,标记存活
清除:遍历所有堆区对象,回收所有非存活的变量值内存空间
分代回收
按照一定频率进行标记-清除操作,多次扫描下依然存活的变量值,归于下一代,扫描频率降低
字符编码
ASCII
Unicode
utf8
gbk
big5
chr()
ord()
encode()
decode()
数据类型
数字类型number
int(str, base)
float(number)
complex(number)
hex()
oct()
bin()
字符串类型string
查找
str[index]
find('', start, end)
rfind('', start, end)
index('', start, end)
rindex('', start, end)
len()
count('', start, end)
split('', maxspilt=-1)
rsplit('', maxsplit=-1)
partition('')
rpartition('')
splitlines('')
判断:
startswith('', start, end)
endswith('', start, end)
isalpha()
isalnum()
isupper()
istitle()
islower()
isdigit()
isnumeric()
isdecimal()
isspace()
修改
replace(old, new,count)
upper()
lower()
title()
ljust(width, '')
rjust(width, '')
center(width, '')
zfill(width)
strip('')
lstrip('')
rstrip('')
''.join(iterable)
expandtabs(tabsize=8)
格式化字符串
%s %f %d %.nf %nd %-nd %''nd %X %x %%
format()
\' \" \t \n \\
r'' R''
列表类型list
增加
.append()
.insert(index, obj)
.extend(iterable)
删除
del list
clear()
remove('')
pop(index)
修改
[index]
查询
[]
len()
in / not in
index('')
count('')
列表排序
.reverse()
.sort(key=func, reverse=True)
sorted(list)
[::-1]
列表推导式
[(i, j) for i in range(1, 10), for j in range(10,20)]
[i for i in range(1, 10) if i % 2 == 0]
元组类型tuple
1. a = 1,2,3,4
2. (1,)
元组的查询
len()
in/ not in
index('')
count('')
[]
元组的增加
+
集合类似set
增加
add()
union()
update()
删除
clear()
remove('')
pop()
del
查看
len()
集合与运算符的使用
- 去交集
& 交集
| 并集
^ 差集
> >= 父集
< <= 子集
字典类型dictionary
增加
update()
fromkeys([k], v)
setdefault(k, default=None)
删除
del
clear()
pop(key)
popitem()
查看
len()
in not in
keys()
values()
items()
布尔类型boolean
bool()
为False:
空字符串、字典、元组、集合、列表,None、数字<=0,False
变量与常量
变量:在整个py文件的执行过程中用于存储会发生变化的数据,即状态
定义语法:
变量名 = 变量值
变量的三大特性
id type value
常量:在整个py文件的执行过程中用于存储不会发生变化的数据,如PI
在python中并没有明确规定常量的定义语法,我们一般将变量名全大写,作为常量名
PI = 3.14...
'''
a = ['zhang',]
b = ('zhang',)
c = dict([('name', 18),])
d = {}