全网最适合入门的面向对象编程教程:60 Python 面向对象综合实例-传感器数据实时绘图器

摘要:

本文将结合之前内容实现模拟一个传感器系统软件,包括三个线程:传感器线程生成数据并通过串口发送给主机进程;主机进程通过串口接收指令,进行数据滤波和处理后,将处理结果发送给绘图线程;绘图线程负责接收数据并绘制更新数据曲线。

原文链接:

FreakStudio的博客

往期推荐:

学嵌入式的你,还不会面向对象??!

全网最适合入门的面向对象编程教程:00 面向对象设计方法导论

全网最适合入门的面向对象编程教程:01 面向对象编程的基本概念

全网最适合入门的面向对象编程教程:02 类和对象的 Python 实现-使用 Python 创建类

全网最适合入门的面向对象编程教程:03 类和对象的 Python 实现-为自定义类添加属性

全网最适合入门的面向对象编程教程:04 类和对象的Python实现-为自定义类添加方法

全网最适合入门的面向对象编程教程:05 类和对象的Python实现-PyCharm代码标签

全网最适合入门的面向对象编程教程:06 类和对象的Python实现-自定义类的数据封装

全网最适合入门的面向对象编程教程:07 类和对象的Python实现-类型注解

全网最适合入门的面向对象编程教程:08 类和对象的Python实现-@property装饰器

全网最适合入门的面向对象编程教程:09 类和对象的Python实现-类之间的关系

全网最适合入门的面向对象编程教程:10 类和对象的Python实现-类的继承和里氏替换原则

全网最适合入门的面向对象编程教程:11 类和对象的Python实现-子类调用父类方法

全网最适合入门的面向对象编程教程:12 类和对象的Python实现-Python使用logging模块输出程序运行日志

全网最适合入门的面向对象编程教程:13 类和对象的Python实现-可视化阅读代码神器Sourcetrail的安装使用

全网最适合入门的面向对象编程教程:全网最适合入门的面向对象编程教程:14 类和对象的Python实现-类的静态方法和类方法

全网最适合入门的面向对象编程教程:15 类和对象的 Python 实现-__slots__魔法方法

全网最适合入门的面向对象编程教程:16 类和对象的Python实现-多态、方法重写与开闭原则

全网最适合入门的面向对象编程教程:17 类和对象的Python实现-鸭子类型与“file-like object“

全网最适合入门的面向对象编程教程:18 类和对象的Python实现-多重继承与PyQtGraph串口数据绘制曲线图

全网最适合入门的面向对象编程教程:19 类和对象的 Python 实现-使用 PyCharm 自动生成文件注释和函数注释

全网最适合入门的面向对象编程教程:20 类和对象的Python实现-组合关系的实现与CSV文件保存

全网最适合入门的面向对象编程教程:21 类和对象的Python实现-多文件的组织:模块module和包package

全网最适合入门的面向对象编程教程:22 类和对象的Python实现-异常和语法错误

全网最适合入门的面向对象编程教程:23 类和对象的Python实现-抛出异常

全网最适合入门的面向对象编程教程:24 类和对象的Python实现-异常的捕获与处理

全网最适合入门的面向对象编程教程:25 类和对象的Python实现-Python判断输入数据类型

全网最适合入门的面向对象编程教程:26 类和对象的Python实现-上下文管理器和with语句

全网最适合入门的面向对象编程教程:27 类和对象的Python实现-Python中异常层级与自定义异常类的实现

全网最适合入门的面向对象编程教程:28 类和对象的Python实现-Python编程原则、哲学和规范大汇总

全网最适合入门的面向对象编程教程:29 类和对象的Python实现-断言与防御性编程和help函数的使用

全网最适合入门的面向对象编程教程:30 Python的内置数据类型-object根类

全网最适合入门的面向对象编程教程:31 Python的内置数据类型-对象Object和类型Type

全网最适合入门的面向对象编程教程:32 Python的内置数据类型-类Class和实例Instance

