异常和日志

概念

 可向用户反馈报错信息。异常也是对象,可对他进行操作。所有的异常都是基类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")

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

撸码的xiao摩羯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值