本文主要目的是总结串口调试助手开发过程中遇到的问题和解决方法,以及总结通用资料以备后续参考,欢迎批评指正。
需要掌握的基础内容:
- 涉及到的python库的基本操作
- 串口通信基础
- 进制转换等算法问题
- python3基础语言和方法
本文安排:
- python库简介,包括tkiner、serial
- 开发上位机过程中遇到的函数调用方式、库方法使用方式
- 涉及具体算法需要掌握的知识基础
- 其他可能用到的资料
内容比较琐碎,可根据目录查看所需内容。详情查看所附链接。
开发上位机用到的python库
此处仅为库的简介,以及实际开发上位机过程中遇到的重要的控件。
serial简介
serial 是串口接口库,与串口通信相关的操作都需使用。
程序中import serial 实际安装的是pyserial库,关于pyserial的详细手册链接和资料,可参见: python库之pyserial用法_CSDN博客
import serial后,工程文件夹下会有serial文件夹。
serial文件夹中的serialwin32.py可以找到库函数的定义,如果看了上面链接中的函数说明仍然有疑惑,可以自行查看函数定义。
这个文件里有from serial import win32
涉及到win32的,可以到Microsoft文档中找资料,如下图为COMSTST结构体的说明。
PyQt5简介
Python上位机软件图形界面实战(2)_Funny-CSDN博客_python适合开发上位机吗
PyQt5是用于图形化界面设计的,仅设计界面,功能函数还需自己编写。对界面要求不高的上位机只需用tkinter库即可完成界面和功能的设计。
上位机图形界面开发设计用QT Designer就可以了。但是qt designer生成的是.ui文件,我们需要将.ui转换为我们用的py文件。
以下仅以tkinter和serial作为开发调试串口助手GUI的核心库,此外可能会用到time库进行延时操作。
tkinter简介
Graphical User Interfaces with Tk — Python 3.8.5 documentation
Python GUI 编程(Tkinter) | 菜鸟教程
tkinter库是Tcl / Tk的Python接口,用于制作和处理图形用户界面(Graphical User Interface,简称 GUI,又称图形用户接口)。
Tk / Tcl提供了与平台无关的窗口工具箱,使用tkinter软件包及其扩展名tkinter.tix和tkinter.ttk模块的Python程序员可以使用该工具箱。
tkinter包是Tcl / Tk之上的面向对象层。要使用tkinter,您无需编写Tcl代码,但您需要查阅Tk文档,有时还需要查阅Tcl文档。 tkinter是一组将Tk小部件实现为Python类的包装器。另外,内部模块_tkinter提供了线程安全机制,该机制允许Python和Tcl进行交互。
tkinter的主要优点是速度快,并且通常与Python捆绑在一起。尽管其标准文档weak,但仍然可以找到不错的材料,其中包括:参考资料,教程,书籍等。但是,您可能会对许多其他GUI库感兴趣,有关替代方法的更多信息,请参见“其他图形用户界面包”。
注意,不同版本的python调用库的名称不同。
#!/usr/bin/python3
import tkinter
# 创建Tk
top = tkinter.Tk()
# 进入消息循环
top.mainloop()
#!/usr/bin/python2
# -*- coding: UTF-8 -*-
import Tkinter
# 创建Tk
top = Tkinter.Tk()
# 进入消息循环
top.mainloop()
tkinter包含的控件
Python GUI之tkinter窗口视窗教程大集合 - 洪卫 - 博客园
控件介绍和基本操作见链接。
Tkinter支持16个核心的窗口部件,这个16个核心窗口部件类简要描述如下:
控件 | 功能 |
---|---|
Button | 一个简单的按钮,用来执行一个命令或别的操作。 |
Canvas | 组织图形。这个部件可以用来绘制图表和图,创建图形编辑器,实现定制窗口部件。 |
Checkbutton | 代表一个变量,它有两个不同的值。点击这个按钮将会在这两个值间切换。 |
Entry | 文本输入域。 |
Frame | 一个容器窗口部件。帧可以有边框和背景,当创建一个应用程序或dialog(对话)版面时,帧被用来组织其它的窗口部件。 |
Label | 显示一个文本或图象。 |
Listbox | 显示供选方案的一个列表。listbox能够被配置来得到radiobutton或checklist的行为。 |
Menu | 菜单条。用来实现下拉和弹出式菜单。 |
Menubutton | 菜单按钮。用来实现下拉式菜单。 |
Message | 显示一文本。类似label窗口部件,但是能够自动地调整文本到给定的宽度或比率。 |
Radiobutton | 代表一个变量,它可以有多个值中的一个。点击它将为这个变量设置值,并且清除与这同一变量相关的其它radiobutton。 |
Scale | 允许你通过滑块来设置一数字值。 |
Scrollbar | 为配合使用canvas, entry, listbox, and text窗口部件的标准滚动条。 |
Text | 格式化文本显示。允许你用不同的样式和属性来显示和编辑文本。同时支持内嵌图象和窗口。 |
Toplevel | 一个容器窗口部件,作为一个单独的、最上面的窗口显示。 |
messageBox | 消息框,用于显示你应用程序的消息框。(Python2中为tkMessagebox) |
注意在Tkinter中窗口部件类没有分级;所有的窗口部件类在树中都是兄弟关系。
所有这些窗口部件提供了Misc和几何管理方法、配置管理方法和部件自己定义的另外的方法。此外,Toplevel类也提供窗口管理接口。这意味一个典型的窗口部件类提供了大约150种方法。
mainloop的实质
mainloop()是tkinker的界面初始化完成后,开启界面及其调度管理功能的函数。用户只需按照库中已有的方法编写好所需的功能和界面,再执行mainloop,就可以实现上位机的程序开发过程。
以下伪代码说明了其实质:链接
def mainloop():
while the main window has not been closed:
if an event has occurred:
run the associated event handler function
只要GUI还在屏幕上,mainloop调用就不会返回执行代码。
tkinter text
text:Python - Tkinter Text - Tutorialspoint
上面的链接中介绍了tkinter库中的关于文本text的属性、方法等。需要GUI显示多行文字时使用,常见的应用是显示输出数据、显示输入文字等。下面是关于方法的截图,insert用于在文本中添加内容,see用于选择GUI上显示的位置。
text在GUI上长这样:
Scrollbar控件-添加滑动条
Tkinter 组件详解(九):Scrollbar_一只没有脚的猪的博客-CSDN博客
Scrollbar 组件通常与 Text 组件、Canvas 组件和 Listbox 组件一起使用,水平滚动条还能跟 Entry 组件配合。
text控件默认没有滑动条,所以当文本内容超出窗口大小时不能判断内容的多少和位置,很不方便。下面是scrollbar和text一起使用的例子。
如果只有一个滑动条,还可以绑定鼠标滚轮和滑动条(绑定后鼠标即使不点击选中窗口,滑动滚轮也可以翻页)
# 给text添加滑动条:
# 设置滑动条,设置其位置
st = tkinter.Scrollbar(self.mainwin) # 在text旁边加
# st.pack(side=tkinter.RIGHT, fill=tkinter.Y) # 在整个窗口旁边加滑动条
# text
self.SendDataView = ScrolledText(self.mainwin, width=60, height=3,
font=("宋体", 10)) # text实际上是一个文本编辑器
self.SendDataView.place(x=230, y=35) # 显示
# 在text右边添加滑动条
self.SendDataView.focus_set() # 不知何用?
st.config(command=self.SendDataView.yview)
# 绑定鼠标滚轮和滑动条
# self.mainwin.bind("<MouseWheel>", self._on_mousewheel)
numpy
threading库简介
手册(全英文):threading — Thread-based parallelism — Python 3.8.5 documentation
threading:Python 3 之后的线程模块,提供了功能丰富的多线程支持,推荐使用。
Python 主要通过两种方式来创建线程:(链接)
- 使用 threading 模块中 Thread 类的构造器创建线程。即直接对类 threading.Thread 进行实例化创建线程,并调用实例化对象的 start() 方法启动线程。
- 继承 threading 模块中的 Thread 类创建线程类。即用 threading.Thread 派生出一个新的子类,将新建类实例化创建线程,并调用其 start() 方法启动线程。
线程需要手动启动才能运行,threading 模块提供了 start() 方法用来启动线程。
import threading
def t_receive():
# 接收...
def t_save():
# 保存...
# 创建线程
t1 = threading.Thread(target=t_receive)
t2 = threading.Thread(target=t_save)
# 设置t2为守护线程,即服务程序
t2.setDaemon(True)
# 开启线程
t1.start()
t2.start()
# 线程占用CPU直至死亡
t1.join()
t2.join()
join
join() 方法的功能是在程序指定位置,优先让该方法的调用者使用 CPU 资源。该方法的语法格式如下:
thread1.join( [timeout] )
其中,thread1 为 thread 类或其子类的实例化对象;timeout 参数作为可选参数,其功能是指定 thread 线程最多可以霸占 CPU 资源的时间(以秒为单位),如果省略,则默认直到 thread 执行结束(进入死亡状态)才释放 CPU 资源。
开发串口调试助手
背景知识(新手入门):
关于串口上位机编程你需掌握的背景知识_Robert Zhang-CSDN博客
哈喽,上位机(上位机开发指南)_Robert Zhang_robert_cysy-CSDN博客
基本过程:
- 完成所需功能(选择串口、选择波特率、发送、接收、显示、输出结果到文件)
- 设计界面(文本、按钮、选项框、大小、位置、颜色)
- 连接功能函数和界面
- 测试,解决bug
- 封装,打包为exe文件等等
代码重点参考:
python实现串口通讯小程序(GUI界面)_明志的博客-CSDN博客_pycharm 开发串口
上位机开发工具对比:
原来这才是大家常用的上位机开发平台_Robert Zhang-CSDN博客
下面只总结一些具体的方法和代码。
串口类
定义串口处理类,后续操作可直接调用。
import serial
import serial.tools.list_ports
# 串口处理类
class SerialAchieve:
def __init__(self, band=3000000, check="无校验位", data=8, stop=1):
self.port = None
# 获取可用串口
self.port_list = list(serial.tools.list_ports.comports())
assert (len(self.port_list) != 0), "无可用串口"
self.bandRate = band
self.checkbit = check
self.databit = data
self.stopbit = stop
# 读写的数据
self.read_data = None
self.write_data = None
pass
def show_port(self):
for i in range(0, len(self.port_list)):
print(self.port_list[i])
def show_other(self):
print("波特率:" + self.bandRate)
print("校验位:" + self.checkbit)
print("数据位:" + self.databit)
print("停止位:" + self.stopbit)
# 返回串口
def get_port(self):
return self.port_list
# 打开串口
def open_port(self, port):
self.port = serial.Serial(port, self.bandRate, timeout=1) # timeout=None
# 关闭串口
def delete_port(self):
if self.port != None:
self.port.close()
print("关闭串口完成")
else:
pass
def Read_data(self): # self.port.read(self.port.in_waiting) 表示全部接收串口中的数据
self.read_data = self.port.read(self.port.in_waiting) # 读取数据
return self.read_data.decode("utf-8")
def Write_data(self, data):
if self.port.isOpen() == False:
print("串口打开错误")
else:
self.port.write(data.encode("utf-8")) # 返回的是写入的字节数
# 主类
class MainSerial:
def __init__(self):
# 定义串口变量
self.port = None
self.band = None
self.check = None
self.data = None
self.stop = None
self.myserial = None
# 创建串口对象
self.myserial = SerialAchieve(int(self.band), self.check, self.data, self.stop)
# 处理串口值
self.port_list = self.myserial.get_port()
port_str_list = [] # 用来存储切割好的串口号
for i in range(len(self.port_list)):
# 将串口号切割出来
lines = str(self.port_list[i])
str_list = lines.split(" ")
port_str_list.append(str_list[0])
# 主函数
if __name__ == '__main__':
my_ser1 = MainSerial()
my_ser1.show()
打包GUI程序为exe文件
如果要脱离python环境使用,则需要将写好gui的python3的py文件打包成exe程序。
链接:
步骤(详细步骤见链接):
- 在命令窗口安装pyinstaller库
- 在命令窗口切换到打包程序目录
例:需要打包程序目录为:D:\automation\autotest_tool\interface_param_change_tool
切换指令:cd D:\automation\autotest_tool\interface_param_change_tool - 打包文件,pyinstaller -F xxx.py(xxx.py,打包的文件)
例:需要打包的python程序为:runner.py
指令:pyinstaller -F runner.py - 检查是否成功,到打包文件目录查看打包好的程序,并执行
打包成功后项目中新增dist文件,进入dist文件,点击运行打包好的exe程序
错误解决
读取串口数据时崩溃、无数据、数据不全
python-在Python3.7的环境下,每次都是执行到serial.read()就卡住了。——CSDN问答频道
上位机崩溃(不断输出,鼠标点击后无响应)。
可能是由于陷入死循环中,阻塞了,不能进行其他操作。可检查读取串口的函数,看看是不是无限循环,无法退出。还可能是要读取的数据太多了,超出缓存区大小。
解决:增加退出条件,或建立线程(需要操作系统相关知识)。
关于超出缓存的问题,可参考下面链接关于缓存区大小和解决思路的讨论:
串口一次最大能接收多少字节-CSDN论坛
上位机要接收两次才能将下位机发送数据显示完全。
- 缓冲区决定一次接收数据大小。
- 一般串口硬件只有1个字节缓冲,其他都是系统自己的内存做暂存缓冲的,而且一般不会很大。最好自己设置一个内存,多少取决于你的内存大小,中断消息处理串口数据,存到自己的缓冲区,等到字节到了你需要的,再从缓冲区读出。这样就非常灵活了。链接
接收数据,但无数据显示。
首先排除单片机确实无数据发送的情况,再考虑是否由于没有增加延时,导致缓存区里没有储存到单片机发送的数据。
解决:在读取串口数据之前增加延时语句。延时可import time,使用time库中的time.sleep(sec),参数单位为秒。
补充:
- serial.iswaiting启动接收,并返回接收数据的长度,然后用read(n)将这指定的数据读出来。但现实中的问题是两者的中间需要加延时(根据波特率计算发送内容所需的时间,这样就不会出现延时过短读出的不全;延时时间长了就会出现前后帧发出的内容重合到一起),此外如果需要判断什么时候串口不活动,可以再serial.iswaiting一直延时(超过几个字符的传送时间,软件延时计数器累加),而在循环体外将计数器清零,在累计的几个字符时间接受的数据长度还为0则认为通讯结束。链接
数据不全,有数据显示,但缺少了内容。
可能是单片机发送的时间长,延时时间比数据发送时间短,所以缓存中内容只有显示的那些数据。还可能是由于接受串口数据晚了,单片机发的数据没及时存到缓存里。还可能是由于接收及显示期间有中断打断该过程,执行完毕后经过一段时间,等到返回原程序处时已不能实现实时接收和显示的功能。
解决:延时时间加长(延时期间不能进行操作,为阻塞状态,不推荐),或考虑中断返回后进行判断,进一步处理,或建立多线程。
丢包
网络丢包:
什么是丢包,为什么会丢包 - 知乎
数据丢包:
下位机、PC都有能力高速发送或接受数据,但过高的传输速率(高波特率)意味着,中间的传输线路一旦受到干扰更容易发生电平不能及时转换的问题。从帮助理解的角度,可以将数据看作一位一位的0/1组成的值,传输本身是高低电平的转换,高电平代表1,低电平代表0。
数据丢包的原因:噪声干扰、强磁场环境
间接原因:波特率过高,更易出错
解决:尽量在满足应用速度要求的前提下,低速率传输;采用可靠的协议;保持硬件稳定。
数据显示不全与数据丢包要区分开,丢包是在传输途中出现问题,显示不全可能是由于丢包,也可能是由于上位机程序逻辑编写错误,或者单线程且处理数据紧接在接收数据之后,导致处理数据时接收值未显示,而下次显示时缓存中已被新数据覆盖等等。
串口通信之数据丢失
串口通信丢失数据结局方案——C#_紫冰寒寞的专栏-CSDN博客_serialport 字符缺失
串口通信的一般思路是:先接收数据,然后处理数据,并在数据处理之后再次等待接收新的数据。但这种方法的缺点是,在串口高速率大信息量通信时,会出现丢失数据的情况。
丢失数据的原因是数据接收和数据处理再同一个线程中,如果数据处理的时间太长,则来不及接收的数据只能暂存在缓存中。因此,一旦缓存满了,新到的数据就会冲刷掉未来得及接收的数据,从而造成数据的丢失。因此,只是增加缓存的容量不能解决数据丢失的根本问题。
解决思路:
- 数据接收与数据处理分别放在两个线程中进行;
- 数据接收线程:接收数据并将接收到的数据存入数据池中;
- 数据处理线程:从数据池中读取数据和处理数据;
注意:
- 由于两个线程可能会同时访问数据池,因此为了使数据接收得到最快的响应,最好不选用数组结构,而是选用队列Queue作为数据池的数据结构。
队列在顺序存储方面非常有用。数据对象在队列的一段插入,另一端移除。当两个线程同时访问队列时,一个线程负责数据存入,另一个线程只负责操作数读取,就会提高程序的运行效率。
为何丢失数据量的大小不确定?
举个例子,如果是由于单线程进行读取数据和处理数据,那么处理数据期间就不能读取,缓存区若溢出,则会被覆盖。如果处理数据的操作和量是固定的,按道理会丢失定量的数据,但实际上缓冲区中的数据量不一定,处理的数据量也不一定,读取的速度也有不确定性,所以丢失的数据量也不会是恒定的。
如果读取足够快,或者次数足够少,能够不影响数据继续写入缓存区,那么就能读取完整的数据,数据量等于发送量。
python相关
为什么要加if __name __==‘__main __’:
不写也可以启动,但最好加上,因为if __ name __ == ’ __ main __’的意思是:当.py文件被直接运行时,if __ name __ == ’ __ main __’之下的代码块将被运行;当.py文件以模块形式被导入时,if __ name __ == ’ __ main __’之下的代码块不被运行。
一些功能由于比较复杂,往往需要多人开发,一个python程序对应一个功能,为便于测试,每个功能程序下都有一个主函数。在主程序中,只需import功能程序所在文件,就可以调用功能py程序的函数(关于如何跨文件调用函数见本文目录)。为了保证功能文件中的主函数不被导入到主函数中,就需要注释掉每个功能程序中的主函数,这十分的麻烦。因此python提供了if __name __==‘__main __’:条件,只要编写主函数时均在此条件下编写,就可以保证运行哪个程序就用哪个主函数。
来自链接:https://blog.csdn.net/qq_25939803/article/details/98038106
线程
python多线程详解 - luyuze95 - 博客园
链接目录:
python多线程详解
一、线程介绍
什么是线程
为什么要使用多线程
二、线程实现
threading模块
自定义线程
守护线程
主线程等待子线程结束
多线程共享全局变量
互斥锁
递归锁
信号量(BoundedSemaphore类)
事件(Event类)
三、GIL(Global Interpreter Lock)全局解释器锁
并发与并行
几乎所有的操作系统都支持同时运行多个任务,每个任务通常是一个程序,每一个运行中的程序就是一个进程,即进程是应用程序的执行实例。现代的操作系统几乎都支持多进程并发执行。
- 并行指在同一时刻有多条指令在多个处理器(多核处理器)上同时执行
- 并发是指在同一时刻只能有一条指令执行,但多个进程指令被快速轮换执行,使得在宏观上具有多个进程同时执行的效果。
线程与进程
首先需要强调的是,线程和进程对于开发一般的上位机串口助手不是必须的,尤其是对于操作系统不够了解的新手来说,使用线程需要补充很多基础知识,较为耗时。
对于一个 CPU 而言,在某个时间点它只能执行一个程序。也就是说,只能运行一个进程,CPU 不断地在这些进程之间轮换执行。那么,为什么用户感觉不到任何中断呢?
这是因为相对人的感觉来说,CPU 的执行速度太快了(如果启动的程序足够多,则用户依然可以感觉到程序的运行速度下降了)。所以,虽然 CPU 在多个进程之间轮换执行,但用户感觉到好像有多个进程在同时执行。
单线程与多线程
- 当一个进程里只有一个线程时,叫作单线程。
- 一个进程里超过一个线程就叫作多线程。
线程是进程的组成部分,一个进程可以拥有多个线程。在多线程中,会有一个主线程来完成整个进程从开始到结束的全部操作,而其他的线程会在主线程的运行过程中被创建或退出。
当进程被初始化后,主线程就被创建了,对于绝大多数的应用程序来说,通常仅要求有一个主线程,但也可以在进程内创建多个顺序执行流,这些顺序执行流就是线程。
每个线程必须有自己的父进程,且它可以拥有自己的堆栈、程序计数器和局部变量,但不拥有系统资源,因为它和父进程的其他线程共享该进程所拥有的全部资源。线程可以完成一定的任务,可以与其他线程共享父进程中的共享变量及部分环境,相互之间协同完成进程所要完成的任务。
线程的运行是抢占式的,也就是说,当前运行的线程在任何时候都可能被挂起,以便另外一个线程可以运行。
多线程也是并发执行的,即同一时刻,Python 主程序只允许有一个线程执行,这和全局解释器锁有关系,后续会做详细介绍。
一个线程可以创建和撤销另一个线程,同一个进程中的多个线程之间可以并发运行。
从逻辑的角度来看,多线程存在于一个应用程序中,让一个应用程序可以有多个执行部分同时执行,但操作系统无须将多个线程看作多个独立的应用,对多线程实现调度和管理以及资源分配,线程的调度和管理由进程本身负责完成。
常见异常类型
Python 常见异常类型 - Bactiy - 博客园
python 异常类型_Lapland的博客-CSDN博客
异常处理:
python中的异常及几种常见异常_棠牧师的博客-CSDN博客
try: 功能,应该做什么
except: 若有异常,做什么
重命名变量方法
右键变量名称-> Refactor-> Rename
直接重命名所有同名变量。
运算
原码补码转换
代码:
python——原码转补码_cherry1307的博客-CSDN博客_python原码转补码
- 源码转补码或补码转源码都可用同一步骤实现
- 何时转换:有符号型二进制数且符号位为1时才需要转换
- 转换步骤:除最高位1外,其余位取反得到反码,反码加1得补码或原码。
- 代码:见上面的链接,亲测可用,感谢博主
python指数**
例:求次方、根号、倒数
# 2的立方
print(2**3)
# 8
# 9开二次方根
print(9**(1/2))
# 3.0
# 2平方的倒数
print(2**(-2))
# 0.25
数值与字符串
python读取字符串长度len()
len()的参数只能是字符串类型。
例:
print(len('0b10001'))
# 7
python的数值与字符串区分
‘10001’:字符串
10001:十进制
‘0b10001’:字符串
0b10001:二进制
print(bin(17))显示0b10001,没问题。
不过,print(0b10001)显示的是十进制17,而不是0b10001,有人知道这是为什么吗?
若有误,欢迎指正留言。
python二进制-十进制转换
python十进制转换为二进制,八进制_qq_37178232的博客-CSDN博客_十进制6转二进制的计算过程python
十进制转二进制:
bin()函数,例子:17的二进制数是10001,bin(17)为0b10001
bin函数得到二进制字符串
def mybin(a):#自定义函数去除系统自带的多余0b
b=bin(a) # a为int型整数17,bin(a)为0b10001
b=b.replace('0b','') # 用空字符替代0b
print(b)
mybin(17) # 结果 10001
注意:bin转换的二进制默认最高位为1,高位的0会被去除,即0b类型。
注意:replace() 不会改变原 string 的内容,要想改变需要重新赋值给原string。
二进制转十进制:
注意:bin()转换的结果是字符串,不能直接用int()转换为十进制整型,只有去除0b才可以,因为字母不能转换为int。
print(int(0b10001)) # 输出17
# b=bin(7)
# print(int(b))
# ValueError: invalid literal for int() with base 10: '0b10001'
注意:默认在int()中转换的是无符号原码,若有符号位要自行去除符号位并根据情况乘以-1(符号位为1,则需将除去符号位的原码转化为十进制后再乘以-1);若为补码,要自行判断是否需要转换为原码(正数的原码等于补码)。
注意:要判断二进制位数是否有缺,尤其对于有符号位的二进制,若缺位,容易将本来符号位为0的正数当作符号位为1的负数处理。(字符串补零用str.zfill(n),将str数组总位数补到n位)
啰嗦一句,位数不够或无符号位,就可以直接转换;有符号位且位数齐全且符号位为1,则必须注意上述提醒。
python字符串转十进制整型
Python进制转换和补零_iridescent_mian的博客-CSDN博客_python hex 补0
(各种进制转换和类型转换详见链接)
从文档中读取的数据可能是string格式,运算时需要转化为可以计算的数值
注意:str字符串不能直接强制转换为二进制数,要先转换为十进制后再转换为二进制。
str = "12345"
num = int(str) # 转为整型12345
# num_bin = bin(str)
# TypeError: 'str' object cannot be interpreted as an integer
非数值字符串不能转换,会报错。
python截取字符串
python按照指定字符或者长度 截取字符串 - pager - 博客园
截取字符串可以按照给定截取字符位置的方式截取:
如,a为一个字符串,则
a[0] 为字符串a从左往右数第1个字符
a[:1]为字符串a从左往右数第1个字符
a[1:]为字符串a从左往右数从第2个字符开始的所有字符
a[-1:]为字符串a从右往左数第1个字符
a[:-1]为字符串a从右往左数第2个字符开始的所有字符(顺序不变)
例:
a = "Hello"
print "a[1:4] 输出结果:", a[1:4] #结果 ell
print "a[:4] 输出结果:", a[:4] #结果 Hell
print "a[1:] 输出结果:", a[1:] #结果 ello
print "a[-1:] 输出结果:", a[-1:] #结果o
print "a[:-1] 输出结果:", a[:-1] #结果Hell
截取字符串也可以按照给定截取字符标志的方式截取:
即根据特定字符为界,截取特定字符之前或之后的字符串。
例:
a = "Hello"
symbol = 'e' # 截取字符标志
# 截取e字符左半部分
a_l = a[:a.index(symbol)]
# 截取e字符右半部分,包括e
a_r = a[a.index(symbol):]
print(a_l) #结果 H
print(a_r) #结果 ello
注:截取字符标志也可以是’\t’等符号。
python 替换字符串
temp_str = 'this is a test'
print(temp_str.replace('is','IS')
print(temp_str)
# 输出
# thIS IS a test
# this is a test
temp_str = temp_str.replace('is','IS')
print(temp_str)
# 输出
# thIS IS a test
注意:replace() 不会改变原 string 的内容,要想改变需要重新赋值给原string。
列表插入元素append
python中没有数组的数据结构,可以用列表代替。
列表的声明:
# 声明一个空列表
a = []
# 声明一个列表
b = ['3', '4']
插入元素:
# 创建列表并增加元素
a = ['!3']
a.append('a')
a.append('bc')
a.append('123')
print(a)
# ['!3', 'a', 'bc', '123']
# 将第4个元素切片(截取)
a[3] = a[3][2:]
print(a)
# ['!3', 'a', 'bc', '3']
python 二维列表
# 声明一维列表
list1 = []
# 声明二维列表list1,list1含1个列表元素
list1.append([])
list1[0].append('1')
list1[0].append(2)
# 声明二维列表list1,list1含2个列表元素
list1.append([])
list1[1].append('3')
list1[1].append('4')
# 声明二维列表list1,list1含3个列表元素
list1.append([])
list1[2].append('567')
print(len(list1))
print(list1)
print(str(list1))
print(int(list1[2][0]))
# 结果:
# 3
# [['1', 2], ['3', '4'], ['567']]
# [['1', 2], ['3', '4'], ['567']]
# 567
python二维列表对应元素相加
Python之list对应元素求和的方法_python_脚本之家
方法1:直接用for循环相加
方法2:用numpy模块定义数组,数组1+数组2
方法3:用numpy模块定义数组,用sum()函数
import numpy as np
a = np.array([1,2,3])
b = np.array([2,3,4])
c = np.array([3,4,5])
# 方法2
print(a+b+c) # a+b+c后的类型为numpy.ndarray
# 输出
# [ 6 9 12]
# 方法3
print(np.sum([a,b,c], axis = 0)) # axis = 0:纵向求和
# 输出
# [ 6 9 12]
encode与decode
decode的作用是将其他编码的字符串转换成Unicode编码,如str1.decode(‘gb2312’),表示将gb2312编码的字符串str1转换成Unicode编码。
encode的作用是将unicode编码转换成其他编码的字符串,如str2.encode(‘gb2312’),表示将Unicode编码的字符串str2转换成gb2312编码。
str1.decode(‘utf-8’):将utf-8编码的字符串str1转换成Unicode编码。
文件
读写文件(txt、csv、excel)
Python读写文件(csv、txt、excel) - 简书
读写均由open()实现,结束后要close()关闭文件。
例:读text文件
# 以读的模式打开文件
f = open('C:/Users/Administrator/Desktop/output.txt', mode='r')
# 读取数据,读取方式有三种
ftext1 = f.read() # 一次性读取完成
ftext2 = f.readlines() # 同上
ftext3 = f.readline() # 只读取1行
# 关闭
f.close()
例:写text文件
# 以写的模式打开文件
f = open('C:/Users/Administrator/Desktop/input.txt', mode='w')
# 写入数据
ftext1 = f.write('hello!') # 一次性读取完成
# 关闭
f.close()
with open :
由于文件读写时都有可能产生IOError,一旦出错,后面的f.close()就不会调用。所以,为了保证无论是否出错都能正确地关闭文件,我们可以使用try … finally来实现,但是每次都这么写实在太繁琐,所以,Python引入了with语句来自动帮我们调用close()方法:
with open('/path/to/file', 'r') as f:
print(f.read())
补充:Python 将数据写入文件(txt、csv、excel)_菲宇运维-CSDN博客
文件操作模式
'w’模式下,每次写入都会覆盖原内容,若不想覆盖原内容,则用’a’模式。
python跨文件调用函数
python 一个.py文件如何调用另一个.py文件中的类和函数_winycg的博客-CSDN博客_python 引用另一个py文件
亲测可行,感谢博主
datetime库 获取当前时间
datetime.datetime.now()
import datetime
t_name = datetime.datetime.strftime(datetime.datetime.now(), '%m%d_%M:%S')
print(t_name)
# 0727_31:12
实例链接
计算器GUI实例
python带界面的计算器_qq_24624539的博客-CSDN博客_python计算器
可供小白学习快速熟悉python开发GUI。
串口调试助手GUI实例
python实现串口通讯小程序(GUI界面)_明志的博客-CSDN博客_pycharm 开发串口
该实例能够满足最基础的串口调试功能,发送命令和接收命令需手动操作。还能够实现串口自动读取连接。