全网最适合入门的面向对象编程教程:33 Python的内置数据类型-对象Object和类型Type的关系

全网最适合入门的面向对象编程教程:34 Python的内置数据类型-Python常用复合数据类型:元组和命名元组

全网最适合入门的面向对象编程教程:35 Python的内置数据类型-文档字符串和__doc__属性

全网最适合入门的面向对象编程教程:36 Python的内置数据类型-字典

全网最适合入门的面向对象编程教程:37 Python常用复合数据类型-列表和列表推导式

全网最适合入门的面向对象编程教程:38 Python常用复合数据类型-使用列表实现堆栈、队列和双端队列

全网最适合入门的面向对象编程教程:39 Python常用复合数据类型-集合

全网最适合入门的面向对象编程教程:40 Python常用复合数据类型-枚举和enum模块的使用

全网最适合入门的面向对象编程教程:41 Python常用复合数据类型-队列(FIFO、LIFO、优先级队列、双端队列和环形队列)

全网最适合入门的面向对象编程教程:42 Python常用复合数据类型-collections容器数据类型

全网最适合入门的面向对象编程教程:43 Python常用复合数据类型-扩展内置数据类型

全网最适合入门的面向对象编程教程:44 Python内置函数与魔法方法-重写内置类型的魔法方法

全网最适合入门的面向对象编程教程:45 Python实现常见数据结构-链表、树、哈希表、图和堆

全网最适合入门的面向对象编程教程:46 Python函数方法与接口-函数与事件驱动框架

全网最适合入门的面向对象编程教程:47 Python函数方法与接口-回调函数Callback

全网最适合入门的面向对象编程教程:48 Python函数方法与接口-位置参数、默认参数、可变参数和关键字参数

全网最适合入门的面向对象编程教程:49 Python函数方法与接口-函数与方法的区别和lamda匿名函数

全网最适合入门的面向对象编程教程:50 Python函数方法与接口-接口和抽象基类

全网最适合入门的面向对象编程教程:51 Python函数方法与接口-使用Zope实现接口

全网最适合入门的面向对象编程教程:52 Python函数方法与接口-Protocol协议与接口

全网最适合入门的面向对象编程教程:53 Python字符串与序列化-字符串与字符编码

全网最适合入门的面向对象编程教程:54 Python字符串与序列化-字符串格式化与format方法

全网最适合入门的面向对象编程教程:55 Python字符串与序列化-字节序列类型和可变字节字符串

全网最适合入门的面向对象编程教程:56 Python字符串与序列化-正则表达式和re模块应用

全网最适合入门的面向对象编程教程:57 Python字符串与序列化-序列化与反序列化

全网最适合入门的面向对象编程教程:58 Python字符串与序列化-序列化Web对象的定义与实现

全网最适合入门的面向对象编程教程:59 Python并行与并发-并行与并发和线程与进程

更多精彩内容可看:

给你的 Python 加加速:一文速通 Python 并行计算

一文搞懂 CM3 单片机调试原理

肝了半个月,嵌入式技术栈大汇总出炉

电子计算机类比赛的“武林秘籍”

一个MicroPython的开源项目集锦:awesome-micropython,包含各个方面的Micropython工具库

Avnet ZUBoard 1CG开发板—深度学习新选择

SenseCraft 部署模型到Grove Vision AI V2图像处理模块

文档和代码获取:

可访问如下链接进行对文档下载:

https://github.com/leezisheng/Doc

本文档主要介绍如何使用 Python 进行面向对象编程,需要读者对 Python 语法和单片机开发具有基本了解。相比其他讲解 Python 面向对象编程的博客或书籍而言,本文档更加详细、侧重于嵌入式上位机应用,以上位机和下位机的常见串口数据收发、数据处理、动态图绘制等为应用实例,同时使用 Sourcetrail 代码软件对代码进行可视化阅读便于读者理解。

相关示例代码获取链接如下:https://github.com/leezisheng/Python-OOP-Demo

正文

