目录
3.1内置模块
3.1.1builtins模块
3.1.1.1输入输出函数
- input
3.1.1.2类型转换函数
- str()
- int()
- float()
3.1.1.3统计相关函数
- sum()
- min()
- max()
- len()
- count()
3.1.1.4进制转换函数
- bin--0b0010--二进制
- oct--0o12--八进制
- hex--0xd--十六进制
- int--十进制
3.1.1.5编码相关函数
- chr():字符转unicode编码
- ord():unicode转字符
3.1.1.6数据类型转换
- list()
- tuple()
- set()
- dict()
3.1.1.7其他相关函数
- isinstance(dog,Dog):判断对象是否是该类
- issubclass(son_class,father_class):判断儿子是否继承该父亲
- id(a):获取该对象地址
3.1.1.8高级函数
map(function,iterable):根据function对iterable一个一个进行运算,返回map对象,通过list转换,得到的是Bool类型的值
a=[1,2,3,4,5]
b=map(lambda i:i%2==0,a)
print(list(b))
filter(function,iterable):将不符合function的结果过滤掉
r=filter(lambda i:i%2==0,a)
print(list(r))
reduce(function,iterable,initial):第一次是iterable中的第一和第二个数,后续都是上一次求得的结果和这一次要输入的值
from functools import *
r=reduce(lambda i,j:i,a,2)
print(r)
sorted(iterable,key,reverse):根据key值对iterable进行排序
a=[(1,2),(5,3),(7,1)]
b=sorted(a,key=lambda i:i[1],reverse=True)
print(b)
3.1.2os模块
3.1.2.1文件和目录
- mkdir(path):创建目录
- rmdir(path):删除空目录
- remove(path):移除文件
- rmtree(path):删除非空文件或者目录
- listdir(path):列出该文件夹中的文件和目录
3.1.2.2路径相关
- getcwd():获取当前文件的绝对路径
- getpid():获取进程号
- getppid():获取父进程号
- chdir(path):当前路径修改为指定路径
3.1.2.3os中的path模块
- abspath(relative_path):相对路径转绝对路径
- isfile(path)
- isdir(path)
- exists(path)
- join(path1,path2,path3)
- getsize(path):该路径下文件的个数
- split(path):将该路径切分成一个含有两个元素的元组,第一个元素是Base路径,第二个是项目路径
- getctime(path)最后一次创建时间
- getmtime(path):最后一次修改时间
- getatime(path):最后一次访问时间
3.1.2.4其他相关
- environ:环境变量
- name:操作系统名字
- path=r'c:\foo'
- path='c:/foo
3.1.3时间日期模块
3.1.3.1time
- time.time():当前时间秒数
- time.asctime():当前时间年月日时分秒
- time.sleep(3):睡眠3秒钟
3.1.3.2datetime
- datetime.now():当前时间年月日时分秒
- datetime.today()
3.1.3.3date,time,timedalta
- 略
3.1.3.4calendar
- calendar.calendar(2019,10) 打印出2019年的日历,并且行与行之间的宽度是10
- calendar.month(2019,8) 打印出2019年8月的时间表
- calendar.weekday(2019,8,13) 打印出2019年8月13日是星期几
3.1.3.5重点
- timedelta(mintinue=30)
- datetime.now()
- datetime.today()
3.1.4random模块
import random
print(random.random()) # (0,1)
print(random.randint(1,10)) # [1,10]
print(random.randrange(1,10)) # [1,10)
print(random.choice([1,2,3,4,5,6,7,8])) # 从这个序列中随机取出一个
li=[1,2,3,4,5,6]
random.shuffle(li) # 将这个序列打乱
print(li)
3.1.5math模块
import math
li=[1,2,3,4,5,6]
print(math.ceil(1.1)) # 向上取整
print(math.floor(1.1))
print(math.fmod(1,2)) # 取余数
print(math.fabs(-90)) # 绝对值
print(math.pow(2,5)) # 2**5
print(math.sqrt(16)) # 开方
print(math.sin(30))
print(math.fsum(li))
print(math.fabs(-1))
print(round(4.2))
3.1.6hashlib模块
3.1.6.1加密算法分类
- 加密不可逆:md5,sha1,sha256
- 加密可逆:base64
3.1.6.2加密算法应用
md5算法
import hashlib
s = 'hello' # 需要加密的字符串
md5 = hashlib.md5() # 创建加密算法对象
md5.update(s.encode('utf-8')) # 对字符串进行加密
print(md5.digest()) # 二进制的方式显示加密字符串
print(md5.hexdigest()) # 十六进制的方式显示加密字符串
sha1算法
import hashlib
s = 'hello' # 需要加密的字符串
sha_one=hashlib.sha1()
sha_one.update(s.encode('utf-8'))
print(sha_one.digest())
print(sha_one.hexdigest())
base64算法
import base64
s = '我是字符串' # 需要加密的字符串
b64en=base64.b64encode(s.encode('utf-8'))
print(b64en)
b64de=base64.b64decode(b64en)
print(b64de)
3.1.6.3综合案例
import csv
import hashlib
def register():
username=input("please enter the username:")
password=input("please enter the password:")
li=[]
li.append(username)
li.append(hashlib.sha1(password.encode('utf-8')).hexdigest())
with open('./user.csv','a',newline='') as f:
csv_obj=csv.writer(f) # 创建一个csv的写入对象,并将文件句柄传入
csv_obj.writerow(li) # 通过这个对象,将这个列表写入到这个对象中
print("注册成功!")
def login():
username = input("please enter the username:")
password = input("please enter the password:")
password=hashlib.sha1(password.encode('utf-8')).hexdigest()
with open('./user.csv','r') as f:
r_csv=csv.reader(f)
for user in r_csv:
print(user)
if username==user[0] and password==user[1]:
print('login success!')
break
else:
print('用户名或者密码输入不正确...')
def main():
register()
login()
if __name__ == '__main__':
main()
3.1.7logging模块
3.1.7.1日志级别
- critical:批判的
- fatal:错误
- error:错误
- warning:警告
- info:信息
- debug:调试
级别从高到低,级别太高就不会显示相应的错误
3.1.7.2设置日志的步骤
- 创建记录器
- 设置记录器级别
- 创建日志文件对象
- 设置日志文件级别
- 设置日志存放格式
- 将格式添加到日志文件
- 将日志文件添加到记录器
- 使用logging.error('要输出的日志提示')
3.1.7.3综合应用
import logging
logger=logging.getLogger() # 创建日志对象
logger.setLevel(logging.ERROR) # 设置日志级别
handler=logging.FileHandler('log.txt') # 创建一个存放日志的文件对象
handler.setLevel(logging.ERROR) # 设置存放日志的级别
format_obj=logging.Formatter('%(asctime)s - %(module)s - %(filename)s[%(lineno)d] - %(levelname)s:%(message)s') # 设置存放日志的格式
handler.setFormatter(format_obj) # 将这个格式添加到日志对象中
logger.addHandler(handler) # 将日志对象添加到记录器
def log():
try:
number=int(input("please enter the data:"))
for i in range(number):
print('------i',i)
except:
logger.error('您输入的不是一个数字.')
finally:
print('---over---')
if __name__ == '__main__':
log()
3.1.8urllib模块
import urllib
from urllib import request,parse
url=''
headers={}
data=urllib.parse.urlencode({'kw':'Python'}).encode('utf-8') # 对参数进行编码
req=request.Request(url=url,data=data,headers=headers) # 对请求进行封装
req.add_header('user-agender','') # 为请求头添加参数
respon=request.urlopen(req) # 发送请求
html=respon.read().decode('utf-8') # 对请求进行解码
携带数据的get请求
import urllib
from urllib import request,parse
url = 'http://httpbin.org/get?%s'
headers={
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36',
'Cookie': 'PHPSESSID=ST-56995-8t1zsY2JpoqzcaRuLLlNvq5-Pks-izm5ejd5j1npj2pjc7i3v4z',
}
params = urllib.parse.urlencode({'age':35,'sex':'男','work_years':15}) # 对参数进行编码
req=request.Request(url = url%(params),headers=headers) # 构造请求头
respon = urllib.request.urlopen(req)
html=respon.read().decode('utf-8')
print(html)
携带数据的post请求
import urllib
from urllib import request,parse
headers={
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36',
'Cookie': 'PHPSESSID=ST-56995-8t1zsY2JpoqzcaRuLLlNvq5-Pks-izm5ejd5j1npj2pjc7i3v4z',
}
url = 'http://httpbin.org/post'
data = {'Language':'Python','salary':20000,'work_time':996}
data=urllib.parse.urlencode(data).encode('utf-8') # 对要请求的参数进行编码
req=request.Request(url=url,data=data,headers=headers)
respon=urllib.request.urlopen(req)
print(respon.read().decode()) # 对获取到的数据进行解码
对数据的保存
from urllib import request
url = 'https://www-file.huawei.com/huawei_logo.png' # 图片地址
result=request.urlretrieve(url=url,filename='./logo.png') # 返回图片对象
print(result)
设置代理
import urllib
from urllib import request
url = 'http://httpbin.org/ip'
proxies={'http':'117.69.201.206:9999'} # 代理参数
ph=request.ProxyHandler(proxies) # 伪装代理参数
opener=request.build_opener(ph) # 构建代理者
respon=opener.open(url) # 让代理者打开我们的url
print(respon.read().decode('utf-8'))
print(respon.getcode())
print(respon.geturl())
3.2文件读取模块
3.2.1文本文件的读写
3.2.1.1数据读取
def read_file(path):
with open(path,'r') as rf:
# data=rf.read() # 把整篇文章当成一个字符串读取
# data=rf.readline() # 读取一行
data=rf.readlines() # 将数据存放在列表中,每一行为一个数据
print(data)
if __name__ == '__main__':
filepath='./log.txt'
read_file(filepath)
3.2.1.2数据的写入
def write_file(data):
with open('write.txt','w') as wf:
wf.writelines(data) # 列表中的数据的写入
print('写入成功')
if __name__ == '__main__':
data = ['1\n', '2', '3']
write_file(data)
3.2.2csv文件的读写
3.2.2.1读取数据
import csv
def read_csv(filepath):
with open(filepath,'r',encoding='utf-8',newline='') as rf:
reader=csv.reader(rf)
for data in reader:
print(data)
if __name__ == '__main__':
read_csv('./ip_port.csv')
3.2.2.2将列表数据写入文件
# 文件路径,数据格式:[[1,2,3],[3,4,5],[5,4,6]]
def write_csv(filepath,datas):
try:
with open(filepath, 'a', encoding='utf-8', newline='') as wf:
writer = csv.writer(wf)
for data in datas:
writer.writerow(data)
return True
except Exception as ex:
return False
3.2.2.3将字典数据写入文件
def write_csv_dict(filepath,datas):
head={'ip':'IP地址','port':'端口'}
with open(filepath,'w',encoding='utf-8',newline='') as wf:
writer=csv.DictWriter(wf,head)
writer.writeheader()
writer.writerows(data)
if __name__ == '__main__':
data=[{'ip':'202.201.80.162','port':'8888'},
{'ip':'202.201.80.163','port':'8888'}]
write_csv_dict('./1.csv',data)
3.2.3数据库文件的读写
3.2.3.1数据的读取
import pymysql
conn=pymysql.connect(
host='localhost',
user='root',
password='gfb123',
database='test1',
port=3306
)
def query():
cursor=conn.cursor()
sql='select * from dept'
rows=cursor.execute(sql)
# 方式一:查询所有数据
all_data=cursor.fetchall()
print(all_data)
# 方式二:
# for i in range(rows):
# data=cursor.fetchone()
# print(data)
# 方式三
# data=cursor.fetchmany(3)
# print(data)
conn.close()
if __name__ == '__main__':
query()
3.2.3.2数据的写入
import pymysql
conn=pymysql.connect(
host='localhost',
user='root',
password='gfb123',
database='test1',
port=3306
)
def insert(data):
cursor = conn.cursor()
sql = 'insert into dept(deptno,dname,loc) values(%s,%s,%s)'
rows = cursor.execute(sql, (data[0],data[1],data[2]))
conn.commit()
if rows:
print('插入成功')
else:
print('插入失败')
if __name__ == '__main__':
insert([10,'hello','world'])
3.2.4图片文件的读写
3.2.4.1图片文件的写入
from urllib import request
url='https://www.baidu.com/img/bd_logo1.png?where=super'
response=request.urlopen(url=url)
text=response.read()
with open('./baidu.jpg',mode='wb') as f:
f.write(text)
print('图片爬取成功')
3.3序列化和反序列化
3.3.1json库
3.3.1.1数据的序列化
dumps(dict)字典数据序列化成json数据
import json
a={'name':'Marry','sex':'male','age':18}
result=json.dumps(a)
print(type(result))
dump(dict)字典数据序列化到文件
import json
dict1={'name':'Marry','sex':'male','age':18}
with open('1.json','w') as wf:
json.dump(dict1,wf)
print('保存成功')
3.3.1.2数据的反序列化
loads(str):json反序列化成字典
str='{"name": "Marry", "sex": "male", "age": 18}'
r=json.loads(str)
print(type(r))
load(rf):json数据反序列化成字典
with open('1.json','r') as rf:
dict1=json.load(rf)
print(dict1)
print(type(dict1))
3.3.2pickle库
3.3.2.1序列化
- pickle.dumps(dict):字典序列化成字符串
- pickle.dump(dict,wf):字典序列化到文件
3.3.2.2反序列化
- pickle.loads(str):字符串反序列化成字典
- pickle.load(rf):文件数据反序列化成字典
3.3.3json和pickle区别和联系
- 联系:都能将数据进行序列化和反序列化
- 区别:pickle转成的是字节对象,json转成的是字符串对象,也因为如此,pickle在转自定义对象的时候也可以进行序列化,但是json的话相对会有一定的局限性,只能序列化或者反序列化系统已经定义好的对象.
3.4网络编程
3.4.1网络编程基础
3.4.1.1IP地址
在网络中标记的一台电脑,局域网下唯一.
- A类:1字节网络地址和3字节主机地址,最高位0,个数0-127
- B类:2个字节的网络地址和2个字节的主机地址,最高位是“10”,128-191
- C类:3个字节的网络地址和1个字节的主机地址,最高位是“110”,192-223;
- D类:第一个字节以“1110”开头,它是一个专门保留的地址,它并不指向特定的网络,目前主要用来多点广播中,多点广播用来
- E类地址:以'1111'开始,保留将来使用,仅作为实验和开发
3.4.1.2Port端口
- 说到端口,举个很简单的例子,你的电脑相当于一座房子,ip相当于你电脑的详细地址,而端口相当于房子的门,端口有很多个,房子的门也不止一个。
- 在linux中共有2**16=65535个端口;知名端口:0-1023,一般情况下,一个程序员需要使用知名端口,那么他就需要有root权限。
- 动态端口:共有(65535-1024)个,之所以叫动态端口,是因为他一般不固定分配给一个固定的服务,而是动态的分配。动态分配就是当一个系统或者应用程序需要进行网络通信的时候,他向主机申请一个端口,主机从可用的端口中分配一个供他使用。,当程序关闭的时候也会关闭相应的端口。通常情况下是使用ip地址区分电脑主机,使用端口区分这台主机的应用程序。
3.4.1.3其他相关
- ifconfig查看网卡信息
- socket套接字是进程直接通信的方式
3.4.2UDP(用户数据报协议)
3.4.2.1基础知识
- 创建套接字:socket=socket(AF_INET,SOCK_DGRAM)
- 绑定本地ip和端口:socket.bind((ip,port))
- 发送消息:socket.sendto(msg.encode('utf-8'),(ip,port))
- 接收消息:socket.recvfrom(1024)
- 关闭套接字:socket.close()
3.4.2.2聊天器
from socket import *
def send_msg(udp_socket):
msg = input("请输入你想发送的数据:")
desk_ip = input("请输入对方的ip地址:")
desk_port = int(input("请输入对方的该应用程序的端口号:"))
udp_socket.sendto(msg.encode('utf-8'),(desk_ip,desk_port))
def recv_msg(udp_socket):
recv_msg=udp_socket.recvfrom(1024)
recv_ip=recv_msg[1]
recv_data=recv_msg[0].decode('utf-8')
print(">>>%s:%s"%(str(recv_ip),recv_data))
def main():
udp_socket=socket(AF_INET,SOCK_DGRAM) # 创建套接字
udp_socket.bind(('192.168.23.131',8900)) # 绑定本地ip和端口
while True:
print("=" * 30)
print("1.发送消息;2.接收消息;0.退出程序")
op_num = input("请输入需要操作的功能序号:")
if op_num == '1':
send_msg(udp_socket)
elif op_num == '2':
recv_msg(udp_socket)
elif op_num == '0':
break
else:
print("输入错误,请重新输入。")
if __name__ == '__main__':
main()
3.4.2.3注意点
-
字符串转二进制:encode;二进制转字符串:decode,encoding是为了指明编码方式可以是decode('utf-8'),也可以是decode(encoding='utf-8')
-
普通的应用程序是不需要绑定端口,只有服务器性质的应用程序才需要绑定端口.
3.4.3TCP(传输控制协议)
3.4.3.1TCP基础
- 创建套接字:socket(AF_INET,SOCK_STREAM)
- 需要连接的服务器:connect((ip,port))
- 发送数据:send(send_data.encode("utf-8"))
- 接收数据:recv(1024)
- 绑定主机和端口:bind((ip,port))
- 监听套接字:listen(128) 最多连接128个进程
- 接收到客户端:client,address=tcp_sever_socket.accept()
- 客户端携带的消息:client.recv(1024)
- 发送消息:client.send(msg.encode('utf-8'))
3.4.3.2文件下载器
首先我们需要一个客户端:创建套接字;连接ip和port;输入要下载的文件的名字;将这个文件的名字发送给服务器,服务器判断有没有这个文件,如果文件存在就将这个文件发送过来,如果文件不存在,就说该文件不存在。
客户端
from socket import *
def main():
tcp_client = socket(AF_INET, SOCK_STREAM)
dest_ip = input("goal server ip:")
dest_port = int(input("goal server port:"))
tcp_client.connect((dest_ip, dest_port))
filename = input("please input the filename:")
tcp_client.send(filename.encode("utf-8"))
recv_data = tcp_client.recv(1024*1024)
if recv_data:
with open("download_"+filename,"wb") as f:
f.write(recv_data)
print("下载完成!")
else:
print("没有你想要的文件。")
tcp_client.close()
if __name__=="__main__":
main()
服务端
from socket import *
def getFileName(filename):
try:
with open(filename,'rb') as f:
content=f.read()
return content
except:
print("没有下载的文件")
def main():
server_socket = socket(AF_INET, SOCK_STREAM)
server_socket.bind(("192.168.23.1", 7890))
server_socket.listen()
while True:
print("等待客户端连接。。。")
client,address=server_socket.accept()
print("from %s" %str(address))
filename=client.recv(1024).decode("utf-8")
print("对方请求下载的文件是:%s"%filename)
fileContent= getFileName(filename)
if fileContent:
client.send(fileContent)
client.close()
if __name__ == "__main__":
main()
3.4.3.3注意点
3.4.3网络编程相关
3.4.3.1三次握手四次挥手
三次握手
发生在客户端连接服务器的时候,客户端向服务器发送消息,服务器中有请求的内容则服务器直接将客户端请求的内容发送给客户端,如果没有客户端请求的内容,则给客户端提示没有要请求的数据,客户端收到来自服务器的消息后,给服务器回复确认收到消息
四次挥手
发生在服务器和客户端断开连接的时候,
- TCP客户端发送一个FIN报文,用来关闭客户到服务器的数据传送。
- 服务器收到这个FIN报文,它发回一个ACK报文,确认序号为收到的序号加1。和SYN一样,一个FIN报文将占用一个序号。
- 服务器关闭客户端的连接,发送一个FIN给客户端。
- 客户端发回ACK报文确认,并将确认序号设置为收到序号加1。
3.4.3.2长连接(TCP)和短连接(UDP)
区别和联系
- 短连接一般只会在 client/server 间传递一次读写操作.存在的连接都是有用的不需要额外的控制手段
- 长连接可以省去较多的TCP建立和关闭的操作,减少浪费,节约时间。对于频繁请求资源的客户来说,较适用长连接。
- 不过这里存在一个问题,存活功能的探测周期太长,还有就是它只是探测TCP连接的存活,属于比较斯文的做法,遇到恶意的连接时,保活功能就不够使了。在长连接的应用场景下,client端一般不会主动关闭它们之间的连接,client与server之间的连接如果一直不关闭的话,会存在一个问题,随着客户端连接越来越多,server早晚有扛不住的时候,这时候server端需要采取一些策略,
如关闭一些长时间没有读写事件发生的连接,这样可以避免一些恶意连接导致server端服务受损;如果条件再允许就可以以客户端机器为颗粒度,限制每个客户端的最大长连接数,这样可以完全避免某个蛋疼的客户端连累后端服务。
应用场景
- 长连接是点对点的连接,连接数不能太多,(每个操作之后对不会断开连接,方便下次使用,避免浪费时间)eg:连接数据库用长连接,tcp就是长连接.
- web网站http,udp一般用的都是短连接,因为长连接对服务器资源的消耗非常大,web上亿用户如果每个用户都占用一个连接的话,并发量将会非常的大.
- 参考文章:长连接和短连接
3.5测试
3.5.1单元测试
3.5.2文档测试