Python中实战小案例
目录
- Python中实战小案例
- 一、正则表达式
- 二、genent创建协程
- 三、服务端使用http协议向浏览器发送消息
- 四、深拷贝与浅拷贝
- 五、类的继承
- 5.1 单继承
- 5.2 多继承
- 5.3 使用super
- 六、*arg与**kwargs传入参数
- 七、计算分页的类
- 八、property装饰器
- 8.1 使用装饰器去调用
- 8.2 使用方法去调用
- 九、difflib模块比较文件内容
- 9.1 实战:比较nginx的配置文件
- 十、filecmp模块实现目录对比
一、正则表达式
匹配4-20位可以带字母数字下划线的126或者163邮箱,创建一个分组,用group(1)取值
ret = (re.match(r"[a-zA-Z_0-9]{4,20}@(163|126)\.com$", 'abcdd@126.com'))
print (ret.group())
验证手机号是否有效,只能匹配以1开头,第二位是3,长度为2+9=11的手机号
print(re.match(r'^1[3]\d{9}$','13345678401').group())
使用sub方法替换内容
第一种,直接替换
import re
ret = re.sub(r"\d+",str(100),"python = 99")
print(ret)
第二种,调用函数替换,两种输出都是一样的
import re
def add(temp):
strNum = temp.group()
num = int(strNum) +1
return str(num)
ret = re.sub(r"\d+",add,"python = 99")
print(ret)
结果:
python = 100
二、genent创建协程
genvnt: 在需要阻塞的代码处,自动切换下一个函数
注意:如果没有打补丁的话,耗时的代码不会切换另一个函数
代码如下:
import gevent
from gevent import monkey
import time
monkey.patch_all() # 将程序中所用到的所有耗时操作的代码打上gevent的补丁
def work1(num):
ret=0
for i in range(num):
print(ret,'work1')
ret+=1
time.sleep(1)
def work2(num):
ret=0
for i in range(num):
print(ret,'work2')
ret+=1
time.sleep(1)
gevent.joinall(
[
gevent.spawn(work1,5),
gevent.spawn(work2,5)
]
)
运行结果:
0 work1
0 work2
1 work1
1 work2
2 work1
2 work2
3 work1
3 work2
4 work1
4 work2
三、服务端使用http协议向浏览器发送消息
浏览器作为客户端
代码原理:
- 创建套接字,监听7788端口
- 浏览器请求根目录返回主界面代码,请求文件则打开文件并返回给浏览器
- 若请求文件不存在,则返回404
- qq浏览器犯病,有时候请求体为空,所以加了一个判断,判断是否存在请求体
代码如下:
import logging
import os.path
import re
import socket
Format = logging.Formatter('%(levelname)s %(asctime)s %(filename)s %(funcName)s [%(message)s] ')
logger = logging.getLogger()
logger.setLevel('DEBUG')
console_handle = logging.StreamHandler()
console_handle.setLevel(level='INFO')
console_handle.setFormatter(Format)
logger.addHandler(console_handle)
def send_main(new_tcp_socket):
logger.info('request main')
responce = 'HTTP/1.1 200 OK\r\n'
responce += "\r\n"
send_data = "<h1>I am a cute server</h1>"
logger.info(f'sending data: {send_data}')
new_tcp_socket.send((responce + send_data).encode('utf-8'))
def send_responce(new_tcp_socket):
request = new_tcp_socket.recv(1024).decode('utf-8')
if request:
request_lines = request.splitlines()
logger.debug(request_lines)
ret = re.match(r"[^/]+/([^ ]*)", request_lines[0]).group(1)
if ret:
logger.info(f'request file = {ret}')
if os.path.exists(ret):
with open(ret, 'rb') as file:
send_data = file.read().decode('utf-8')
responce = 'HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\n'
responce += "\r\n"
logger.info(f'sending file content: {file}')
new_tcp_socket.send((responce + send_data).encode('utf-8'))
else:
responce = 'HTTP/1.1 404 Not Found\r\nContent-Type: text/html; charset=utf-8\r\n'
responce += "\r\n"
logger.error('file not exists')
new_tcp_socket.send((responce + '<h1>file not exists</h1>').encode('utf-8'))
else:
send_main(new_tcp_socket)
else:
logger.error('QQ browser disease')
send_main(new_tcp_socket)
new_tcp_socket.close()
logger.info('close connection')
def main():
logger.info('start listen port:7788')
tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_server_socket.bind(('', 7788))
tcp_server_socket.listen(128)
while True:
logger.info('reday for a new connection')
new_tcp_socket, client_addr = tcp_server_socket.accept()
logger.info(f'client has established a connection.client addr = {client_addr}')
send_responce(new_tcp_socket)
if __name__ == '__main__':
main()
成果展示:
后台日志:
四、深拷贝与浅拷贝
import copy
print('----------浅拷贝----------')
a=[1,2,3]
b=[4,5,6]
c=[a,b]
d=copy.copy(c)
print('c的值与id为',c,id(c))
print('d的值与id为',d,id(d))
print('a的id为',id(a))
print('d中第一个元素的id为',id(d[0]))
print('a中添加元素777')
a.append(777)
print(f'c的值为{c},d的值为{d}')
print()
print('----------深拷贝----------')
a=[1,2,3]
b=[4,5,6]
c=[a,b]
d=copy.deepcopy(c)
print('c的值与id为',c,id(c))
print('d的值与id为',d,id(d))
print('a的id为',id(a))
print('d中第一个元素的id为',id(d[0]))
a.append(777)
print(f'c的值为{c},d的值为{d}')
结果:
----------浅拷贝----------
c的值与id为 [[1, 2, 3], [4, 5, 6]] 2962023748352
d的值与id为 [[1, 2, 3], [4, 5, 6]] 2962023748608
a的id为 2962014350272
d中第一个元素的id为 2962014350272
a中添加元素777
c的值为[[1, 2, 3, 777], [4, 5, 6]],d的值为[[1, 2, 3, 777], [4, 5, 6]]
----------深拷贝----------
c的值与id为 [[1, 2, 3], [4, 5, 6]] 2962023743424
d的值与id为 [[1, 2, 3], [4, 5, 6]] 2962023748352
a的id为 2962023748096
d中第一个元素的id为 2962023743168
c的值为[[1, 2, 3, 777], [4, 5, 6]],d的值为[[1, 2, 3], [4, 5, 6]]
五、类的继承
5.1 单继承
5.2 多继承
父类被继承了几次就会被调用几次
class Persion(object):
def __init__(self, name):
print('presion主类的init方法被调用')
self.name = name
print('presion主类的init方法结束调用')
class son1(Persion):
def __init__(self, name, age):
print('son1的init方法被调用')
self.age = age
Persion.__init__(self, name)
print('son1的init方法结束调用')
class son2(Persion):
def __init__(self, name, gender):
print('son2的init方法被调用')
self.gender=gender
Persion.__init__(self, name)
print('son2的init方法结束调用')
class all(son1, son2):
def __init__(self, name, age, gender):
print('all 的init被调用')
son1.__init__(self, name, age)
son2.__init__(self, name, gender)
print('all的init方法结束调用')
stu1 = all('小张', 20, 'man')
print(f'姓名:{stu1.name},年龄:{stu1.age},性别{stu1.gender}')
执行结果:
all 的init被调用
son1的init方法被调用
presion主类的init方法被调用
presion主类的init方法结束调用
son1的init方法结束调用
son2的init方法被调用
presion主类的init方法被调用
presion主类的init方法结束调用
son2的init方法结束调用
all的init方法结束调用
姓名:小张,年龄:20,性别man
5.3 使用super
这段我也蒙了,先记录一下代码吧
class Persion(object):
def __init__(self, name):
print('presion主类的init方法被调用')
self.name = name
print('presion主类的init方法结束调用')
class son1(Persion):
def __init__(self, name, age, *args, **kwargs):
print('son1的init方法被调用')
self.age = age
super().__init__(name, *args, **kwargs)
print('son1的init方法结束调用')
class son2(Persion):
def __init__(self, name, gender, *args, **kwargs):
print('son2的init方法被调用')
self.gender = gender
super().__init__(name, *args, **kwargs)
print('son2的init方法结束调用')
class all(son1, son2):
def __init__(self, name, age, gender):
print('all 的init被调用')
super().__init__(name, age, gender)
print('all的init方法结束调用')
stu1 = all('小张', 20, 'man')
print(all.__mro__)
print(f'姓名:{stu1.name},年龄:{stu1.age},性别{stu1.gender}')
执行结果:
all 的init被调用
son1的init方法被调用
son2的init方法被调用
presion主类的init方法被调用
presion主类的init方法结束调用
son2的init方法结束调用
son1的init方法结束调用
all的init方法结束调用
(<class '__main__.all'>, <class '__main__.son1'>, <class '__main__.son2'>, <class '__main__.Persion'>, <class 'object'>)
姓名:小张,年龄:20,性别man
六、*arg与**kwargs传入参数
args保存到元组,kwargs保存到列表
def worker(a,b,*args,**kwargs):
print(a,b,args,kwargs)
worker('asdsadas',"a4",23,56,name='laowang')
运行结果:
asdsadas a4 (23, 56) {'name': 'laowang'}
注意:如果要给另一个函数传递变量,请使用下图的写法
七、计算分页的类
class Pager:
def __init__(self, current_page) -> None:
self.current_page = current_page
self.per_items = 10
@property
def start(self):
val = (self.current_page -1 ) * self.per_items
return val
@property
def end(self):
val = self.current_page * self.per_items
return val
p=Pager(2)
print(p.start,p.end)
执行结果:
10 20
八、property装饰器
定义装饰器共有两种方式,分别是【装饰器】与【类属性】,而装饰器方式针对经典类与新式类又有所不同;
通过property属性,能够简化调用者在获取数据的流程
8.1 使用装饰器去调用
class Godds(object):
def __init__(self, cur_prise) -> None:
self.cur_prise = cur_prise
@property
def say(self):
print('property:' , self.cur_prise)
@say.setter
def say(self,value):
self.cur_prise=value
@say.deleter
def say(self):
print('del')
del self.cur_prise
a = Godds(20)
a.say #获取
a.say=30 # 修改
del a.say # 删除
a.say
8.2 使用方法去调用
九、difflib模块比较文件内容
import difflib
a1='hahahahha \n pipipipi'
a2='hahahaeee \n pipipipi'
# 创建对象
d=difflib.Differ()
# 生成不同内容
diff=d.compare(a1,a2)
print('\n'.join(list(diff)))
# 生成精美的html文件
html_diff=difflib.HtmlDiff()
html_result=html_diff.make_file(a1,a2)
with open ('./html_result.pdf','w') as f :
f.write(html_result)
9.1 实战:比较nginx的配置文件
import difflib
import sys
# 获取变量
try:
conf_file1=sys.argv[1]
conf_file2=sys.argv[2]
except Exception as e:
print(e)
# 读取文件
def readfile(filename):
try:
with open(filename,'r') as f:
text = f.read().splitlines()
return text
except Exception as e :
print(e)
if conf_file1 == '' or conf_file2 == '':
print ('文件为空')
sys.exit()
# print(conf_file1,conf_file2)
text1=readfile(conf_file1)
text2=readfile(conf_file2)
diff_object = difflib.HtmlDiff()
diff_result = diff_object.make_file(text1,text2)
with open('nginx_diff.html','w') as f :
f.write(diff_result)
十、filecmp模块实现目录对比
介绍都在代码注释里,所以直接上代码
import filecmp
# 文件对比
def file_compare():
# 返回一个元祖,第一组是相同的,第二组是不同的,第三组是独有的
result = filecmp.cmpfiles("/root/python/2022-0307","/root/python/demo",['demo1.txt','demo2.txt','demo3.txt','demo4.txt'])
print(result) # (['demo1.txt'], ['demo2.txt'], ['demo3.txt', 'demo4.txt'])
# 文件夹对比
def dir_compare():
dir1 = "/root/python/2022-0307/dir1"
dir2 = "/root/python/2022-0307/dir2"
# 实现目录的比对,忽略普通文件demo2.txt
dir_obj = filecmp.dircmp(dir1,dir2,['demo2.txt'])
# 仅输出一级目录
dir_obj.report()
# 仅输出一级目录及一级目录下的效果
dir_obj.report_partial_closure()
# 输出所有目录信息的效果
dir_obj.report_full_closure()
# 输出相同目录
#print("共同存在的目录:{}".format(dir_obj.common_dirs))
print("共同存在的文件:{}".format(dir_obj.common_files))
print("不共同存在的文件:{}".format(dir_obj.diff_files))
dir_compare()