接下来,我们将运用之前学习过的内容实现如下任务:

  • 模拟传感器线程生成数据,通过串口协议传输给模拟主机进程;
  • 模拟主机进程通过串口发送给传感器线程指令以获取数据,进行数据滤波和处理,并将数据传输给绘图线程;
  • 绘图线程完成数据曲线绘制和更新操作。

可以注意到,我们之前为了阐述面向对象编程的技巧,所提及的某些类和类之间的关联设计,在实际应用中并非最佳实践。此外,原先的程序代码中,为了增强读者的直观感受,我们使用了大量的 print 语句进行输出。然而,这样的做法在程序进行并行运行时,不仅会降低整体的执行效率,而且在观察终端输出时,对于多线程或多进程的运行顺序也易造成混淆,使得理解变得困难。因此,我们有必要对这部分代码进行优化调整,以提高程序的性能和可读性。

在以下代码中,我们定义了一个 MasterProcess 主机多进程类,它继承了 Process 类,用于创建和管理主机多进程。可以看到 MasterProcess 主机多进程类直接在__ReadMasterSerial 和__WriteMasterSerial 方法中实现了串口的读写,而不像原先代码 MasterClass 类继承于 SerialClass 类。

示例代码如下:

class MasterProcess(Process):
'''
主机多进程类
'''
_# 类变量:_
_# START_CMD - 开启命令 -0_
_# STOP_CMD - 关闭命令 -1_
_# SENDID_CMD - 发送ID命令 -2_
_# SENDVALUE_CMD - 发送数据命令 -3_
START_CMD, STOP_CMD, SENDID_CMD, SENDVALUE_CMD = (0, 1, 2, 3) def __init__(self,
lock,
Queue,
simplequeue,
port:str = "COM17",
baudrate:int = 115200,
bytesize:int = serial.EIGHTBITS,
parity :str = serial.PARITY_NONE,
stopbits:int = serial.STOPBITS_ONE):
'''
MasterProcess初始化函数
:param lock: 互斥锁
:param Queue: 队列
:param port: 端口号
:param baudrate: 波特率
:param bytesize: 数据位
:param parity: 校验位
:param stopbits: 停止位
'''
self.lock = lock
self.Queue = Queue
self.simplequeue = simplequeue
self.dev = serial.Serial()
self.dev.port = port
self.dev.baudrate = baudrate
self.dev.bytesize = bytesize
self.dev.parity = parity
self.dev.stopbits = stopbits
_# 设置读取timeout超时时间_
self.dev.timeout = 0.3
_# 设置写入timeout超时时间_
self.dev.write_timeout = 0.3
_# 数据缓存_
self.datalist = []
_# 滤波器长度_
self.filterlength = 3
_# 数据处理类实例_
self.dataprocessobj = DateProcessClass(self.datalist,self.filterlength)
_# Process初始化方法_
Process.__init__(self)
def StartMasterSerial(self):
'''
打开主机串口
:return: None
'''
self.dev.open()
def StopMasterSerial(self):
'''
停止主机串口
:return: None
'''
self.dev.close()
def __ReadMasterSerial(self):
'''
读取主机串口,私有方法
:return data[int] : 读取的数据
'''
_# 按行读取_
data = self.dev.readline()
_# 如果接收到字节的情况下,进行处理_
if data != b'':
_# 收到为二进制数据_
_# 用utf-8编码将二进制数据解码为unicode字符串_
_# 字符串转为int类型_
data = int(data.decode('utf-8', 'replace'))
_# 否则,设置data为-1_
else:
data = -1
return data
def __WriteMasterSerial(self,write_data):
'''
写入主机串口,私有方法
:param write_data: 写入的数据
:return:
'''
_# 非阻塞方式写入_
self.dev.write(write_data.encode())
_# 输出换行符_
_# write的输入参数必须是bytes格式_
_# 字符串数据需要encode()函数将其编码为二进制数据,然后才可以顺利发送_
_# \r\n表示换行回车_
self.dev.write('\r\n'.encode())
def RecvSensorID(self):
'''
读取传感器ID
:return sensorid[int] : 读取的传感器id号
'''
sensorid = self.__ReadMasterSerial()
return sensorid
def RecvSensorValue(self):
'''
读取传感器数据值
:return data[int] : 读取的传感器数据
'''
data = self.__ReadMasterSerial()
return data
def SendSensorCMD(self,cmd):
'''
主机发送命令
:param cmd : MasterProcess中的类变量
:return: None
'''
self.__WriteMasterSerial(str(cmd))

