概念
可向用户反馈报错信息。异常也是对象,可对他进行操作。所有的异常都是基类Exception的成员,异常是在exceptions模块中定义,Python自动将所有异常名称放在内建命名空间中,所以程序不必导入exceptions模块即可使用异常。
一旦引发而且没有捕捉SystemExit异常,程序执行就会终止。如果交互式会话遇到一个未被捕捉的SystemExit异常,会话就会终止。
异常是指程序运行时引发的错误,原因有除零、下标越界、文件不存在、网络异常、类型错误、名字错误、字典键错误、磁盘空间不足 、文件不存在、路径写错 缩进错误 将赋值运算符 = 和比较运算符==混淆
当Python解释 器遇到异常情况时,它会停止程序的运行,然后显示一个追踪(traceback) 信息。
SyntaxError;语法
IndentationError:缩进
TypeError: 数值不可修改 连接字符串和非字符串 忘记为类中第一个方法添加self
NameError : 变量没有定义
内置异常
定义在exceptions模块中,此模块在Python解释器启动时就会自动加载
异常处理结构
try……except……
编写程序接受用户输入,且要求用户必须输入整数,不接收其他类型的输入。
>>>while True:
x = input('Please input:')
try:
x = int(x)
print('You have input {0}'.format(x))
break
except Exception as e:
print('Error.')
Please input:234c
Error.
Please input:5
You have input 5
try……except……else
>>>while True:
x = input('Please input:')
try:
x = int(x)
except Exception as e:
print('Error')
else:
print('You have input [0]'.format(x))
break
Please input:888c
Error.
Please input:888
You have input 888
try……except……finally
filename = input('请输入一个文件名:')
try:
fp = open(filename) #尝试打开文件
try: #尝试读取数据并计算和输出
print(int(fp.read())+5)
except: #读取文件或计算失败时执行的代码
print('文件内容格式不正确。')
finally: #确保文件能够关闭
fp.close()
except: #打开文件失败时执行的代码
print('文件不存在')
异常类的实例和清除异常
每当有一一个异常被输出时,该异常类就会创建一个实例,此实例继承了异常类的所有属性。(最 重要的就是args属性)
try:
x = [1,2,3]
print(x[4])
except IndexError as err :
print(err.args[0])
list index out of range
IndexError: list index out of range
捕获多种异常处理结构
>>>try:
x = float(input('请输入整数:'))
y = float(input('请输入除数:'))
z = x / y
except ZeroDivisionError:
print('除数不能为零')
except ValueError:
print('被除数和除数应为数值类型')
except NameError:
print('变量不存在')
else:
print(x,'/',y,'=',z)
>>> a = 3
>>> b = 5
>>> assert a==b, 'a must be equal to b'
AssertionError: a must be equal to b
跟踪查看异常
发生异常时Python能够记住引发的异常以及程序的当前状态,Python还维护着traceback(跟踪)对象,其中含有异常发生时与函数调用堆栈有关的信息,异常可能在一系列嵌套较深的函数调用中引发,程序调用每个函数时,Python会在“函数调用堆栈”的起始处插入函数名,一旦异常被引发 ,Python会搜索一个相应的异常处理程序。
如果当前函数中没有异常处理程序,当前函数会终止执行,Python会搜索当前函数的调用函数,并以此类推,直到发现匹配的异常处理程序,或者Python抵达主程序为止,这一查找合适的异常处理程序的过程就称为“堆栈辗转开解”(Stack Unwinding)。解释器一方面维护着与放置堆栈中的函数有关的信息,另一方面也维护着与已从堆栈中“辗转开解”的函数有关的信息。
try:
block
except:
traceback.print_exc()
内置异常的协助模块
sys模块
sys模块中的exc_info()函数,可以取得目前正在处理的异常信息exc_info()函数会返回一个元组,这个元组包括三个元素。
import sys
try:
12/0
except:
info = sys.exc_info()
exc_type = info[0]
exc_value = info[1]
exc_traceback = info[2]
print(ecx_type,':',exc_value)
import sys
try:
12/0
except :
info=sys.exc_ info( )
exc_ type=info[0]
exc_ value = info[1]
exc_ traceback = info[2]
print(exc_ type, " :" ,exc_ value )
<class ' ZeroDivisionError'> : division by zero
traceback对象
使用sys模块的exc_ info() 函数返回值的第三个元素,会返回一个traceback对象。
traceback对象的接口函数可以捕捉、格式化,或是输出Python程序的堆栈追踪(traceback) 信息。
import traceback
try:
12/0
except :
traceback.print exc()
Traceback (most recent call last) ;
File "<ipython- input- 19- 71f6b5a77e1e>", line 4, in <module>
12/0
ZeroDivisionError: division by zero
抛出异常
raise NameError ('抛出了一个异常')
raise NameError( '这里是raise抛出的-个异常' )
NameError
Traceback (most recent cal1 last )
<ipython- input- 20-e274246dfc1f> in <module>
----> 1 raise NameError( '这里是raise抛出的一个异常')
NameError:这里是raise抛出的一 个异常
结束解释器的运行
用户可以利用输出SystemExit异常,来强迫结束解释器的运行
使用sys.exit()函数会输出一个SystemExit异常,sys.exit()会结束线程
import sys
try:
sys.exit()
except SystemExit:
print('目前还不能结束解释器运行')
#如果想正常结束解释器运行,最好利用OS模块的_exit()函数
离开嵌套循环
使用raise语句离开嵌套循环
class ExitLoop(Exception):
pass
try:
i = 1
while i < 10:
for j in range(1, 10):
print(i, j)
if (i == 2) and (j == 2):
raise(ExitLoop)
i += 1
except ExitLoop:
print('当i = 2, j = 2时离开嵌套循环')
1 1
2 2
当i=2,j=2时离开循环嵌套
用户自定义异常类
class URLError(Exception):
pass
try:
raise URLError(“URL ERROR”)
except URLError as err:
print(err.args[0])
URL ERROR
assert语句
原理:检查表达式的代码当表达式求值为真,一切正常;但若表达式求值为假,则暂停程序,打印消息,并在可行的情况下启动调试器。
assert <测试码>[, 参数]
#原理
a = 10
assert (a != 0),"Error happened, a = 0"
print(a)
如果a = 0会抛出 Error happened a = 0
__debug__内置变量
if __debug__:
if not (<测试码>):
raise AssertionError [, 参数]
import types
def checkType(arg):
if__debug__:
if not (type(arg) == str):
raise AssertionError("参数类型不是字符串")
checkType(1)
Asser t ionError
Traceback (most recent ca11 last)
<ipython- input- 30-c6dc6612ea27> in <module>
5
raise AssertionError("参 数类型不是字符串")
6
----> 7 checkType(1)
<ipython- input-30-c6dc6612ea27> in checkType (arg)
3
debug__
4
if not (type(arg) == str):
----> 5
raise AssertionError("参 数类型不是字符串")
6
7 checkType(1)
AssertionError:参数类型不是字符串
断言与上下管理语句
- 上下文管理(context manager)语句with可以自动管理资源,不论因为什么原因(哪怕是代码引发了异常)跳出with块,总能保证文件被正确关闭,并且可以在代码块执行完毕后自动还原进入该代码块时的现场,常用于文件操作、数据库连接、网络通信连接和多线程、多进程同步等场合。
- with语句用于文件操作时的用法如下:
with open(filename, mode, encoding) as fp:
# 通过文件对象fp操作文件的代码
tkinter简介
tkinter是Python标准库,不需要额外安装就可以直接使用,比较方便,得到了很多人的青睐,成为现在做GUI开发的主流模块。除了在tkinter库的主模块中提供了大量组件,还通过其中的模块tkinter.ttk提供了Combobox、Progressbar和Treeview等组件,tkinter.scrolledtext提供了带滚动条的文本框,messagebox、commondialog、dialog、colorchooser、simpledialog、filedialog等模块提供了各种形式的对话框。
常用组件
组件名称 | 说明 |
Button | 按钮 |
Canvas | 画布,用于绘制直线、椭圆、多边形等各种图形 |
Checkbutton | 复选框形式的按钮 |
Entry | 单行文本框 |
Frame | 框架 |
Label | 标签,常用来显示文本 |
Listbox | 列表框 |
Menu | 菜单 |
Message | 多行文本框 |
Radiobutton | 单选框 |
Scrollbar | 滚动条 |
Toplevel | 创建新窗口 |
Tkinter开发基本步骤:
编写通用代码,例如数据库操作
搭建界面,放置组件,设置组件属性,可以借助PAGE
编写组件的事件处理代码
启动应用程序,启动消息主循环
用户登录界面
import tkinter
import tkinter.messagebox
import os
import os.path
path = os.getenv('temp')
filename = os.path.join(path, 'info.txt')
#创建应用程序窗口
root = tkinter.Tk()
#定义窗口大小
root['height'] = 140
root['width'] = 200
#在窗口上创建标签组件
labelName = tkinter.Label(root,
text='User Name:',
justify=tkinter.RIGHT,
anchor = 'e',
width=80)
#把组件放置到窗口上指定区域
labelName.place(x=10, y=5, width=80, height=20)
varName = tkinter.StringVar(root, value='')
entryName = tkinter.Entry(root,
width=80,
textvariable=varName)
entryName.place(x=100, y=5, width=80, height=20)
labelPwd = tkinter.Label(root,
text='User Pwd:',
justify=tkinter.RIGHT,
anchor = 'e',
width=80)
labelPwd.place(x=10, y=30, width=80, height=20)
#创建密码文本框
varPwd = tkinter.StringVar(root, value='')
entryPwd = tkinter.Entry(root,
show='*', #不管输入什么,都显示星号
width=80,
textvariable=varPwd)
entryPwd.place(x=100, y=30, width=80, height=20)
#尝试自动填写用户名和密码
try:
with open(filename) as fp:
n, p = fp.read().strip().split(',')
varName.set(n)
varPwd.set(p)
except:
pass
#记住我,复选框
rememberMe = tkinter.IntVar(root, value=1)
checkRemember = tkinter.Checkbutton(root,
text='Remember me?',
variable=rememberMe,
onvalue=1,
offvalue=0)
checkRemember.place(x=30, y=70, width=120, height=20)
#登录按钮事件处理函数
def login():
#获取用户名和密码
name = entryName.get()
pwd = entryPwd.get()
if name=='admin' and pwd=='123456':
tkinter.messagebox.showinfo(title='恭喜',
message='登录成功!')
if rememberMe.get() == 1:
#把登录成功的信息写入临时文件
with open(filename, 'w') as fp:
fp.write(','.join((name,pwd)))
else:
try:
#删除用于记录用户名和密码的临时文件
os.remove(filename)
except:
pass
else:
tkinter.messagebox.showerror('警告',
message='用户名或密码错误')
#创建按钮组件,同时设置按钮事件处理函数
buttonOk = tkinter.Button(root,
text='Login', #设置按钮上显示的文本
command=login) #设置按钮的单击事件处理函数
buttonOk.place(x=30, y=100, width=50, height=20)
#取消按钮的事件处理函数
def cancel():
#清空用户输入的用户名和密码
varName.set('')
varPwd.set('')
buttonCancel = tkinter.Button(root,
text='Cancel',
command=cancel)
buttonCancel.place(x=90, y=100, width=50, height=20)
#启动消息循环
root.mainloop()
例12-2 tkinter单选钮、复选框、组合框、列表框综合运用案例。
import tkinter
import tkinter.messagebox
import tkinter.ttk
#创建tkinter应用程序
root = tkinter.Tk()
#设置窗口标题
root.title('Selection widgets')
#定义窗口大小
root['height'] = 400
root['width'] = 320
#与姓名关联的变量
varName = tkinter.StringVar()
varName.set('')
#创建标签,然后放到窗口上
labelName = tkinter.Label(root,
text='Name:',
justify=tkinter.RIGHT,
width=50)
labelName.place(x=10, y=5, width=50, height=20)
#创建文本框,同时设置关联的变量
entryName = tkinter.Entry(root,
width=120,
textvariable=varName)
entryName.place(x=70, y=5, width=120, height=20)
labelGrade = tkinter.Label(root,
text='Grade:',
justify=tkinter.RIGHT, width=50)
labelGrade.place(x=10, y=40, width=50, height=20)
#模拟学生所在年级,字典键为年级,字典值为班级
studentClasses = {'1':['1', '2', '3', '4'],
'2':['1', '2'],
'3':['1', '2', '3']}
#学生年级组合框
comboGrade = tkinter.ttk.Combobox(root,width=50,
values=tuple(studentClasses.keys()))
comboGrade.place(x=70, y=40, width=50, height=20)
#事件处理函数
def comboChange(event):
grade = comboGrade.get()
if grade:
#动态改变组合框可选项
comboClass["values"] = studentClasses.get(grade)
else:
comboClass.set([])
#绑定组合框事件处理函数
comboGrade.bind('<<ComboboxSelected>>', comboChange)
labelClass = tkinter.Label(root,
text='Class:',
justify=tkinter.RIGHT, width=50)
labelClass.place(x=130, y=40, width=50, height=20)
#学生班级组合框
comboClass = tkinter.ttk.Combobox(root, width=50)
comboClass.place(x=190, y=40, width=50, height=20)
labelSex = tkinter.Label(root,
text='Sex:',
justify=tkinter.RIGHT, width=50)
labelSex.place(x=10, y=70, width=50, height=20)
#与性别关联的变量,1:男;0:女,默认为男
sex = tkinter.IntVar()
sex.set(1)
#单选钮,男
radioMan = tkinter.Radiobutton(root,
variable=sex,
value=1,
text='Man')
radioMan.place(x=70, y=70, width=50, height=20)
#单选钮,女
radioWoman = tkinter.Radiobutton(root,
variable=sex,
value=0,
text='Woman')
radioWoman.place(x=130, y=70, width=70, height=20)
#与是否班长关联的变量,默认当前学生不是班长
monitor = tkinter.IntVar()
monitor.set(0)
#复选框,选中时变量值为1,未选中时变量值为0
checkMonitor = tkinter.Checkbutton(root,
text='Is Monitor?',
variable=monitor,
onvalue=1,
offvalue=0)
checkMonitor.place(x=20, y=100, width=100, height=20)
#添加按钮单击事件处理函数
def addInformation():
result = 'Name:' + entryName.get()
result = result + ';Grade:' + comboGrade.get()
result = result + ';Class:' + comboClass.get()
result = result + ';Sex:'\
+ ('Man' if sex.get() else 'Woman')
result = result + ';Monitor:'\
+ ('Yes' if monitor.get() else 'No')
#把信息插入到列表框组件中
listboxStudents.insert(0, result)
buttonAdd = tkinter.Button(root,
text='Add',
width=40,
command=addInformation)
buttonAdd.place(x=130, y=100, width=40, height=20)
#删除按钮的事件处理函数
def deleteSelection():
selection = listboxStudents.curselection()
if not selection:
tkinter.messagebox.showinfo(title='Information',
message='No Selection')
else:
listboxStudents.delete(selection)
buttonDelete = tkinter.Button(root,
text='DeleteSelection',
width=100,
command=deleteSelection)
buttonDelete.place(x=180, y=100, width=100, height=20)
#创建列表框组件
listboxStudents = tkinter.Listbox(root, width=300)
listboxStudents.place(x=10, y=130, width=300, height=200)
#启动消息循环
root.mainloop()
import os
import tkinter
import tkinter.simpledialog
import tkinter.colorchooser
import tkinter.filedialog
#需要执行pip install pillow安装扩展库
from PIL import ImageGrab
root = tkinter.Tk()
root.title('My Paint----by Dong Fuguo')
root['width'] = 800
root['height'] = 600
#控制是否允许画图的变量,1:允许,0:不允许
canDraw = tkinter.IntVar(value=0)
what = tkinter.IntVar(value=1)
#记录鼠标位置的变量
X = tkinter.IntVar(value=0)
Y = tkinter.IntVar(value=0)
#前景色、背景色
foreColor = '#000000'
backColor = '#FFFFFF'
#创建画布
image = tkinter.PhotoImage()
canvas = tkinter.Canvas(root,
bg='white',
width=800, height=600)
canvas.create_image(800, 600, image=image)
#鼠标左键单击,允许画图,并记录当前鼠标位置
def onLeftButtonDown(event):
canDraw.set(1)
X.set(event.x)
Y.set(event.y)
if what.get()==4:
canvas.create_text(event.x, event.y, text=text)
canvas.bind('<Button-1>', onLeftButtonDown)
#记录最后绘制图形的id
lastDraw = 0
#按住鼠标左键移动,画图
def onLeftButtonMove(event):
global lastDraw
if canDraw.get()==0:
return
if what.get()==1:
#使用当前选择的前景色绘制曲线
canvas.create_line(X.get(), Y.get(), event.x,
event.y, fill=foreColor)
X.set(event.x)
Y.set(event.y)
elif what.get()==2:
#绘制直线,先删除刚刚画过的直线,再画一条新的直线
try:
canvas.delete(lastDraw)
except Exception as e:
pass
lastDraw = canvas.create_line(X.get(), Y.get(),
event.x, event.y,
fill=foreColor)
elif what.get()==3:
#绘制矩形,先删除刚刚画过的矩形,再画一个新的矩形
try:
canvas.delete(lastDraw)
except Exception as e:
pass
lastDraw = canvas.create_rectangle(X.get(), Y.get(),
event.x, event.y,
fill=backColor,
outline=foreColor)
elif what.get()==5:
#橡皮,使用背景色填充10*10的矩形区域
canvas.create_rectangle(event.x-5, event.y-5,
event.x+5, event.y+5,
outline=backColor, fill=backColor)
canvas.bind('<B1-Motion>', onLeftButtonMove)
#鼠标左键抬起,不允许再画图了
def onLeftButtonUp(event):
if what.get()==2:
#绘制直线
canvas.create_line(X.get(),
Y.get(),
event.x,
event.y,
fill=foreColor)
elif what.get()==3:
#绘制矩形
canvas.create_rectangle(X.get(),
Y.get(),
event.x,
event.y,
fill=backColor,
outline=foreColor)
canDraw.set(0)
global lastDraw
#防止切换图形时误删上次绘制的图形
lastDraw = 0
canvas.bind('<ButtonRelease-1>', onLeftButtonUp)
#创建菜单
menu = tkinter.Menu(root, tearoff=0)
#打开图像文件
def Open():
filename = tkinter.filedialog.askopenfilename(title='Open Image',
filetypes=[('image', '*.jpg *.png *.gif')])
if filename:
global image
image = tkinter.PhotoImage(file=filename)
canvas.create_image(80, 80, image=image)
menu.add_command(label='Open', command=Open)
def Save():
#获取客户区域位置和尺寸,并截图保存
left = int(root.winfo_rootx())
top = int(root.winfo_rooty())
width = root.winfo_width()
height = root.winfo_height()
im = ImageGrab.grab((left,top,left+width,top+height))
#保存绘制的图片
filename = tkinter.filedialog.asksaveasfilename(title='保存图片',
filetypes=[('图片文件','*.png')])
if not filename:
return
if not filename.endswith('.png'):
filename = filename+'.png'
im.save(filename)
menu.add_command(label='Save', command=Save)
#添加菜单,清除,遍历画布上的所有图像,逐个删除
def Clear():
for item in canvas.find_all():
canvas.delete(item)
menu.add_command(label='Clear', command=Clear)
#添加分割线
menu.add_separator()
#创建子菜单,用来选择绘图类型
menuType = tkinter.Menu(menu, tearoff=0)
def drawCurve():
what.set(1)
menuType.add_command(label='Curve', command=drawCurve)
def drawLine():
what.set(2)
menuType.add_command(label='Line', command=drawLine)
def drawRectangle():
what.set(3)
menuType.add_command(label='Rectangle', command=drawRectangle)
def drawText():
global text
text = tkinter.simpledialog.askstring(title='Input what you want to draw', prompt='')
what.set(4)
menuType.add_command(label='Text', command=drawText)
menuType.add_separator()
#选择前景色
def chooseForeColor():
global foreColor
foreColor = tkinter.colorchooser.askcolor()[1]
menuType.add_command(label='Choose Foreground Color',
command=chooseForeColor)
#选择背景色
def chooseBackColor():
global backColor
backColor = tkinter.colorchooser.askcolor()[1]
menuType.add_command(label='Choose Background Color',
command=chooseBackColor)
#橡皮
def onErase():
import tkinter
import tkinter.messagebox
import random
import threading
import itertools
import time
root = tkinter.Tk()
# 窗口标题
root.title('随机提问')
# 窗口初始大小和位置
root.geometry('260x180+400+300')
# 不允许改变窗口大小
root.resizable(False, False)
# 关闭程序时执行的函数代码,停止滚动显示学生名单
def closeWindow():
# 标记flat变量为False,停止滚动
root.flag = False
# 暂停0.1秒,等待用于滚动名单的子线程结束
time.sleep(0.1)
# 销毁窗口,关闭程序
root.destroy()
# 绑定消息处理函数,当窗口关闭时会触发'WM_DELETE_WINDOW'消息
root.protocol('WM_DELETE_WINDOW', closeWindow)
# 模拟学生名单,这些学生姓名在窗口上滚动
students = ['张三', '李四', '王五', '赵六', '周七', '钱八']
# 变量,用来控制是否滚动显示学生名单,默认启动时不滚动
root.flag = False
# 用户滚动名单的线程函数
def switch():
root.flag = True
# 随机打乱学生名单
t = students[:]
random.shuffle(t)
# 创建cycle对象,用于实现无限重复的滚动
t = itertools.cycle(t)
# 一直滚动,直到flag的值为False
while root.flag:
# 滚动显示
# 把第二个人名移动到第一个
# 把第三个人名移动到第二个
# 获取一个新的人名显示为第三个
lbFirst['text'] = lbSecond['text']
lbSecond['text'] = lbThird['text']
lbThird['text'] = next(t)
# 数字可以修改,控制滚动速度
time.sleep(0.1)
def btnStartClick():
# 每次单击“开始”按钮创建并启动新线程
t = threading.Thread(target=switch)
t.start()
# 把“开始”按钮禁用,避免重复响应单击操作
btnStart['state'] = 'disabled'
# 启用“停”按钮
btnStop['state'] = 'normal'
btnStart = tkinter.Button(root,
text='开始',
command=btnStartClick)
btnStart.place(x=30, y=10, width=80, height=20)
def btnStopClick():
# 单击“停”按钮结束滚动显示
root.flag = False
# 等待0.3秒,彻底停止滚动之后再获取中奖的人名
time.sleep(0.3)
tkinter.messagebox.showinfo('恭喜',
'本次中奖:'+lbSecond['text'])
# 启用“开始”按钮,禁用“停”按钮
btnStart['state'] = 'normal'
btnStop['state'] = 'disabled'
btnStop = tkinter.Button(root,
text='停',
command=btnStopClick)
# 程序启动时,“停”按钮初始设置为禁用
btnStop['state'] = 'disabled'
btnStop.place(x=150, y=10, width=80, height=20)
# 用来滚动显示学生名单的3个Label组件
# 可以根据需要进行添加,但要修改上面的线程函数代码
lbFirst = tkinter.Label(root, text='')
lbFirst.place(x=80, y=60, width=100, height=20)
# 红色Label组件,表示中奖名单
lbSecond = tkinter.Label(root, text='')
lbSecond['fg'] = 'red'
lbSecond.place(x=80, y=90, width=100, height=20)
lbThird = tkinter.Label(root, text='')
lbThird.place(x=80, y=120, width=100, height=20)
# 启动消息主循环,启动应用程序
root.mainloop()
例12-7 使用tkinter实现计算器程序
import re
import tkinter
import tkinter.messagebox
root = tkinter.Tk()
# 设置窗口大小和位置
root.geometry('300x270+400+100')
# 不允许改变窗口大小
root.resizable(False, False)
# 设置窗口标题
root.title('简易计算器-董付国')
# 字符串变量
contentVar = tkinter.StringVar(root, '')
# 用来显示表达式的文本框,设置关联变量
contentEntry = tkinter.Entry(root, textvariable=contentVar)
# 设置为只读,只能通过按钮来输入要计算的表达式
contentEntry['state'] = 'readonly'
contentEntry.place(x=10, y=10, width=280, height=20)
# 按钮通用代码,参数btn表示按钮的是哪个按钮
def buttonClick(btn):
content = contentVar.get()
# 如果已有内容是以小数点开头的,前面加0
if content.startswith('.'):
content = '0' + content
# 根据不同按钮做出相应的处理
if btn in '0123456789':
# 普通数字按钮,直接连接到表达式最后
content += btn
elif btn == '.':
# 如果最后一个运算数中已经有小数点,就提示错误
lastPart = re.split(r'\+|-|\*|/]', content)[-1]
if '.' in lastPart:
tkinter.messagebox.showerror('错误', '小数点太多了')
return
else:
# 最后一个运算数中没有小数点,把小数点连接到最后
content += btn
elif btn == 'C':
# 清除整个表达式
content = ''
elif btn == '=':
# 按下等于号按钮,计算结果
try:
# 尝试对输入的表达式求值
content = str(eval(content))
except:
tkinter.messagebox.showerror('错误', '表达式错误')
return
elif btn in operators:
# 按下运算符按钮,表达式中不允许有连续的运算符
if content.endswith(operators):
tkinter.messagebox.showerror('错误',
'不允许存在连续运算符')
return
content += btn
elif btn == 'Sqrt':
# 求平方根
# 切分出整数部分和小数部分
n = content.split('.')
# 要求小数点前后都是数字,如果表达式中含有运算符,不符合要求
if all(map(lambda x: x.isdigit(), n)):
content = eval(content) ** 0.5
else:
tkinter.messagebox.showerror('错误', '表达式错误')
return
# 显示计算结果
contentVar.set(content)
# 放置清除按钮和等号按钮
btnClear = tkinter.Button(root,
text='Clear',
command=lambda:buttonClick('C'))
btnClear.place(x=40, y=40, width=80, height=20)
btnCompute = tkinter.Button(root,
text='=',
command=lambda:buttonClick('='))
btnCompute.place(x=170, y=40, width=80, height=20)
#放置10个数字、小数点和计算平方根的按钮
digits = list('0123456789.') + ['Sqrt']
index = 0
for row in range(4):
for col in range(3):
d = digits[index]
index += 1
btnDigit = tkinter.Button(root,
# 按钮上显示的内容
text=d,
# 按下按钮时执行的函数
command=lambda x=d:buttonClick(x))
# 把按钮放置到窗口上
btnDigit.place(x=20+col*70,
y=80+row*50,
width=50,
height=20)
# 放置运算符按钮
operators = ('+', '-', '*', '/', '**', '//')
for index, operator in enumerate(operators):
btnOperator = tkinter.Button(root,
text=operator,
command=lambda x=operator:buttonClick(x))
btnOperator.place(x=230, y=80+index*30, width=50, height=20)
# 启动消息主循环,启动应用程序
root.mainloop()
例12-8 使用tkinter实现定时自动关闭的窗口
import time
import tkinter
import threading
# 创建应用程序窗口,设置标题和大小
root = tkinter.Tk()
root.title('倒计时自动关闭的窗口')
root['width'] = 400
root['height'] = 300
# 不允许改变窗口大小
root.resizable(False, False)
# 创建Text组件,放置一些文字
richText = tkinter.Text(root, width=380)
richText.place(x=10, y=10, width=380, height=230)
# 连续插入5行内容
# '0.0'表示插入位置,第0行第0列
# 如果想让插入的内容占一行,需要在字符串最后有换行符
for i in range(5):
# f字符串语法,会把{i}替换为i的当前实际值
richText.insert(f'{i}.0',
'假设阅读这些文字需要10秒钟时间\n')
# 显示倒计时的Label
lbTime = tkinter.Label(root, fg='red', anchor='w')
lbTime.place(x=10, y=250, width=150)
def autoClose():
# 倒计时10秒钟
for i in range(10):
# f字符串语法,对{}中的表达式进行计算并替换
lbTime['text'] = f'距离窗口关闭还有{10-i}秒'
# 每秒钟修改一次提示信息
time.sleep(1)
root.destroy()
# 创建并启动线程
t = threading.Thread(target=autoClose)
t.start()
# 启动消息主循环,启动应用程序
root.mainloop()
import time
import tkinter
import threading
# 创建应用程序窗口,设置标题和大小
root = tkinter.Tk()
root.title('倒计时自动关闭的窗口')
root['width'] = 400
root['height'] = 300
# 不允许改变窗口大小
root.resizable(False, False)
# 创建Text组件,放置一些文字
richText = tkinter.Text(root, width=380)
richText.place(x=10, y=10, width=380, height=230)
# 连续插入5行内容
# '0.0'表示插入位置,第0行第0列
# 如果想让插入的内容占一行,需要在字符串最后有换行符
for i in range(5):
# f字符串语法,会把{i}替换为i的当前实际值
richText.insert(f'{i}.0',
'假设阅读这些文字需要10秒钟时间\n')
# 显示倒计时的Label
lbTime = tkinter.Label(root, fg='red', anchor='w')
lbTime.place(x=10, y=250, width=150)
def autoClose():
# 倒计时10秒钟
for i in range(10):
# f字符串语法,对{}中的表达式进行计算并替换
lbTime['text'] = f'距离窗口关闭还有{10-i}秒'
# 每秒钟修改一次提示信息
time.sleep(1)
root.destroy()
# 创建并启动线程
t = threading.Thread(target=autoClose)
t.start()
# 启动消息主循环,启动应用程序
root.mainloop()
日志
logging库日志级别
级别 级别数值 使用时机
DEBUG 10 详细信息,常用于调试。
INFO 20 程序正常运行过程中产“生的一些信息。
WARNING 30 警告用户,虽然程序还在正常工作,但有可能发生错误。
ERROR 40 由于更严重的问题,程序已不能执行一些功能了。
CRITICAL 50 严重错误,程序已不能继续运行。
import logging
#print("This is a 10g. text")
logging. debug("This is debug log")
logging.info("This is info Log")
logging.warning("This is warning log")
logging.error("This is error Log")
logging.critical("This is critical log")
WARNING: root:This is wa rning log
ERROR: root:This is error Log
CRITICAL : root:This is critical Log
Process finished with exit code 0
import logging
#使用baseConfig( )来指定日志输出级别
logging.basicConfig( leve1= logging. DEBUG)
print("This is a log text")
logging.debug("This is debug log" )
logging.info("This is info log")
logging.warning("This is warning log")
logging.error("This is error log")
logging.critical(This is critical log")
输出代码:
DEBUG: root:This is debug log
INFO: root:This is info log
WARNING: root:This is warning log
ERROR: root:This is error log
CRITICAL: root:This is critical log
This is a log text
logging . basicConfig( filename='demo,Log', fi lemode= 'w's leve (= Logging . DEBUG
新生成一个叫demo.log的文件 每次记录日志都会重新写入 不依次追加 默认是追加
loggingbasicConfig(format="%(message)s", level=logging.DEBUG)
name = “张三"
age = 18
logging.debug("姓名%s, 年龄%d", name, age )
可以只输出信息
logging.basicConfig(format="%(asctime)s|%(LeveLnames|%(filename)s:% (lineno)s|% (message)s
", leve L= logging. DEBUG)
2021-09-16 11:07:52, 161 DEBUG|2.2py:10|姓名张三,年龄18
日志logging
高级应用,四个组件:
Loggers:记录器
Handlers:处理器
Filters:过滤器
Formatters:格式化器
import logging
import logging.config
#配置文件的方式来处理日志
logging.config.fileConfig('logging.config')
logger = logging.getLogger('applog')
#打印日志
logger.debug("This is a debug log")
logger.info("This is a info log")
logger.warning("This is a warning log")
logger.error("This is a error log")
logger.critical("This is a critical log")