同时,我们在其中定义了一个 run 方法,这个方法在多进程启动后被调用。在这个方法中,首先打开串口,然后发送获取 ID 的指令,接收传感器的 ID 号。然后进入一个无限循环,每 9 次循环,计算一次最大值和最小值,并打印出来。然后发送获取数据的指令,接收传感器的数据,将数据放入队列和列表中,然后对数据进行滤波处理,将滤波后的数据放入另一个队列。最后,打印出接收到的传感器数据,并让当前进程休眠 0.5 秒。

示例代码如下:

def run(self):
'''
多进程start后运行的方法
:return: None
'''
_# 运行计数变量_
count = 0
_# 文件保存索引计数变量_
index = 0
_# 打开串口_
self.StartMasterSerial()
self.lock.acquire()
print(" Master Process Started ")
self.lock.release() _# 发送获取ID指令_
self.SendSensorCMD(self.SENDID_CMD)
_# 获取传感器ID号_
id = self.RecvSensorID() self.lock.acquire()
print(" Recv Sensor ID : ", id)
self.lock.release() while True:
if count == 9:
maxvalue = self.dataprocessobj.DateCalMax()
minvalue = self.dataprocessobj.DateCalMin()
self.lock.acquire()
print("----------------------------------")
print("Max Value: ", maxvalue)
print("Min Value: ", minvalue)
print("----------------------------------")
self.lock.release()
count = 0
else:
count = count + 1 _# 发送获取数据指令_
self.SendSensorCMD(self.SENDVALUE_CMD) self.lock.acquire()
print("Master Send SENDVALUE_CMD")
self.lock.release() _# 接收传感器数据值_
data = self.RecvSensorValue()
self.Queue.put(data) self.datalist.append(data)
filterdata,filterdatalist = self.dataprocessobj.DateFilter()
self.simplequeue.put(filterdata) self.lock.acquire()
print(" Recv Sensor Data : ",data)
self.lock.release() time.sleep(0.5)

同时,我们需要注意 MasterProcess 主机进程类和 DateProcessClass 数据处理类为组合关系,使用如下语句实现:

_# 数据缓存_
self.datalist = []
_# 滤波器长度_
self.filterlength = 3
_# 数据处理类实例_
self.dataprocessobj = DateProcessClass(self.datalist,self.filterlength)

同时我们重写了 DateProcessClass 数据处理类,为方便理解程序运行情况,我们去掉了异常类、日志和 print 输出语句,同时在 DateFilter 方法中将计算出的平均值也进行返回。

class DateProcessClass():
def __init__(self, DateList: List[int], FilterLength: int):
self.DateList = DateList
self.FilterLength = FilterLength
self.TempList = [0] * (self.FilterLength) def DateFilter(self) -> List:
_# 遍历DateList_
for index, value in enumerate(self.DateList):
_# 把每个值都当成传入的新的传感器的值_
NowValue = value
_# 表示列表求和的变量_
sum = 0
for i in range(self.FilterLength - 1):
_# 实现列表的移位操作_
self.TempList[i] = self.TempList[i + 1]
_# 实现列表求和_
sum += self.TempList[i]
self.TempList[self.FilterLength - 1] = NowValue
sum += self.TempList[self.FilterLength - 1]
_# 求平均值_
average = sum / self.FilterLength
_# 将计算得到的平均值替换原始值_
self.DateList[index] = average
_# 计算完成后将TempList中元素清零_
self.TempList = [0] * (self.FilterLength)
return average,self.DateList def DateCalMax(self) -> int:
max_value = max(self.DateList)
return int(max_value) def DateCalMin(self) -> int:
min_value = min(self.DateList)
return int(min_value)

同时,我们重写了绘图类,该类包含了初始化、数据更新和定时更新等方法。在初始化方法中,程序创建了一个 Qt 应用实例对象、一个多面板图形窗口对象以及两个绘图曲线对象。数据更新方法用于接收传感器数据并将其添加到缓存列表中,然后将数据转化为图形。定时更新方法则用于定时进行曲线更新。

这里主要对 GetValue 方法和 DataUpdate 方法进行改写,同时我们可以看到在初始化方法和绘图曲线中增加了滤波后数据的相关属性,用于查看滤波效果。

示例代码如下:

class PlotThread:
def __init__(self,lock,queue,simplequeue,wintitle:str="Basic plotting examples",plottitle:str="Updating plot",width:int=1000,height:int=600):
'''
用于初始化PlotThread类
:param wintitle: 窗口标题
:param plottitle: 图层标题
:param width: 窗口宽度
:param height: 窗口高度
'''
self.lock = lock
self.queue = queue
self.simplequeue = simplequeue
_# Qt应用实例对象_
self.app = None
_# 窗口对象_
self.win = None
_# 设置窗口标题_
self.title = wintitle
_# 设置窗口尺寸_
self.width = width
self.height = height
_# 传感器数据_
self.value = 0
_# 存放滤波后数据_
self.filtervalue = 0
_# 计数变量_
self.__count = 0
_# 传感器数据缓存列表_
self.valuelist = []
_# 传感器滤波数据缓存列表_
self.filtervaluelist = []
_# 绘图曲线_
self.curve = None
_# 滤波后绘图曲线_
self.filtercurve = None
_# 图层对象_
self.plotob = None
_# 图层标题_
self.plottitle = plottitle
_# 定时器对象_
self.timer = QtCore.QTimer()
_# 定时时间_
self.time = 0
_# Qt应用和窗口初始化_
self.appinit() self.lock.acquire()
print(" PlotClass Object Init Complete ")
self.lock.release() def appinit(self):
'''
用于qt应用程序初始化,添加窗口、曲线和图层
:return: None
'''
_# 创建一个Qt应用,并返回该应用的实例对象_
self.app = pg.mkQApp("Plotting Example")
_# 生成多面板图形_
_# show:(bool) 如果为 True,则在创建小部件后立即显示小部件。_
_# title:(str 或 None)如果指定,则为此小部件设置窗口标题。_
self.win = pg.GraphicsLayoutWidget(show=True, title=self.title)
_# 设置窗口尺寸_
self.win.resize(self.width, self.height)
_# 进行窗口全局设置,setConfigOptions一次性配置多项参数_
_# antialias启用抗锯齿,useNumba对图像进行加速_
pg.setConfigOptions(antialias=True, useNumba=True) _# 添加图层_
self.plotob = self.win.addPlot(title=self.plottitle)
_# 添加曲线_
_# 原始数据-黄色曲线_
self.curve = self.plotob.plot(pen='y')
_# 滤波后数据-红色曲线_
self.filtercurve = self.plotob.plot(pen='r') def GetValue(self,value,filtervalue):
'''
用于接收传感器数据,加入缓存列表
:param value: 传感器数据
:param filtervalue: 传感器滤波后数据
:return: None
'''
self.value = value
self.valuelist.append(self.value)
self.filtervalue = filtervalue
self.filtervaluelist.append(self.filtervalue) def DataUpdate(self):
'''
用于定时进行曲线更新,这里模拟绘制正弦曲线
:return: None
'''
self.value = self.queue.get()
self.filtervalue = self.simplequeue.get()
self.GetValue(self.value,self.filtervalue)
_# 将数据转化为图形_
self.curve.setData(self.valuelist)
self.filtercurve.setData(self.filtervaluelist) def SetUpdate(self,time:int = 100):
'''
设置定时更新任务
:param time: 定时的时间
:return: None
'''
_# 定时器结束,触发DataUpdate方法_
self.timer.timeout.connect(self.DataUpdate)
_# 启动定时器_
self.timer.start(time)
_# 定时时间_
self.time = time
_# 进入主事件循环并等待_
pg.exec()

GetValue 方法用于接收传感器数据并将其加入缓存列表,DataUpdate 方法定时运行,它使用队列接收 MasterProcess 进程中产生和传输的数据,并将更新后的数据通过 setData 方法实现绘图曲线的更新。可以看到,数据的绘图和更新都是在主线程中进行的,这是由于在使用 PyQtGraph 绘图时,如果在主线程之外进行绘图操作,可能会出现绘图不生效或程序崩溃的问题。

在主线程中完成创建互斥锁、消息队列和进程实例,然后创建传感器线程和绘图线程实例,最后启动进程和线程。示例代码如下:

if __name__ == "__main__":
_# 创建互斥锁_
lock = Lock()
_# 创建消息队列_
queue = Queue(5)
_# 创建消息队列_
simplequeue = SimpleQueue() _# 创建进程实例_
m_process = MasterProcess(lock,queue,simplequeue,port = "COM17")
_# 创建线程实例_
s_thread = SensorThread(lock,port="COM11", id=0, state=SensorThread.WORK_MODE["RESPOND_MODE"])
_# 创建绘图类实例_
p_thread = PlotThread(lock,queue,simplequeue) _# 启动进程_
m_process.start()
_# 开启线程,start方法以并发方式执行_
s_thread.start()
_# 启动p_thread的定时任务_
p_thread.SetUpdate(600)

接下来,我们运行程序:

可以看到整个程序可以并行运行,对于并行运行的 Python 程序来说,我们可以使用 Profile/CProfile 等工具进行分析调试,或者利用 viztracer/SnakeViz 等可视化工具生成线程/进程运行的火焰图,这些工具可以完成记录函数的入口/出口,函数参数/返回值、任意变量的值以及线程/进程的运行顺序等操作。

全网最适合入门的面向对象编程教程:60 Python面向对象综合实例-传感器数据实时绘图器的更多相关文章

  1. 最适合入门的Laravel中级教程(一)

    Laravel 是一个全栈框架: 我们使用 Laravel 开发业务常见有 3 个方向: 前端页面和后端逻辑混合的应用 主要是面向对 SEO 有需求的项目: 比如说新闻资讯博客文章等: 一般在控制器中 ...

  2. [.net 面向对象编程基础] (2) 关于面向对象编程

    [.net 面向对象编程基础]  (2)  关于面向对象编程 首先是,面向对象编程英文 Object-Oriented Programming 简称 OOP 通俗来说,就是 针对对象编程的意思 那么问 ...

  3. 洗礼灵魂,修炼python(31)--面向对象编程(1)—面向对象,对象,类的了解

    面向对象 1.什么是面向对象 (图片来自网络) 哈哈,当然不是图中的意思. 1).面向对象(Object Oriented,OO)是软件开发方法.利用各大搜索引擎得到的解释都太官方,完全看不懂啥意思对 ...

  4. python自动化测试学习笔记-7面向对象编程,类,继承,实例变量,邮件

    面向对象编程(OOP)术语: class TestClass(object):   val1 = 100       def __init__(self):     self.val2 = 200   ...

  5. Python - 面向对象编程 - 什么是 Python 类、类对象、实例对象

    什么是对象和类 https://www.cnblogs.com/poloyy/p/15178423.html Python 类 类定义语法 最简单的类定义看起来像这样 class ClassName: ...

  6. 最适合入门的Laravel中级教程(二)用户认证

    之前的初级教程主要是学习简单的增删改查: 接着的中级教程的目标是在初级教程的基础上能写出更复杂更健壮的程序: 我们先来学习 laravel 的用户认证功能: 在现代网站中基本都有用户系统: 而我们每开 ...

  7. 最适合入门的Laravel中级教程(四)前端开发

    Laravel 使用 npm 安装前端依赖: npm 是一个类似 composer 的工具: 用于管理前端的各种依赖包: 在使用之前需要先安装 node : Windows 下可以在官网下载安装: h ...

  8. 最适合入门的Laravel中级教程(三)表单验证

    做开发有个原则是永远不能信任用户输入的数据: 即便前端已经做了验证: 在后端 php 也必须要再次验证: laravel 为表单验证提供了强大且简单的方案: 创建示例路由: routes/web.ph ...

  9. 【C语言入门教程】4.10 综合实例 - 媒体播放器

    4.10.1 建立播放列表 数据字典 名称 数据类型 说明 MAX_LENGTH 符号常量 用于定义数组长度,表示列表最大长度 MAX_FILE_LENGTH 符号常量 用于定义数组长度,表示文件名最 ...

  10. Laravel初级教程浅显易懂适合入门

    整理了一些Laravel初级教程,浅显易懂,特适合入门,留给刚学习laravel想快速上手有需要的朋友 最适合入门的laravel初级教程(一)序言 最适合入门的laravel初级教程(二)安装使用 ...

随机推荐

  1. CSS – Counters

    介绍 counter 有点像 JS 的 for loop index. 最常用到的地方就是做 ol > li. 参考: W3Schools – CSS Counters 默认 ol > l ...

  2. YAML编写应用的资源清单文件(十五)

    上面我们在 Kubernetes 中部署了我们的第一个容器化应用,我们了解到要部署应用最重要的就是编写应用的资源清单文件.那么如何编写资源清单文件呢?日常使用的时候我们都是使用 YAML 文件来编写, ...

  3. Windows安装winget

    打开GitHub链接地址:https://github.com/microsoft/winget-cli/releases 选择最新版本,点进去后 找到名为后缀名为 ".msixbundle ...

  4. 17 模块subprocess、re

    1. subprocess模块 1.1 概念 subprocess模块启动一个新进程,并连接到它们的输入/输出/错误管道,从而获取返回值 简单理解:可以远程连接电脑(socket模块) 1.2 Pop ...

  5. java使用正则表达式验证手机号和电话号码和邮箱号码的方法

    验证手机号 我国的手机号一般是以1开头,后面跟着10位数字.因此,可以用如下正则表达式: public static boolean isValidPhoneNumber(String phoneNu ...

  6. vue前端使用nexus配置npm私有仓库

    当我们运行前端项目的时候,常常在解决依赖的时候会加上一个参数npm install --registry=https://registry.npm.taobao.org将源指定为淘宝的源,以期让速度加 ...

  7. 03 Transformer 中的多头注意力(Multi-Head Attention)Pytorch代码实现

    3:20 来个赞 24:43 弹幕,是否懂了 QKV 相乘(QKV 同源),QK 相乘得到相似度A,AV 相乘得到注意力值 Z 第一步实现一个自注意力机制 自注意力计算 def self_attent ...

  8. Kali && Debain 防火墙规则

    Kali && Debain 防火墙规则 查看防火墙规则 iptables -L -n -v iptables -L -n -v 增加防火墙规则:开放指定的端口 iptables -A ...

  9. 云原生周刊:在 Kubernetes 集群中使用通配符证书 | 2024.2.19

    开源项目推荐 kube-fledged kube-fledged 是一个 Kubernetes Operator,用于直接在 Kubernetes 集群的工作节点上创建和管理容器映像的缓存.它允许用户 ...

  10. Rsync 秒杀一切备份工具,你能手动屏蔽某些目录吗?

    引言 Rsync 是一种快速且通用的命令行实用程序,可通过远程shell在两个位置之间同步文件和文件夹. 使用 Rsync,可以镜像数据,创建增量备份,并在系统之间复制文件.复制数据时,你可能要根据文 ...