#第十一章 thinker
import tkinter as tk
print(help(tk.Button.__init__))#以按扭为例查看有什么属性
class myApplication(tk.Frame):
def __init__(self,master=None):
#一、frame
tk.Frame.__init__(self,master)
self.pack()
#二、button
onButton=tk.Button(self)#创建一个按钮下面是属性设置默认值
onButton['activebackground']='gray25' #激活状态背景色
onButton['activeforeground']='gray25' #激活状态前景色
onButton['anchor']='center' #位于窗口位置,另有NW,SE等八选项
onButton['background']='gray25' #正常状态背景色gray25
#onButton['bitmap']= #位图暂时没有
onButton['borderwidth']=30 #边框宽度,单位是像素
onButton['cursor']='gumby' #光标形式gumby
#onButton['command']= #鼠标离开时触发调用
onButton['disabledforeground']='gray25'#禁用状态前景色gray25
onButton['font']='Helvetica' #字体
onButton['foreground']='gray25' #正常状态前景色
onButton['highlightbackground']='gray' #高亮状态背景色
onButton['highlightcolor']='gray' #高亮状态前景色
onButton['highlightthickness']=2 #高亮状态边框宽度
onButton['height']=20 #以font字体字符高度为单位
#onButton['image']= #按钮图像暂时未有
onButton['justify']='right' #组件内部内容对齐方式
onButton['padx']=30 #组件水平方向留白
onButton['pady']=30 #组件竖直方向留白
onButton['relief']='raised' #组件3D效果
#onButton['selectbackground']='gray' #选中时背景色
#onButton['selectborderwidth']=2 #选中时3D边框宽度
#onButton['selectforeground']='gray' #选中时前景色
onButton['state']='normal' #组件当前状态NORMAL或DISABLE1
onButton['takefocus']=1 #键盘接收焦点SHIFT+TAB,0则不接收
onButton['text']='ok' #文本
#onButton['textvariable']=bnText #变量名,获取字符串
onButton['underline']=2 #文本第几字符加下划线
onButton['width']=20 #以font字体字符高度为单位
onButton['wraplength']=20 #对支持换行的组件每行最大字符数
#onButton['xscrollcommand']=scroll.set
#onButton['yscrollcommand']=scroll.set
onButton.pack()
#三、Label
w=tk.Label(self)
w.x=tk.PhotoImage(file='./image/background.png')
w['image']=w.x
w.pack()
app=myApplication()
app.master.title('CJ')
app.mainloop()
#pack
from tkinter import *
class App:
def __init__(self, master):
self.master = master
self.initWidgets()
def initWidgets(self):
fm1=Frame(self.master)# 创建第一个容器
fm1.pack(side=LEFT,fill=BOTH,expand=YES)#该容器放在左边排列
Button(fm1,text='第一个').pack(side=TOP)#在frm1中设按钮且不填充
Button(fm1,text='第二个').pack(side=TOP,fill=X,expand=YES)#在frm1中设按钮且在X方向填充(无效果)
fm2=Frame(self.master)# 创建第二个容器
fm2.pack(side=LEFT,padx=10,fill=BOTH,expand=YES)# 该容器放在左边排列,就会挨着fm1
Button(fm2, text='第一个').pack(side=RIGHT)## 设置按钮从右边开始排列,不填充
Button(fm2, text='第二个').pack(side=RIGHT, fill=X, expand=YES)#X方向填充
Button(fm2, text='第三个').pack(side=RIGHT, fill=Y, expand=YES)#Y方向填充
fm3 = Frame(self.master)# 创建第三个容器
fm3.pack(side=RIGHT, padx=10, fill=BOTH, expand=YES)# 该容器放在右边排列
Button(fm3, text='第一个').pack(side=BOTTOM, fill=Y, expand=YES)
Button(fm3, text='第二个').pack(side=BOTTOM, fill=Y, expand=YES)
Button(fm3, text='第三个').pack(side=BOTTOM, fill=Y, expand=YES)
root = Tk()
root.title("Pack布局")
display = App(root)
root.mainloop()
#grid
from tkinter import *
class App:
def __init__(self, master):
self.master = master
self.initWidgets()
def initWidgets(self):
Entry(relief=SUNKEN,font=('Courier New',24),width=25).pack(side=TOP, pady=10)#创建输入组件放顶部
p=Frame(self.master)#创建frame
p.pack(side=TOP)#放顶部
names=("0","1","2","3","4","5","6","7","8","9","+","-","*","/",".","=")
for i in range(len(names)):#遍历字符串元组
b=Button(p,text=names[i],font=('Verdana',20),width=6)#创建p的子对象Button
b.grid(row=i//4,column=i%4)
root = Tk()
root.title("Grid布局")
App(root)
root.mainloop()
#place
from tkinter import *
import random
class App:
def __init__(self, master):
self.master = master
self.initWidgets()
def initWidgets(self):
books=('疯狂Python讲义','疯狂Swift讲义','疯狂Kotlin讲义','疯狂Java讲义','疯狂Ruby讲义')
for i in range(len(books)):
ct = [random.randrange(256) for x in range(3)] # 生成3个随机数
bg_color="#%02x%02x%02x" % tuple(ct)#得到背景色
grayness=int(round(0.299*ct[0]+0.587*ct[1]+0.114*ct[2]))#得到灰度,下面用来设前景色
lb=Label(root,text=books[i],fg='White' if grayness<120 else 'Black',bg=bg_color)
lb.place(x=20,y=36+i*36,width=180,height=30) # 使用place()设置该Label的大小和位置
root = Tk()
root.title("Place布局")
root.geometry("250x250+30+30")#设置窗口的大小和位置width x height + x_offset + y_offset
App(root)
root.mainloop()
#command
from tkinter import *
import random
class App:
def __init__(self):
self.master = Tk()
self.initWidgets()
self.master.title("简单事件处理")
self.master.mainloop()
def initWidgets(self):
self.label = Label(self.master, width=30)
self.label['font'] = ('Courier', 20) #字体
self.label['bg'] = 'white' #背景色
self.label.pack()
self.bn = Button(self.master, text='单击我', command=self.change)
self.bn.pack()
def change(self):
self.label['text'] = '欢迎学习Python'
ct = [random.randrange(256) for x in range(3)]# 生成3个随机数
grayness = int(round(0.299*ct[0] + 0.587*ct[1] + 0.114*ct[2]))
bg_color = "#%02x%02x%02x" % tuple(ct)#把三个随机数转成颜色格式
self.label['bg'] = bg_color
self.label['fg'] = 'black' if grayness > 125 else 'white'
my_app=App()
#bind
from tkinter import *
class App:
def __init__(self, master):
self.master = master
self.initWidgets()
def initWidgets(self):
self.show = Label(self.master, width=30, bg='white', font=('times', 20))
self.show.pack()
self.bn = Button(self.master, text='CJ的按钮')
self.bn.pack(fill=BOTH, expand=YES)
self.bn.bind('',self.one)
self.bn.bind('',self.b2_motion)
self.bn.bind('',self.double)
self.bn.bind('',self.motion)
def one(self, event):
self.show['text']="左键单击:%s" % event.widget['text']
def b2_motion(self,event):
self.show['text']="你正在按着中键移动"
def double(self, event):
self.show.config(text="右键双击:%s" % event.widget['text'])
def motion(self,event):
self.show['text']="鼠标坐标更新为(%d %d)"%(event.x,event.y)
root = Tk()
root.title('简单绑定')
App(root)
root.mainloop()
#demo_calculator
from tkinter import *
class App:
def __init__(self, master):
self.master = master
self.initWidgets()
self.flag = 0
def initWidgets(self):
self.show=Label(relief=SUNKEN,font=('Courier New',24),width=25,bg='white',anchor=E)
self.show.pack(side=TOP, pady=10)
self.p = Frame(self.master)
self.p.pack(side=TOP)
names=("0","1","2","3","4","5","6","7","8","9","+","-","*","/",".","=")
for i in range(len(names)):
b=Button(self.p,text=names[i],font=('Verdana',20),width=6)
b.grid(row=i // 4, column=i % 4)
b.bind('', self.click)
def click(self, event):
if(event.widget['text'] != '='):
self.show['text'] = self.show['text'] + event.widget['text']
self.flag = 0
elif(event.widget['text']=='='):
if(self.flag==1):
self.show['text']=''
else:
self.flag=1#先设flag是为了下一行出错(如输入01+2)方法直接返回时也能使用双击=消值功能
self.show['text']=str(eval(self.show['text']))#使用eval函数计算表达式的值并显示
root = Tk()
root.title("计算器")
App(root)
root.mainloop()
#ttk(就是改了下装饰)
from tkinter import *
from tkinter import ttk
class App:
def __init__(self, master):
self.master = master
self.initWidgets()
def initWidgets(self):
cb=ttk.Combobox(self.master, font=24)#下拉列表
cb['values'] = ('Python', 'Swift', 'Kotlin')
cb.pack(side=LEFT, fill=X, expand=YES)
lab = ttk.Label(self.master, text='我的标签', font=24)
lab.pack(side=TOP, fill=BOTH, expand=YES)
bn = ttk.Button(self.master, text='我的按钮')
bn.pack()
root = Tk()
root.title("简单事件处理")
App(root)
root.mainloop()
#StringVar(IntVar/DoubleVar/BooleanVar)
from tkinter import *
from tkinter import ttk
from tkinter import messagebox
import random
class App:
def __init__(self, master):
self.master = master
self.initWidgets()
def initWidgets(self):
self.st = StringVar()#这个变量的获取与调用就是用get,set,注意下面的输入框的内从与这个变量绑定
ttk.Entry(self.master,textvariable=self.st,width=24,font=('StSong',20,'bold'),foreground='red').pack(fill=BOTH, expand=YES)
f = Frame(self.master)
f.pack()
ttk.Button(f,text='改变',command=self.change).pack(side=LEFT)
ttk.Button(f,text='获取',command=self.get).pack(side=LEFT)
def change(self):
books = ('疯狂Python讲义', '疯狂Kotlin讲义', '疯狂Swift讲义')
self.st.set(books[random.randint(0, 2)])
def get(self):
messagebox.showinfo(title='输入内容', message=self.st.get() )
root = Tk()
root.title("variable测试")
App(root)
root.mainloop()
#PhotoImage
from tkinter import *
from tkinter import ttk
class App:
def __init__(self, master):
self.master = master
self.initWidgets()
def initWidgets(self):
# 创建一个位图
bm =PhotoImage(file='images/serial.png')#此处会报错,先改成None跑一次,再转成图像
self.label = ttk.Label(self.master, text='疯狂体\n系图书',image=bm , font=('StSong', 20, 'bold'), foreground='red' )
self.label.bm = bm
self.label['compound'] = None
self.label.pack()
f=ttk.Frame(self.master)# 创建Frame容器,用于装多个Radiobutton
f.pack(fill=BOTH, expand=YES)
self.var = StringVar()# 定义一个StringVar变量,用作绑定Radiobutton的变量
self.var.set('None')
compounds = ('None', "LEFT", "RIGHT", "TOP", "BOTTOM", "CENTER")
for val in compounds:# 使用循环创建多个Radionbutton组件,variable=self.var就是说每个单选按钮都绑定这个变量,变量值就是按钮value
Radiobutton(f,text=val,padx=20,variable=self.var,command=self.change_compound,value=val).pack(side=LEFT,anchor=CENTER)
def change_compound(self):
self.label['compound'] = self.var.get().lower()
root = Tk()
root.title("compound测试")
App(root)
root.mainloop()
#entry/text/messagebox
from tkinter import *
from tkinter import ttk
from tkinter import messagebox
class App:
def __init__(self, master):
self.master = master
self.initWidgets()
def initWidgets(self):
self.entry=ttk.Entry(self.master,width=44,font=('StSong',14),foreground='green')
self.entry.pack(fill=BOTH,expand=YES)
self.text=Text(self.master,width=44,height=4,font=('StSong',14),foreground='gray')
self.text.pack(fill=BOTH,expand=YES)
f=Frame(self.master)
f.pack()
ttk.Button(f, text='开始处插入', command=self.insert_start).pack(side=LEFT)
ttk.Button(f, text='光标处插入', command=self.insert_edit).pack(side=LEFT)
ttk.Button(f, text='结尾处插入', command=self.insert_end).pack(side=LEFT)
ttk.Button(f, text='删除文本', command=self.del_text).pack(side=LEFT)
ttk.Button(f, text='获取文本', command=self.get_text).pack(side=LEFT)
def insert_start(self):
self.entry.insert(0, 'Kotlin')
self.text.insert(0.0, 'Kotlin')#第1行第0个字符处插入
def insert_edit(self):
self.entry.insert(INSERT, 'Python')
self.text.insert(INSERT, 'Python')
def insert_end(self):
self.entry.insert(END, 'Swift')
self.text.insert(END, 'Swift')
def del_text(self):
self.text.delete(1.0,END)#删全部
self.entry.delete(0)#删一个字符
def get_text(self):
messagebox.showinfo(title='输入内容', message=self.entry.get())
messagebox.showinfo(title='输入内容', message=self.text.get(1.0, END))
root = Tk()
root.title("Entry测试")
App(root)
root.mainloop()
#webbrowser
import webbrowser
webbrowser.open('https://item.jd.com/12261787.html')
#intVar/Radiobutton单选按钮
from tkinter import *
from tkinter import ttk
class App:
def __init__(self, master):
self.master = master
self.initWidgets()
def initWidgets(self):
ttk.Label(self.master, text='选择您喜欢的单词:').pack(fill=BOTH, expand=YES)
self.intVar = IntVar()
self.intVar.set(2)
books = ('CJ', 'loves','GJL', 'forever')
i = 1
for book in books:
ttk.Radiobutton(self.master,text=book,variable=self.intVar,command=self.change,value=i).pack(anchor=W)
i += 1
def change(self):
print(self.intVar.get())
root = Tk()
root.title("Radiobutton测试")
App(root)
root.mainloop()
#intVar/Checkbutton多选按钮
from tkinter import *
from tkinter import ttk
class App:
def __init__(self, master):
self.master = master
self.initWidgets()
def initWidgets(self):
self.chars = []
for ch in ('孙悟空', '猪八戒','唐僧', '牛魔王'):
intVar=IntVar()
self.chars.append(intVar)
ttk.Checkbutton(self.master,text=ch,variable=intVar,command=self.change).pack(anchor=W)#不加w会居中
def change(self):
print(','.join([str(e.get()) for e in self.chars]))
root = Tk()
root.title("Checkbutton测试")
root.iconbitmap('images/fklogo.ico')
App(root)
root.mainloop()
#Listbox
from tkinter import *
from tkinter import ttk
class App:
def __init__(self, master):
self.master = master
self.initWidgets()
def initWidgets(self):
#第一个frame
topF = Frame(self.master)
topF.pack(fill=Y, expand=YES)
#列表框
self.lb = Listbox(topF)
self.lb.pack(side=LEFT, fill=Y, expand=YES)
for item in ['Python', 'Kotlin', 'Swift', 'Ruby']:self.lb.insert(END, item)
#self.lb.insert(ANCHOR, 'Python', 'Kotlin', 'Swift', 'Ruby')#与上一行等价
self.lb.bind("", self.click)#列表框中的双击事件
#滚动条
scroll=Scrollbar(topF, command=self.lb.yview)# 创建Scrollbar组件,设置该组件与self.lb的纵向滚动关联
scroll.pack(side=RIGHT, fill=Y)
self.lb.configure(yscrollcommand=scroll.set)# 设置self.lb的纵向滚动影响scroll滚动条
#第二个frame
f = Frame(self.master)
f.pack()
#标签
Label(f, text = '选择模式:').pack(side=LEFT)
#多选按钮
self.strVar = StringVar()
self.strVar.set('browse')
for m in ('multiple', 'browse', 'single', 'extended'):#单选可拖动,多选,单选必单击,多选必ctrl/shift
ttk.Radiobutton(f,text=m,value=m,variable=self.strVar,command=self.choose_mode).pack(side=LEFT)
def choose_mode(self):
print(self.strVar.get())
self.lb['selectmode'] = self.strVar.get()
def click(self, event):
print(str(self.lb.curselection()))
root = Tk()
root.title("Listbox测试")
root.iconbitmap('images/fklogo.ico')
App(root)
root.mainloop()
#Combobox
from tkinter import *
from tkinter import ttk
class App:
def __init__(self, master):
self.master = master
self.initWidgets()
def initWidgets(self):
#下拉列表绑定字符串变量
self.strVar = StringVar()
self.cb = ttk.Combobox(self.master,textvariable=self.strVar,postcommand=self.choose)
self.cb.pack(side=TOP)
self.cb['values'] = ['Python', 'Ruby', 'Kotlin', 'Swift']
#frame
f = Frame(self.master)
f.pack()
#多选按钮绑定整型变量
self.isreadonly = IntVar()
Checkbutton(f, text = '是否只读:',variable=self.isreadonly,command=self.change).pack(side=LEFT)
Button(f, text = '绑定变量设置',command=self.setvalue).pack(side=LEFT)
def choose(self):
print(str(self.cb.get()))
def change(self):
self.cb['state'] = 'readonly' if self.isreadonly.get() else 'enable'#改cb的state属性
def setvalue(self):
self.strVar.set('我爱Python')#改字符串变量
root = Tk()
root.title("Combobox测试")
root.iconbitmap('images/fklogo.ico')
App(root)
root.mainloop()
#scale
from tkinter import *
from tkinter import ttk
class App:
def __init__(self, master):
self.master = master
self.initWidgets()
def initWidgets(self):
self.doubleVar = DoubleVar()
self.scale = Scale(self.master,
from_ = -100, # 设置最大值
to = 100, # 设置最小值
resolution = 5, # 设置步长
label = '示范Sacle', # 设置标签内容
length = 400, # 设置轨道的长度
width = 30, # 设置轨道的宽度
troughcolor='lightblue', # 设置轨道的背景色
sliderlength=20, # 设置滑块的长度
sliderrelief=SUNKEN, # 设置滑块的立体样式
showvalue=YES, # 设置显示当前值…………………………………这个就是本例中要控制的变量
orient = HORIZONTAL, #设置水平方向………………………这个就是本例中要控制的变量
digits = 10, # 设置十位有效数字
command = self.change, # 绑定事件处理函数(value会自动传过去)
variable = self.doubleVar # 绑定变量(如果只是获取的话不用绑定变量也可,直接self.scale.get())
)
self.scale.set(20)
self.scale.pack()
#第一个frame
f = Frame(self.master)
f.pack(fill=X, expand=YES, padx=10)
Label(f, text='是否显示值:').pack(side=LEFT)
self.showVar=IntVar()
self.showVar.set(1)
Radiobutton(f, text='不显示', value=0,variable=self.showVar,command=self.switch_show).pack(side=LEFT)
Radiobutton(f, text='显示', value=1,variable=self.showVar,command=self.switch_show).pack(side=LEFT)
#第一个frame
f = Frame(self.master)
f.pack(fill=X, expand=YES, padx=10)
Label(f, text='方向:').pack(side=LEFT)
self.orientVar = IntVar()
self.orientVar.set(0)
Radiobutton(f, text='水平', value=0,variable=self.orientVar,command=self.switch_orient).pack(side=LEFT)
Radiobutton(f, text='垂直', value=1,variable=self.orientVar,command=self.switch_orient).pack(side=LEFT)
def switch_show(self):
self.scale['showvalue'] = self.showVar.get()
def switch_orient(self):
self.scale['orient'] = VERTICAL if self.orientVar.get() else HORIZONTAL
def change(self, value):
print(value, self.scale.get(), self.doubleVar.get())
root = Tk()
root.title("Scale测试")
App(root)
root.mainloop()
#LabeledScale(简化版scale)
from tkinter import *
from tkinter import ttk
class App:
def __init__(self, master):
self.master = master
self.initWidgets()
def initWidgets(self):
self.scale=ttk.LabeledScale(self.master,from_=-100,to=100,compound=BOTTOM)#设置显示数值在下方
self.scale.value = -20
self.scale.pack(fill=X, expand=YES)
root = Tk()
root.title("LabeledScale测试")
App(root)
root.mainloop()
#Labelframe(frame上有标签)
from tkinter import *
from tkinter import ttk
class App:
def __init__(self, master):
self.master = master
self.initWidgets()
def initWidgets(self):
lf = ttk.Labelframe(self.master, text='请选择',padding=20)
lf.pack(fill=BOTH, expand=YES, padx=10, pady=10)
i = 0
self.intVar = IntVar()
for book in ['CJ', 'LOVES', 'GJL', '1314']:
Radiobutton(lf, text=book,value=i,variable=self.intVar,command=self.rb).pack(side=LEFT)
i += 1
def rb(self):
print(self.intVar.get())
self.intVar.set((self.intVar.get()+1)%4)
root = Tk()
root.title("Labelframe测试")
# 改变窗口图标
root.iconbitmap('images/fklogo.ico')
App(root)
root.mainloop()
#Panedwindow(用户可拉动分界线)
from tkinter import *
from tkinter import ttk
class App:
def __init__(self, master):
self.master = master
self.initWidgets()
def initWidgets(self):
#创建Panedwindow组件,通过style属性配置分隔线
style = ttk.Style()
style.configure("fkit.TPanedwindow", background='darkgray', relief=RAISED)
pwindow = ttk.Panedwindow(self.master,orient=VERTICAL, style="fkit.TPanedwindow")
pwindow.pack(fill=BOTH, expand=1)
#插入一般部件,add,remove,insert
pwindow.add(ttk.Label(pwindow, text="this is a label"))
okBn=ttk.Button(pwindow,text="this is a button",command=lambda:pwindow.remove(okBn))
pwindow.add(okBn)# 因为上面remove要引用okBn所以不能直接把创建代码扔进add里
pwindow.add(ttk.Entry(pwindow, width=30))
pwindow.insert(1, Label(pwindow, text="this is a label too"))
#插入pwindow部件,创建pwindow子对象是水平方向
rightwindow = PanedWindow(pwindow, orient=HORIZONTAL)
pwindow.add(rightwindow)
rightwindow.add(Label(rightwindow, text="左标签", background='lightgreen'))
rightwindow.add(Label(rightwindow, text="右标签", background='lightblue'))
root = Tk()
root.title("Panedwindow测试")
App(root)
root.mainloop()
#OptionMenu
from tkinter import *
from tkinter import ttk
class App:
def __init__(self, master):
self.master = master
self.initWidgets()
def initWidgets(self):
#先建个可选菜单
self.sv = StringVar()
self.om = ttk.OptionMenu(root,self.sv,'CJ','CJ','loves','GJL',command=self.print_option)
self.om.pack()
#然后建个有标签的frame
lf = ttk.Labelframe(self.master, padding=20, text='choose:')
lf.pack(fill=BOTH, expand=YES, padx=10, pady=10)
#层里建单选按钮
self.directions = ['below', 'above', 'left', 'right', 'flush']
i = 0
self.intVar = IntVar()
for direct in self.directions:
Radiobutton(lf,text=direct,value=i,command=self.change,variable=self.intVar).pack(side=LEFT)
i += 1
def print_option(self, val):
print(self.sv.get(), val)#其实就是绑定变量然后在函数里get就行了,同理set回去也可以
def change(self):
self.om['direction'] = self.directions[self.intVar.get()]#修改属性
root = Tk()
root.title("OptionMenu测试")
root.iconbitmap('images/fklogo.ico')
App(root)
root.mainloop()
#simpledialog,dialog提示对话框
from tkinter import *
from tkinter import ttk
from tkinter import simpledialog
from tkinter import dialog
class App:
def __init__(self, master):
self.master = master
self.initWidgets()
def initWidgets(self):
ttk.Button(self.master,text='SimpleDialog',command=self.open_simpledialog).pack(side=LEFT, ipadx=5, ipady=5, padx= 10)
ttk.Button(self.master,text='Dialog',command=self.open_dialog).pack(side=LEFT, ipadx=5, ipady=5, padx = 10)
def open_simpledialog(self):
d = simpledialog.SimpleDialog(self.master, # 设置该对话框所属的窗口
title='SimpleDialog测试', # 标题
text='CJ loves GJL.', # 内容
cancel=3, # 用户点击x关闭对话框时返回值
default=0, # 设置默认是哪个按钮得到焦点
buttons=["是", "否", "取消"] )
print(d.go()) #①
def open_dialog(self):
d = dialog.Dialog(self.master # 设置该对话框所属的窗口
, {'title': 'Dialog测试', # 标题
'text':'CJ loves GJL.', # 内容
'bitmap': 'question', # 图标
'default': 0, # 设置默认选中项
'strings': ('确定','取消','退出')})
print(d.num) #②
root = Tk()
root.title("对话框测试")
App(root)
root.mainloop()
##askinteger输入框
from tkinter import *
from tkinter import ttk
from tkinter import simpledialog
class App:
def __init__(self, master):
self.master = master
self.initWidgets()
def initWidgets(self):
ttk.Button(self.master,text='int',command=self.open_integer).pack(side=LEFT, ipadx=5, ipady=5, padx= 10)
ttk.Button(self.master,text='float',command=self.open_float).pack(side=LEFT, ipadx=5, ipady=5, padx= 10)
ttk.Button(self.master, text='str',command=self.open_string).pack(side=LEFT, ipadx=5, ipady=5, padx= 10)
ttk.Button(self.master,text='colour',command=self.choose_color).pack(side=LEFT,ipadx=5,ipady=5,padx= 10)
def open_integer(self):
print(simpledialog.askinteger("猜岁数","我老婆多少岁:",initialvalue=30,minvalue=10,maxvalue=50))
def open_float(self):
print(simpledialog.askfloat("猜体重","我老婆多少千克:",initialvalue=30,minvalue=10,maxvalue=50))
def open_string(self):
print(simpledialog.askstring("猜名字","我老婆叫什么名字:",initialvalue='GJL'))
def choose_color(self):
print(colorchooser.askcolor(parent=self.master, title='选择画笔颜色'))
root = Tk()
root.title("输入对话框测试")
App(root)
root.mainloop()
#message(共四部分:标题,文字,图标,按钮)
from tkinter import *
from tkinter import ttk
from tkinter import messagebox as msgbox
class App:
def __init__(self, master):
self.master = master
self.initWidgets()
def initWidgets(self):
#先弄个大frame
topF = Frame(self.master)
topF.pack(fill=BOTH)
#大frame下设图标选择
lf1 = ttk.Labelframe(topF, text='请选择图标类型')
lf1.pack(side=LEFT, fill=BOTH, expand=YES, padx=10, pady=5)
i = 0
self.iconVar = IntVar()
self.icons = [None, "error", "info", "question", "warning"]
for icon in self.icons:
Radiobutton(lf1, text = icon if icon is not None else '默认',value=i,variable=self.iconVar).pack(side=TOP, anchor=W)
i += 1
self.iconVar.set(0)
#大frame下设按钮选择
lf2 = ttk.Labelframe(topF, text='请选择按钮类型')
lf2.pack(side=LEFT,fill=BOTH, expand=YES, padx=10, pady=5)
i = 0
self.typeVar = IntVar()
self.types = [None, "abortretryignore", "ok", "okcancel","retrycancel", "yesno", "yesnocancel"]
for tp in self.types:
Radiobutton(lf2, text= tp if tp is not None else '默认',value=i,variable=self.typeVar).pack(side=TOP, anchor=W)
i += 1
self.typeVar.set(0)
#最下面是按钮事件
bottomF = Frame(self.master)
bottomF.pack(fill=BOTH)
btn1 = ttk.Button(bottomF, text="showinfo",command=self.showinfo_clicked)
btn1.pack(side=LEFT, fill=X, ipadx=5, ipady=5,pady=5, padx=5)
btn2 = ttk.Button(bottomF, text="showwarning",command=self.showwarning_clicked)
btn2.pack(side=LEFT, fill=X, ipadx=5, ipady=5,pady=5, padx=5)
btn3 = ttk.Button(bottomF, text="showerror",command=self.showerror_clicked)
btn3.pack(side=LEFT, fill=X, ipadx=5, ipady=5,pady=5, padx=5)
btn4 = ttk.Button(bottomF, text="askquestion",command=self.askquestion_clicked)
btn4.pack(side=LEFT, fill=X, ipadx=5, ipady=5,pady=5, padx=5)
btn5 = ttk.Button(bottomF, text="askokcancel",command=self.askokcancel_clicked)
btn5.pack(side=LEFT, fill=X, ipadx=5, ipady=5,pady=5, padx=5)
btn6 = ttk.Button(bottomF, text="askyesno",command=self.askyesno_clicked)
btn6.pack(side=LEFT, fill=X, ipadx=5, ipady=5,pady=5, padx=5)
btn7 = ttk.Button(bottomF, text="askyesnocancel",command=self.askyesnocancel_clicked)
btn7.pack(side=LEFT, fill=X, ipadx=5, ipady=5,pady=5, padx=5)
btn8 = ttk.Button(bottomF, text="askretrycancel",command=self.askretrycancel_clicked)
btn8.pack(side=LEFT, fill=X, ipadx=5, ipady=5,pady=5, padx=5)
def showinfo_clicked(self):
print(msgbox.showinfo("Info", "showinfo测试.",icon=self.icons[self.iconVar.get()],type=self.types[self.typeVar.get()]))
def showwarning_clicked(self):
print(msgbox.showwarning("Warning", "showwarning测试.",icon=self.icons[self.iconVar.get()],type=self.types[self.typeVar.get()]))
def showerror_clicked(self):
print(msgbox.showerror("Error", "showerror测试.",icon=self.icons[self.iconVar.get()],type=self.types[self.typeVar.get()]))
def askquestion_clicked(self):
print(msgbox.askquestion("Question", "askquestion测试.",icon=self.icons[self.iconVar.get()],type=self.types[self.typeVar.get()]))
def askokcancel_clicked(self):
print(msgbox.askokcancel("OkCancel", "askokcancel测试.",icon=self.icons[self.iconVar.get()],type=self.types[self.typeVar.get()]))
def askyesno_clicked(self):
print(msgbox.askyesno("YesNo", "askyesno测试.",icon=self.icons[self.iconVar.get()],type=self.types[self.typeVar.get()]))
def askyesnocancel_clicked(self):
print(msgbox.askyesnocancel("YesNoCancel", "askyesnocancel测试.",icon=self.icons[self.iconVar.get()],type=self.types[self.typeVar.get()]))
def askretrycancel_clicked(self):
print(msgbox.askretrycancel("RetryCancel", "askretrycancel测试.",icon=self.icons[self.iconVar.get()],type=self.types[self.typeVar.get()]))
root = Tk()
root.title("消息框测试")
App(root)
root.mainloop()
#filedialog(注意返回值是文件还是文件名/路径)
from tkinter import *
from tkinter import ttk
from tkinter import filedialog
class App:
def __init__(self, master):
self.master = master
self.initWidgets()
def initWidgets(self):
ttk.Button(self.master, text='打开单个文件',command=self.open_file).pack(side=LEFT, ipadx=5, ipady=5, padx= 10)
ttk.Button(self.master, text='打开多个文件',command=self.open_files).pack(side=LEFT, ipadx=5, ipady=5, padx= 10)
ttk.Button(self.master, text='获取单个打开文件的文件名',command=self.open_filename).pack(side=LEFT, ipadx=5, ipady=5, padx= 10)
ttk.Button(self.master, text='获取多个打开文件的文件名',command=self.open_filenames).pack(side=LEFT, ipadx=5, ipady=5, padx= 10)
ttk.Button(self.master, text='获取保存文件',command=self.save_file).pack(side=LEFT, ipadx=5, ipady=5, padx= 10)
ttk.Button(self.master, text='获取保存文件的文件名',command=self.save_filename).pack(side=LEFT, ipadx=5, ipady=5, padx= 10)
ttk.Button(self.master, text='打开路径',command=self.open_dir).pack(side=LEFT, ipadx=5, ipady=5, padx= 10)
def open_file(self):# 调用askopenfile方法获取单个打开的文件
print(filedialog.askopenfile(title='打开单个文件',filetypes=[("文本文件", "*.txt"), ('Python源文件', '*.py')],initialdir='g:/'))
def open_files(self):# 调用askopenfile方法获取多个打开的文件
print(filedialog.askopenfiles(title='打开多个文件',filetypes=[("文本文件", "*.txt"), ('Python源文件', '*.py')],initialdir='g:/'))
def open_filename(self):# 调用askopenfilename方法获取单个文件的文件名
print(filedialog.askopenfilename(title='打开单个文件',filetypes=[("文本文件", "*.txt"), ('Python源文件', '*.py')],initialdir='g:/'))
def open_filenames(self):# 调用askopenfilenames方法获取多个文件的文件名
print(filedialog.askopenfilenames(title='打开多个文件',filetypes=[("文本文件", "*.txt"), ('Python源文件', '*.py')],initialdir='g:/'))
def save_file(self):# 调用asksaveasfile方法保存文件
print(filedialog.asksaveasfile(title='保存文件',filetypes=[("文本文件", "*.txt"), ('Python源文件', '*.py')],initialdir='g:/'))
def save_filename(self):# 调用asksaveasfilename方法获取保存文件的文件名
print(filedialog.asksaveasfilename(title='保存文件',filetypes=[("文本文件", "*.txt"), ('Python源文件', '*.py')],initialdir='g:/'))
def open_dir(self):# 标题,初始路径,比上面的方法少了个文件类型(因为现在打开的是路径)
print(filedialog.askdirectory(title='打开目录',initialdir='g:/')) # 初始目录
root = Tk()
root.title("文件对话框测试")
App(root)
root.mainloop()
#Menu(command/checkbutton/radiobutton/separator,label标签/command方法/image贴图/compound方位)
from tkinter import *
from tkinter import ttk
from tkinter import messagebox as msgbox
class App:
def __init__(self, master):
self.master = master
self.init_menu()
def init_menu(self):
#一、总菜单对象
menubar = Menu(self.master)
self.master['menu'] = menubar
#二、主菜单对象
file_menu = Menu(menubar, tearoff=0)# 创建file_menu菜单,它被放入menubar中
lang_menu = Menu(menubar, tearoff=0)# 创建lang_menu菜单,它被放入menubar中
menubar.add_cascade(label='文件', menu=file_menu)# 使用add_cascade方法添加file_menu菜单
menubar.add_cascade(label='语言', menu=lang_menu)# 使用add_cascade方法添加lang_menu菜单
#三、为file_menu添加下拉菜单(注意加add_command是叶子项,加add_cascade是子级菜单)
self.master.filenew_icon = PhotoImage(file='images/filenew.png')
self.master.fileopen_icon = PhotoImage(file='images/fileopen.png')
file_menu.add_command(label="新建", command = None,image=self.master.filenew_icon, compound=LEFT)
file_menu.add_command(label="打开", command = None,image=self.master.fileopen_icon, compound=LEFT)
file_menu.add_separator()#分隔条
sub_menu = Menu(file_menu, tearoff=0)# 创建sub_menu菜单,它被放入file_menu中
file_menu.add_cascade(label='性别', menu=sub_menu) #使用add_cascade方法添加sub_menu子菜单
#四、为sub_menu添加子菜单(注意加了add_radiobutton单选按钮)
self.genderVar = IntVar()
for i, im in enumerate(['男', '女', '保密']):# 使用enumerate循环为sub_menu子菜单添加菜单项(特别注意这里的写法)
sub_menu.add_radiobutton(label=im,command=self.choose_gender,variable=self.genderVar, value=i)#枚举标签,同方法,同变量,枚举值
#五、为lang_menu添加下拉菜单(注意加了add_checkbutton多选按钮)
self.langVars = [StringVar(), StringVar(), StringVar(), StringVar()]
for i, im in enumerate(('Python', 'Kotlin','Swift', 'Java')):
lang_menu.add_checkbutton(label=im, command=self.choose_lang,onvalue=im, variable=self.langVars[i])
def choose_gender(self):
msgbox.showinfo(message=('选择的性别为: %s' % self.genderVar.get()))
def choose_lang(self):
rt_list = [e.get() for e in self.langVars]
msgbox.showinfo(message=('选择的语言为: %s' % ','.join(rt_list)))
root = Tk()
root.title("菜单测试")
root.geometry('400x200')
root.resizable(width=False, height=False)#禁止改变窗口大小
App(root)
root.mainloop()
#右键菜单(函数传参写法)
from tkinter import *
from tkinter import ttk
from collections import OrderedDict
class App:
def __init__(self, master):
self.master = master
self.initWidgets()
def initWidgets(self):
#主界面就是一个text
self.text=Text(self.master,height=12,width=60,foreground='darkgray',font=('微软雅黑',12),spacing2=8,spacing3=12)
self.text.insert(END,'CJ loves GJL.')
self.text.pack()
self.text.bind('',self.popup)
self.text.bind('', self.keyup)
#右键一级菜单是m1与m2
self.popup_menu = Menu(self.master,tearoff = 0)
m1 = Menu(self.popup_menu, tearoff = 0)
m2 = Menu(self.popup_menu, tearoff = 0)
self.popup_menu.add_cascade(label='fc',menu = m1)
self.popup_menu.add_cascade(label='bc',menu = m2)
#m1下的菜单是rgb三个,通过用variable绑定value来换前景色
self.fcVar=StringVar()
m1.add_radiobutton(label='r',command=self.choose1,variable=self.fcVar,value='red')
m1.add_radiobutton(label='b',command=self.choose1,variable=self.fcVar,value='blue')
m1.add_radiobutton(label='g',command=self.choose1,variable=self.fcVar,value='green')
#m2下的菜单也是rgb三个,但是用换了一种函数写法来换背景色
self.my_items=OrderedDict([('红色','red'), ('绿色','green'), ('蓝色', 'blue')])
for i in self.my_items:
m2.add_command(label=i,command=self.handlerAdaptor(self.choose2,val=i))
def popup(self, event):
self.popup_menu.post(event.x_root,event.y_root)
def choose1(self):
self.text['foreground'] = self.fcVar.get()
def choose2(self,val):
self.text['background'] = self.my_items[val]
def handlerAdaptor(self, fun,**kwds):
return lambda fun=fun, kwds=kwds: fun(**kwds)
def keyup(self, event):
print('up',event)#up
root = Tk()
root.title("右键菜单测试")
App(root)
root.mainloop()
#tearoff=1时的情况:能独立出来
import tkinter
root = tkinter.Tk()
root.title('menu')
menu = tkinter.Menu(root)
submenu = tkinter.Menu(menu, tearoff = 1)
submenu.add_command(label = '打开')
menu.add_cascade(label = '文件', menu = submenu)
root.config(menu = menu)
root.mainloop()
#Canvas
from tkinter import *
root = Tk()
cv = Canvas(root, background='white')
cv.pack(fill=BOTH, expand=YES)
cv.create_rectangle(30, 30, 200, 200,outline='red',stipple = 'question',fill="blue",width=5)
cv.create_oval(240, 30, 330, 200,outline='yellow',fill='pink',width=4)
Canvas.create_window(cv, 0, 0, window=Button(cv,text = '单击我', padx=10, pady=5,command = lambda :print('按钮单击')),anchor=NW)
root.mainloop()
#tag_bind与focus_set/bind
from tkinter import *
def first(event):
print('第一次的函数')
def second(event):
print('第二次的函数')
def move_left(event):
print('left')
root = Tk()
cv = Canvas(root,bg = 'white')# 创建一个Canvas,设置其背景色为白色
cv.pack()
cv.create_rectangle(30, 30, 220, 150,width = 8,tags = ('r1','r2','r3'))
cv.tag_bind('r1','', first)# 为指定图形项的左键单击事件绑定处理函数
cv.tag_bind('r1','', second, add=True)# add为True是添加,否则是替代
cv.focus_set()#让画布得到焦点,才可以响应按键事件
cv.bind('',move_left)
root.mainloop()
#第十二章:文件IO
#PurePath自动转PureWindowsPath
from pathlib import *
print(type(PurePath('setup.py'))) # ,自动转为win格式
print(PurePath('crazyit', 'some/path', 'info')) # 'crazyit\some\path\info'
print(PurePath(Path('crazyit'), Path('info'))) # 'crazyit\info'
print(PurePosixPath('crazyit','some/path' 'info')) # crazyit/some/path/info,Unix风格的路径
print(PurePath()) # . 不传入参数,默认使用当前路径
print(PurePosixPath('/etc', '/usr','lib64'))# /usr/lib64,传入参数包含多个根路径
print(PureWindowsPath('c:/Windows','d:info'))# d:info,仅最后一个根路径及后面子路径生效
print(PureWindowsPath('c:/Windows','/Program Files'))#c:\Program Files,在Win中盘符才算根路径
print(PurePath('crazyit//info')) # crazyit\info,路径字符串中多出来的斜杠和点号都会被忽略
print(PurePath('crazyit/./info')) # crazyit\info
print(PurePath('crazyit/../info')) # crazyit\..\info,相当于找和crazyit同一级的info路径
print(PurePosixPath('info') == PurePosixPath('INFO'))# False比较Unix风格路径区分大小写
print(PureWindowsPath('info') == PureWindowsPath('INFO')) # True比较WIN风格路径不区分大小写
print(PureWindowsPath('crazyit') == PurePosixPath('crazyit')) # False不同风格路径总不等
print(PureWindowsPath('abc') / 'xyz' / 'wawa') # abc\xyz\wawa(Win风格的路径)
print(PurePosixPath('abc') / 'xyz' / 'wawa') # abc/xyz/wawa(Unix风格的路径)
print(str(PureWindowsPath('abc','xyz','wawa'))) # abc\xyz\wawa
print(str(PurePosixPath('abc', 'xyz', 'wawa'))) # abc/xyz/wawa
#PurePath的属性
from pathlib import *
# 访问drive属性:驱动器盘符
print(PureWindowsPath('c:/Program Files/').drive) # c:
print(PureWindowsPath('/Program Files/').drive) # ''
print(PurePosixPath('/etc').drive) # ''
# 访问root属性:根路径
print(PureWindowsPath('c:/Program Files/').root) # \
print(PureWindowsPath('c:Program Files/').root) # ''
print(PurePosixPath('/etc').root) # /
# 访问anchor属性:盘符与根路径
print(PureWindowsPath('c:/Program Files/').anchor) # c:\
print(PureWindowsPath('c:Program Files/').anchor) # c:
print(PurePosixPath('/etc').anchor) # /
# 访问parents属性:全部父路径
pp = PurePath('abc/xyz/wawa/haha')
print(pp.parents[0]) # abc\xyz\wawa
print(pp.parents[1]) # abc\xyz
print(pp.parents[2]) # abc
print(pp.parents[3]) # .
# 访问parent属性:上一级路径,相当于parents[0]
print(pp.parent) # abc\xyz\wawa
# 访问name属性:当前路径文件名
print(PurePath('abc/wawa/bb.txt').name) # bb.txt
# 访问suffixes属性:所有后缀名
pp = PurePath('abc/wawa/bb.txt.tar.zip')
print(pp.suffixes[0]) # .txt
print(pp.suffixes[1]) # .tar
print(pp.suffixes[2]) # .zip
# 访问suffix属性:suffixes最后一个值
print(pp.suffix) # .zip
# 访问stem属性:当前路径主文件名
print(pp.stem) # bb.txt.tar
# 类型转换方法
pp = PurePath('d:/', 'Python', 'Python3.6')
print(pp.as_posix()) # d:/Python/Python3.6,转成Unix风格的路径
print(pp.as_uri()) # file:///d:/Python/Python3.6,绝对路径转换成Uri
# 判断当前路径是否匹配指定模式
print(PurePath('a/b.py').match('*.py')) # True
print(PurePath('/a/b/c.py').match('b/*.py')) # True
print(PurePath('/a/b/c.py').match('a/*.py')) # False
# 测试relative_to方法:去除基准路径的路径
pp = PurePosixPath('c:/abc/xyz/wawa')
print(pp.relative_to('c:/')) # abc\xyz\wawa
print(pp.relative_to('c:/abc')) # xyz\wawa
print(pp.relative_to('c:/abc/xyz')) # wawa
# 测试with_name方法:把当前路径文件名替换掉(当前路径无文件名会报错)
p = PureWindowsPath('e:/Downloads/pathlib.tar.gz')
print(p.with_name('fkit.py')) # e:\Downloads\fkit.py
# 测试with_suffix方法:把当前路径文件名后缀替换掉,若没有后缀则加上
print(PureWindowsPath('e:/pathlib.tar.gz').with_suffix('.zip')) # e:\pathlib.tar.zip
print(PureWindowsPath('README').with_suffix('.txt')) # README.txt
#Path的属性
from pathlib import *
for x in Path('.').iterdir():print(x)#当前目录下所有文件与子目录
for x in Path('../').glob('**/*.py'):print(x)#上级目录及其所有子目录下的的py文件
p = Path('a_test.txt')
print(p.write_text('''I LOVE GJL''', encoding='GBK'))# 返回输出的字符数
print(p.read_text(encoding='GBK'))# 输出读取的文本内容
print(p.read_bytes())# 读取字节内容
#os.path的属性
import os
import time
print(os.path.abspath("abc.txt")) # G:\publish\codes\12\12.2\abc.txt 获取绝对路径
print(os.path.commonprefix(['/usr/lib', '/usr/local/lib'])) # /usr/l 获取共同前缀
print(os.path.commonpath(['/usr/lib', '/usr/local/lib'])) # \usr 获取共同路径
print(os.path.dirname('abc/xyz/README.txt')) #abc/xyz 获取目录
print(os.path.exists('abc/xyz/README.txt')) # False 判断指定目录是否存在
print(time.ctime(os.path.getatime('a_test.txt')))# 获取最近一次访问时间
print(time.ctime(os.path.getmtime('a_test.txt')))# 获取最后一次修改时间
print(time.ctime(os.path.getctime('a_test.txt')))# 获取创建时间
print(os.path.getsize('a_test.txt'))# 获取文件大小
print(os.path.isfile('a_test.txt')) # True 判断是否为文件
print(os.path.isdir('a_test.txt')) # False 判断是否为目录
print(os.path.samefile('a_test.txt', './a_test.txt')) # True 判断是否为同一个文件
#fnmatch:file name match
from pathlib import *
import fnmatch
#fnmatch:对文件名进行匹配
for file in Path('.').iterdir():#遍历当前目录下所有文件和子目录
if fnmatch.fnmatch(file,'*.PY'):print(file)# 访问所有以_test.py结尾的文件
#filter:对列表中的串进行匹配
names = ['a.py', 'b.py', 'c.py', 'd.py']
print(fnmatch.filter(names, '[ac].py')) # ['a.py', 'c.py']
#translate:把UNIX的shell风格转换成pattern风格
print(fnmatch.translate('?.py')) # (?s:.\.py)\Z
print(fnmatch.translate('[ac].py')) # (?s:[ac]\.py)\Z
print(fnmatch.translate('[a-c].py')) # (?s:[a-c]\.py)\Z
#写文件
#一、默认生成的txt文件使用的编码是ANSI
import os
f = open('ANSI_test.txt', 'w+')#清空写入
f.write('我爱龚嘉露13' + os.linesep)# os.linesep代表当前操作系统上的换行符
f.writelines(('CJ'+os.linesep,'LOVES'+os.linesep,'GJL'+os.linesep))
f.close()
f = open('ANSI_test.txt', 'a+')#追加写入
f.write('我爱龚嘉露14' + os.linesep)# os.linesep代表当前操作系统上的换行符
f.writelines(('CJ'+os.linesep,'LOVES'+os.linesep,'GJL'+os.linesep,'1314'+ os.linesep))
f.close()
#二、生成以utf-8编码的txt文件要用二进制打开再显式设置utf-8
f = open('utf-8_test.txt', 'wb+')
f.write(('陈俊爱龚嘉露' + os.linesep).encode('utf-8'))
f.writelines((('I'+os.linesep).encode('utf-8'),('love'+os.linesep).encode('utf-8'),('GJL'+os.linesep).encode('utf-8')))
f.close()
#三、ANSI编码方式的读入
f=open("ANSI_test.txt", 'r+', True)
print(f.read())
f.close()
#四、utf-8编方式的读入
#(1)使用codecs读入时直接以编码形式读
import codecs
f=codecs.open('utf-8_test.txt', 'r+', 'utf-8', buffering=True)
print(f.read())
f.close()
#(2)先以二进制形式读入再转换编码
f=open('utf-8_test.txt','rb+',True) #指定使用二进制方式读取文件内容,得到的是bytes类型
print(f.read().decode('utf-8')) #用bytes的decode可将字节内容恢复成字符串
f.close()
#(3)补充:若上面输出不decode的话会得到
f=open('utf-8_test.txt','rb+',True) #指定使用二进制方式读取文件内容,得到的是bytes类型
print(f.read())#b'\xe9\x99\x88\xe4\xbf\x8a\xe7\x88\xb1\xe9\xbe\x9a\xe5\x98\x89\xe9\x9c\xb2\r\nI\r\nlove\r\nGJL\r\n'
f.close()
'''字符串前缀
一、字符串前加 r
r" " 的作用是去除转义字符
str1= 'input\n'
str= r'input\n'
print(str1)#input
print(str)#input\n
二、字符串前加 b
b" "前缀表示后面字符串是bytes类型
网络编程中,服务器和浏览器只认bytes类型数据
在 Python3 中,bytes 和 str 的互相转换方式是
str.encode('utf-8')
bytes.decode('utf-8')
三、字符串前加 u
例:u"我是含有中文字符组成的字符串。"
后面字符串以 Unicode 格式编码,防止因源码储存格式问题,导致再次使用时乱码
'''
#读文件
#零、热身
f = open('a_test.txt') # 默认打开方式
print(f.encoding) # cp936 访问文件的编码方式此处即utf-8
print(f.mode) # r 访问文件的访问模式
print(f.closed) # False 访问文件是否已经关闭
print(f.name) # a_test.txt 访问文件对象打开的文件名
'''(用三个+即可,二进制读入再加b)
r:只读(不清空,指针在开头)
w:只写(先清空)
a:只写(不清空,指针在结尾)
r+:读写(不清空,指针在开头)
w+:读写(先清空)
a+:读写(不清空,指针在结尾)
b:以二进制形式读写文件,用于非文本文件
'''
#一、逐字符读(第三个参数True表示使用缓冲)
f = open("a_test.txt", 'r', True)
while True:
ch = f.read(1) # 每次读取一个字符
if not ch: break # 如果没有读到数据,跳出循环
print(ch, end='') # 输出ch
f.close()
#二、一次读完
f = open("a_test.txt", 'r', True)
print(f.read())# 直接读取全部文件
f.close()
#三、逐行读出
import codecs
f = codecs.open("a_test.txt", 'r', 'utf-8', buffering=True)
while True:
line = f.readline() # 每次读取一行(其实就是遇\r\n或EOF为止),指针自动下移
if not line: break # 如果没有读到数据,跳出循环
print(line, end='') # 输出line
f.close()
import codecs
f = codecs.open("a_test.txt", 'r', 'utf-8', buffering=True)
for l in f.readlines():# 使用readlines()读取所有行,返回所有行组成的列表
print(l, end='')
f.close()
#四、读多文件
import fileinput
for line in fileinput.input(files=('a_test.txt', 'a_test.txt')):
print(fileinput.filename(), fileinput.filelineno(), line, end='')#名,行号,行
fileinput.close()# 关闭文件流
#五、with:该语句会负责关闭文件
import codecs
with codecs.open("a_test.txt", 'r', 'utf-8', buffering=True) as f:
for line in f:
print(line, end='')
import fileinput
with fileinput.input(files=('a_test.txt', 'a_test.txt')) as f:
for line in f:
print(line, end='')
#六、with关键字原理:__enter__与__exit__
class FkResource:
def __init__(self, tag):
self.tag = tag
print('类构造器: %s' % tag)
def __enter__(self):# 定义__enter__方法,with体之前的执行的方法
print('[__enter__ %s]: ' % self.tag)
return '我是'+self.tag # 该返回值将作为as子句中变量的值
def __exit__(self, exc_type, exc_value, exc_traceback):
print('[__exit__ %s]: ' % self.tag)
if exc_traceback is None:# exc_traceback为None,代表没有异常
print('无异常,关闭资源')
else:
print('有异常,关闭资源')
return False # 可以省略,默认返回None也被看做是False
with FkResource('孙悟空') as dr:
print('[with代码块] 开始')
print(dr)#正常执行
print('[with代码块] 结束')
print('------------------------------')
with FkResource('白骨精'):
print('[with代码块] 开始')
#raise Exception#出现异常
print('[with代码块] 结束')
#七、读指定行
import linecache
print(linecache.getline('a_test.txt', 2))# 读取普通文件的第2行
#八、用seek操作指针位置,tell访问指针下标,read读取字节
f=open('Python_test2.py', 'rb')
print(f.tell()) # 0,当前文件指针的位置
f.seek(3) # 将文件指针移动到3处
print(f.tell()) # 3,当前文件指针的位置
print(f.read(1)) # b'p',读取一个字节,文件指针自动后移1个数据
print(f.tell()) # 4,当前文件指针的位置
f.seek(5) # 将文件指针移动到5处,与f.seek(5,0)等价,以开头为基准
print(f.tell()) # 5
f.seek(5, 1) # 将文件指针向后移动5个数据,以指针当前位置为基准
print(f.tell()) # 10
f.seek(-10, 2) # 将文件指针移动到倒数第10处,以指针结尾位置为基准
print(f.tell()) # 574
print(f.read(1)) # b')'
'''
问:在哪里查看一个txt文件格式的编码?
答:打开文档,点另存为,最下面编码栏默认显示的即是当前文件的编码格式。
问:关于编码方式之间的关系:
一、ANSI,最原始的ASCII码,只有127位(但现在说的ANSI是含有GBK的ANSI)
二、ASCII+扩展字符,变成255位
三、GB2312,中国人取消掉127位以后的符号,在原ASCII码基础上加入6000多个汉字
······此时,原ACSII码若用两字节表示叫全角字符,用一字节表示叫半角字符(如,和,)
······区分全/半角:一个小于127的字符意义不变,但两个大于127的字符连在一起就表示一个汉字
四、GBK,在GB2312基础上加入20000个新的汉字(包括繁体字)和符号
······不要求低字节一定是127后的内码,只要第一个字节是大于127就固定表示这是一个汉字的开始
······现在所说的ANSI就是指原ASCII加上GBK扩展包的,我的手提笔记本默认是ANSI编码格式
五、GB18030,在GBK基础上加入几千个新的少数民族的字
六、UNICODE,世界各国都搞编码系统太乱,ISO出台的统一编码系统,全球通用
······用两字节表示一字符,总共可以组合出65535个字符,可覆盖世界上所有文化的符号
······半角英文符号只需要用到低8位,所以其高8位永远是0,虽然浪费但是硬盘空间已不是问题
······笔记本另存为中除了ANSI,Unicode,UTF-8外还有一项Unicode big endian是大端模式
七、UTF(UCS Transfer Format),用于传输,UTF8是每次8个位传输数据,UTF16是每次16个位
'''
#目录
import os
print(os.getcwd()) # 获取当前目录F:\ProjectPython\hello_test2
os.chdir('F:') # ch=change改变当前目录
os.mkdir('my_dir',0o755)#在当前目录创建目录,755是所有者/组用户/其他用户的读/写/执行权限
os.makedirs("abc/xyz/wawa", 0o755) # 递归创建目录
os.rename('my_dir', 'your_dir') # 直接重命名当前目录下的子目录
os.renames("abc/xyz/wawa", 'foo/bar/haha') # 递归重命名子目录
os.rmdir('your_dir') # 直接删除当前目录下的子目录
os.removedirs('foo/bar/haha') # 递归删除子目录
#权限
print(os.access('.', os.F_OK|os.R_OK|os.W_OK|os.X_OK))#当前目录权限F存在R读W写X执行
print(os.access('Python_test2.py', os.F_OK|os.R_OK|os.W_OK|os.X_OK))#文件权限
#链接
#os.symlink('Python_test4.py', 'soft_link.py')#创建快捷方式(WIN下要管理员权限)
#os.link('Python_test4.py', 'hard_link.py')#创建硬连接(Windows上就是复制文件)
#临时
import tempfile
fp = tempfile.TemporaryFile()# 创建临时文件
print(fp.name)
fp.write('两情若是久长时,'.encode('utf-8'))
fp.write('又岂在朝朝暮暮。'.encode('utf-8'))
fp.seek(0)# 将文件指针移到开始处,准备读取文件
print(fp.read().decode('utf-8')) # 输出刚才写入的内容
fp.close()#此时关闭就会自动删除
with tempfile.TemporaryFile() as fp:#通过with语句创建临时文件,块结束时自动关闭并删除临时文
fp.write(b'I Love Python!')# 写入内容
fp.seek(0)# 将文件指针移到开始处,准备读取文件
print(fp.read()) # b'I Love Python!'# 读取文件内容
with tempfile.TemporaryDirectory() as tmpdirname:# 通过with语句创建临时目录
print('创建临时目录', tmpdirname)
#第十三章:数据库
#sqlite3
import sqlite3
conn = sqlite3.connect('first.db')# ①、打开或创建数据库
c = conn.cursor()# ②、获取游标
#增
c.execute('''create table user_tb(_id integer primary key autoincrement,name text,pass text,gender text)''')#执行DDL语句创建数据表
#插
c.execute('insert into user_tb values(null, ?, ?, ?)',('孙悟空', '123456', 'male'))#调用执行insert语句插入数据
#改
c.executemany('update user_tb set name=? where _id=?',(('小孙',2),('小白',3),('小猪',4)))#调用executemany()方法同时修改多个语句
print('修改的记录条数:',c.rowcount)# 通过rowcount获取被修改的记录条数
#查
c.execute('select * from user_tb where _id > ?', (2,))#调用执行select语句查询数据
print('查询返回的记录数:', c.rowcount)
for col in (c.description):print(col[0], end='\t')#通过游标的description属性获取列信息
print('\n--------------------------------')
while True:
row = c.fetchone()# 获取一行记录,每行数据都是一个元组
if not row :break# 如果抓取的row为None,退出循环
print(row)
#SQL脚本
c.executescript('''insert into user_tb values(null, '武松', '3444', 'male')''')# 执行一段SQL脚本
#自定义函数
def reverse_ext(st):# 先定义一个普通函数,准备注册为SQL中的自定义函数
return '[' + st[::-1] + ']'# 对字符串反转,前后加方括号
conn.create_function('enc', 1, reverse_ext)## 调用create_function注册自定义函数:enc,这句要放在c游标赋值之前
c.execute('insert into user_tb values(null, ?, enc(?), ?)', ('贾宝玉', '123456', 'male'))# 在SQL语句中使用enc自定义函数
#聚集函数
class MinLen:# 先定义一个普通类,准备注册为SQL中的自定义聚集函数
def __init__(self):
self.min_len = None
def step(self, value):
if self.min_len is None : # 如果self.min_len还未赋值,直接将当前value赋值给self.min_lin
self.min_len = value
return
if len(self.min_len) > len(value):# 找到一个长度更短的value,用value代替self.min_len
self.min_len = value
def finalize(self):
return self.min_len
conn.create_aggregate('min_len', 1, MinLen)# 调用聚集函数名字,所需参数数目,函数实现类,这句要放在c游标赋值之前
c.execute('select min_len(pass) from user_tb')# 在SQL语句中使用min_len自定义聚集函数
print(c.fetchone()[0])#输出user_tb表中长度最短的密码
#比较函数
def my_collate(st1, st2):# 去掉字符串第一个、最后一个字符后比较大小
if st1[1: -1] == st2[1: -1]:return 0
elif st1[1: -1] > st2[1: -1]:return 1
else:return -1
conn.create_collation('sub_cmp', my_collate)# 调用create_collation注册自定义比较函数:sub_cmp,这句要放在c游标赋值之前
c.execute('select * from user_tb order by pass collate sub_cmp')# ③、在SQL语句中使用sub_cmp自定义的比较函数
for row in c:print(row)# 采用for循环遍历游标,不需要fetchone()
conn.commit()
c.close()# ④、关闭游标
conn.close()# ⑤、关闭连接
'''
DDL(data definition language): DDL比DML要多,主要的命令有CREATE、ALTER、DROP等,DDL主要是用在定义或改变表(TABLE)的结构,数据类型,表之间的链接和约束等初始化工作上,他们大多在建立表时使用,不需要commit
DML(data manipulation language): 它们是SELECT、UPDATE、INSERT、DELETE,就象它的名字一样,这4条命令是用来对数据库里的数据进行操作的语言,需要commit
DCL(Data Control Language): 是数据库控制功能。是用来设置或更改数据库用户或角色权限的语句,包括(grant,deny,revoke等)语句。在默认状态下,只有sysadmin,dbcreator,db_owner或db_securityadmin等人员才有权力执行DCL
TCL - Transaction Control Language:事务控制语言,COMMIT - 保存已完成的工作,SAVEPOINT - 在事务中设置保存点,可以回滚到此处,ROLLBACK - 回滚,SET TRANSACTION - 改变事务选项
'''
#第十四章:并发编程
'''
新建态start()变就绪态
就绪态得到CPU变运行态,运行态失去CPU变就绪态(CPU控制不关程序员事)
运行态sleep()或IO阻塞或等待锁或等待通知变阻塞态
阻塞态sleep()完或IO方法返回或获得锁或收到通知变就绪态
运行态run()或target完成变死亡态(若中途Error或Exception也变死亡态)
'''
#创建线程
#第一种方式:直接使用Thread类(推荐)
import threading
def action(maxs):
for j in range(maxs):
print(threading.current_thread().getName() + " " + str(j))
for i in range(10):
print(threading.current_thread().getName() + " " + str(i))
if i == 3:
t1 =threading.Thread(target=action,name='t1',args=(20,))
t1.start()#必须调用start()才能把run方法变成线程执行体,若调用run就是普通调用函数
t2 =threading.Thread(target=action,name='t2',args=(20,))
t2.start()#只有新建状态的线程才能调用start方法转换为就绪态
print('主线程执行完成!')
#threading.Thread的参数:
#group=None:线程所属线程组
#target=None:线程要调度的目标方法
#name=None:线程名字
#args=():传入参数
#kwargs=None:指定字典传入参数
#daemon=None:指定所构建的线程是否为后台线程
#第二种方式:继承Threado在(不推荐)
import threading
class myThread(threading.Thread):
def __init__(self,x):
threading.Thread.__init__(self,target=self.go,name=x)#相当于上一例的传参
self.j = 0
def go(self):
print('go')
'''
# 如果重写run()方法作为线程执行体,则会覆盖上面的go函数
def run(self):
while self.j < 20:
print(threading.current_thread().getName() + " " + str(self.j))
self.j += 1
'''
for i in range(10):
print(threading.current_thread().getName() + " " + str(i))
if i == 9:
ft1 = myThread('t1')
ft1.start()
ft2 = myThread('t2')
ft2.start()
print('主线程执行完成!')
#join
import time
import threading
def action():
time.sleep(2)
for i in range(5):
print(threading.current_thread().name+str(i)+'\n')
jt=threading.Thread(target=action, name="Join线程")
jt.start()
jt.join()#有参数timeout=None表示等待被join的最大时长
time.sleep(1)
print(threading.current_thread().name+'\n')
#daemon thread后台线程(全部前台线程结束就会结束)
import threading
def action(max):# 定义后台线程的线程执行体与普通线程没有任何区别
time.sleep(1)
for i in range(max):
print(threading.current_thread().name + " " + str(i))
t = threading.Thread(target=action,args=(20,),daemon = True,name='后台线程')
t.start()
time.sleep(1)
for i in range(10):
print(threading.current_thread().name + " " + str(i))
# -----程序执行到此处,前台线程(主线程)结束,后台线程也应该随之结束------
#time
import time
for i in range(10):
print("当前时间: %s" % time.ctime())
time.sleep(1)
#同步锁
import threading
import time
class Account:
def __init__(self, account_no, balance):
self.account_no = account_no #账户编号
self._balance = balance #账户余额
self.lock = threading.RLock()
def draw(self, draw_amount):# 提供一个线程安全的draw()方法来完成取钱操作
time.sleep(1)
self.lock.acquire()#blocking=True,timeout=-1指定加锁时间
try:
if self._balance>=draw_amount:#账户余额大于取钱数目
self._balance-=draw_amount#修改余额
print(threading.current_thread().name+"取钱成功,余额为:"+str(self._balance)+'\n',end='')
else:
print(threading.current_thread().name+"取钱失败,余额为:"+str(self._balance)+'\n',end='')
finally:
self.lock.release()# 修改完成,释放锁
def draw(account, draw_amount):
account.draw(draw_amount)# 直接调用account对象的draw()方法来执行取钱操作
acct = Account("1234567" , 1000)
threading.Thread(name='甲', target=draw , args=(acct , 500)).start()
threading.Thread(name='乙', target=draw , args=(acct , 600)).start()
#LOCK与RLOCK
#Lock:基本锁对象,每次锁一次,其余锁请求需等待锁释放后才能获取
#RLock:可重入锁,N次acquire就有N次release(推荐)
#死锁
import threading
import time
class A:
def __init__(self):
self.lock = threading.RLock()
def foo(self, b):
try:
self.lock.acquire()
print("当前线程名: " + threading.current_thread().name+ " 进入了A实例的foo()方法" ) # ①
time.sleep(0.2)
print("当前线程名: " + threading.current_thread().name+ " 企图调用B实例的last()方法") # ③
b.last()
finally:
self.lock.release()
def last(self):
try:
self.lock.acquire()
finally:
self.lock.release()
class B:
def __init__(self):
self.lock = threading.RLock()
def bar(self, a):
try:
self.lock.acquire()
print("当前线程名: " + threading.current_thread().name+ " 进入了B实例的bar()方法" ) # ②
time.sleep(0.2)
print("当前线程名: " + threading.current_thread().name+ " 企图调用A实例的last()方法") # ④
a.last()
finally:
self.lock.release()
def last(self):
try:
self.lock.acquire()
finally:
self.lock.release()
a = A()
b = B()
def init():
threading.current_thread().name = "主线程"
a.foo(b)
def action():
threading.current_thread().name = "副线程"
b.bar(a)
threading.Thread(target=action).start()
init()
#condition
#acquire/release:就是关联lock的acquire/release
#wait:当前进程进入condition等待池等待通知并释放锁
#notify:唤醒在condition等待池的单个线程(任意)
#notify_all:唤醒在condition等待池的全部线程
import threading
import time
class Account:
def __init__(self, account_no, balance):
self.account_no = account_no
self._balance = balance
self.cond = threading.Condition()
self._flag = False# 定义代表是否已经存钱的旗标
def draw(self, draw_amount):
time.sleep(0.5)
self.cond.acquire()# 加锁,相当于调用Condition绑定的Lock的acquire()
try:
if not self._flag:# 如果self._flag为假,表明账户中还没有人存钱进去,取钱方法阻塞
self.cond.wait()
else:
self._balance -= draw_amount
print(threading.current_thread().name+"取钱"+str(draw_amount)+" 账户余额"+str(self._balance)+'\n',end='')
self._flag = False# 将标识账户是否已有存款的旗标设为False
self.cond.notify_all()# 唤醒其他线程
finally:# 使用finally块来释放锁
self.cond.release()
def deposit(self, deposit_amount):
time.sleep(1)
self.cond.acquire()# 加锁,相当于调用Condition绑定的Lock的acquire()
try:
if self._flag:# 如果self._flag为真,表明账户中已有人存钱进去,存钱方法阻塞
self.cond.wait()
else:
self._balance += deposit_amount
print(threading.current_thread().name+"存款"+str(deposit_amount)+" 账户余额"+str(self._balance)+'\n',end='')
self._flag = True# 将表示账户是否已有存款的旗标设为True
self.cond.notify_all()# 唤醒其他线程
finally:# 使用finally块来释放锁
self.cond.release()
def draw_many(account, draw_amount, maxs):#模拟重复max次执行取钱操作
for i in range(maxs):
account.draw(draw_amount)
def deposit_many(account, deposit_amount, maxs):#模拟重复max次执行存款操作
for i in range(maxs):
account.deposit(deposit_amount)
acct = Account("1234567" , 0)# 创建一个账户
threading.Thread(name="取钱者", target=draw_many,args=(acct, 800, 10)).start()
threading.Thread(name="存款者甲", target=deposit_many,args=(acct , 800, 10)).start()
threading.Thread(name="存款者乙", target=deposit_many,args=(acct , 800, 10)).start()
threading.Thread(name="存款者丙", target=deposit_many,args=(acct , 800, 10)).start()
#queue
'''
queue.Queue(maxsize=0):FIFO
queue.LifoQueue(maxsize=0):LIFO
PriorityQueue(maxsize=0):优先队列
Queue.qsize():队列元素个数
Queue.empty():队列是否为空
Queue.full():队列是否为满
Queue.put(item,block=True,timeout=None):入队
Queue.put_nowait(item):入队且不阻塞(入不了就丢弃)
Queue.get(item,block=True,timeout=None):出队
Queue.get_nowait(item):出队且不阻塞(没元素就是空)
'''
import threading
import time
import queue
ans=[]
def product(bq):
for i in range(3):
t=threading.current_thread().name+"'s no."+str(i)
bq.put(t)# 尝试放入元素,如果队列已满,则线程被阻塞
ans.append(threading.current_thread().name+"第%d次生产%s"%(i,t))
def consume(bq):
for i in range(9):
t = bq.get()# 尝试取出元素,如果队列已空,则线程被阻塞
ans.append(threading.current_thread().name+"第%d次消费%s"%(i,t))
bq = queue.Queue(maxsize=1)# 创建一个容量为1的Queue
threading.Thread(target=product,name='a',args=(bq, )).start()# 启动3个生产者线程
threading.Thread(target=product,name='b',args=(bq, )).start()
threading.Thread(target=product,name='c',args=(bq, )).start()
threading.Thread(target=consume,name='x',args=(bq, )).start()# 启动一个消费者线程
time.sleep(1)#等待上面的线程跑完
print(ans)#我发现不用上面的ans而是直接print会十分混乱!
#event
#is_set():返回内部旗标是否为true
#set():设内部旗标为true
#clear():设内部旗标为false,后面常接wait
#wait(timeout=None):等待内部旗标为false
import threading
import time
event = threading.Event()
def cal(name):
print(name+'正式等待'+'\n',end='')
event.wait()
print(name+'正式计算'+'\n',end='')
threading.Thread(target=cal, args=('甲', )).start()
threading.Thread(target=cal, args=("乙", )).start()
time.sleep(0.1)
print('主线程发出事件')
time.sleep(0.1)
event.set()
#线程池:需要创建大量生存期很短暂的线程时使用
#result得到结果
from concurrent.futures import ThreadPoolExecutor
import threading
import time
def action(max):#定义线程任务是累加和
my_sum = 0
for i in range(max):
print(threading.current_thread().name + ' ' + str(i)+'\n',end='')
my_sum += i
return my_sum
pool = ThreadPoolExecutor(max_workers=2)# 创建一个包含2条线程的线程池
future1 = pool.submit(action, 10)# 向线程池提交一个task, 10会作为action()函数的参数
future2 = pool.submit(action, 20)# 向线程池提交一个task, 20会作为action()函数的参数
print(str(future1.done())+'\n',end='')# 判断future1代表的任务是否结束
time.sleep(0.1)
print(future2.done())# 判断future2代表的任务是否结束
print(future1.result())# 查看future1代表的任务返回的结果(如未返回会阻塞主线程)
print(future2.result())# 查看future2代表的任务返回的结果
pool.shutdown()# 关闭线程池
print('--------------')
#注意:最后四行一定是True,45,190,-------因为存在阻塞关系!
#add_done_callback:用法是调用回调函数,再调用result就可不阻塞主线程且何时执行完何时输出
from concurrent.futures import ThreadPoolExecutor
import threading
def action(max):# 定义一个准备作为线程任务的函数
my_sum = 0
for i in range(max):
print(threading.current_thread().name + ' ' + str(i)+'\n',end='')
my_sum += i
return my_sum
with ThreadPoolExecutor(max_workers=2) as pool:# 用with写就不用手动关了
future1 = pool.submit(action, 10)# 向线程池提交一个task, 50会作为action()函数的参数
future2 = pool.submit(action, 20)# 向线程池再提交一个task, 100会作为action()函数的参数
def get_result(future):
print(str(future.result())+'\n',end='')
future1.add_done_callback(get_result)# 为future1添加线程完成的回调函数
future2.add_done_callback(get_result)# 为future2添加线程完成的回调函数
print('--------------'+'\n',end='')
#map
from concurrent.futures import ThreadPoolExecutor
import threading
def action(max):# 定义一个准备作为线程任务的函数
my_sum = 0
for i in range(max):
print(threading.current_thread().name + ' ' + str(i)+'\n',end='')
my_sum += i
return my_sum
with ThreadPoolExecutor(max_workers=4) as pool:# 创建一个包含4条线程的线程池
results = pool.map(action, (10, 20, 30))#后面元组3元素故程序启动3条线程来执行action函数
print('--------------'+'\n',end='')
for r in results:
print(str(r)+'\n',end='')
#local(其实在线程执行函数里面定义局部变量即可)
import threading
from concurrent.futures import ThreadPoolExecutor
mydata = threading.local()# 定义线程局部变量:即每个线程都复制一个
def action (max):
for i in range(max):
try:
mydata.x += i
except:
mydata.x = i
print('%s mydata.x的值为: %d' %(threading.current_thread().name, mydata.x)+'\n',end='')
with ThreadPoolExecutor(max_workers=2) as pool:
pool.submit(action , 5)
pool.submit(action , 10)
#timer
from threading import Timer
def hello():
print("hello, world")
t=Timer(10.0, hello)# 指定10秒后执行hello函数
t.start()#定时器开始
from threading import Timer
import time
count = 0# 定义总共输出几次的计数器
def print_time():
print("当前时间:%s" % time.ctime())
global t, count
count += 1
if count < 10:# 如果count小于10,开始下一次调度
t=Timer(1, print_time)#定时器要重新装载
t.start()
t = Timer(1, print_time)# 指定1秒后执行print_time函数
t.start()
#任务调度
import sched, time
s = sched.scheduler()# 定义线程调度器
def print_time(name='default'):# 定义被调度的函数
print("%s 的时间: %s" % (name, time.ctime()))
print('主线程:', time.ctime())
s.enter(10, 1, print_time)# 指定10秒之后执行print_time函数
s.enter(5, 2, print_time, argument=('位置参数',))# 指定5秒之后执行print_time函数,优先级为2
s.enter(5, 1, print_time, kwargs={'name': '关键字参数'})# 指定5秒之后执行print_time函数,优先级为1
s.run()# 执行调度的任务,会阻塞主线程
print('主线程:', time.ctime())
#多进程
#fork
import os#在windows系统上无效
print('父进程(%s)开始执行' % os.getpid())
pid = os.fork()# 开始fork一个子进程,下面代码都会被两个进程执行
print('进程进入:%s' % os.getpid())
if pid == 0:# 如果pid为0,表明是子进程
print('子进程,其ID为 (%s), 父进程ID为 (%s)' % (os.getpid(), os.getppid()))
else:
print('我 (%s) 创建的子进程ID为 (%s).' % (os.getpid(), pid))
print('进程结束:%s' % os.getpid())
#Process(我的编译器好像有问题,开不了子进程)
#run重新进程执行体
#start启动进程
#join当前进程等被join进程执行完才能往下执行,name设置访问进程的名字
#is_alive()进程是否活着
#daemon进程是否是后台状态
#pid进程ID
#authkery进程授权key
#terminate()中断进程
import multiprocessing
import os
def action(maxs):
for i in range(maxs):
print("(%s)子进程(父进程:(%s)):%d" %(os.getpid(), os.getppid(), i))
if __name__ == '__main__':# 下面是主程序(也就是主进程)
for i in range(10):
print("(%s)主进程: %d" % (os.getpid(), i))
if i == 2:
mp=multiprocessing.Process(target=action,args=(10,))
mp.start()
mp.join()
print('主进程执行完成!')
import multiprocessing
import os
class MyProcess(multiprocessing.Process):
def __init__(self, max):
self.max = max
super().__init__()
def run(self):# 重写run()方法作为进程执行体
for i in range(self.max):
print("(%s)子进程(父进程:(%s)):%d"%(os.getpid(),os.getppid(),i))
if __name__ == '__main__':
for i in range(10):# 下面是主程序(也就是主进程)
print("(%s)主进程: %d" % (os.getpid(), i))
if i == 2:
mp=MyProcess(10)
mp.start()
mp.join()
print('主进程执行完成!')
#Context和启动进程的方式
import multiprocessing#fork在UNIX
def foo(q):
q.put('Python')
if __name__ == '__main__':
multiprocessing.set_start_method('fork') # 设置使用fork方式启动进程
q = multiprocessing.Queue()
mp = multiprocessing.Process(target=foo, args=(q, )) # 创建进程
mp.start() # 启动进程
print(q.get()) # 获取队列中的消息
import multiprocessing#spawn在WIN
def foo(q):
q.put('Python!')
if __name__ == '__main__':
ctx = multiprocessing.get_context('spawn') # 使用spawn方式启动进程并获取Context对象
q = ctx.Queue()# 接下来就可用Context对象来代替mutliprocessing模块了
mp = ctx.Process(target=foo, args=(q, )) # 创建进程
mp.start() # 启动进程
print(q.get()+'abc') # 获取队列中的消息
#进程池(唯一BUG:子进程不能输出到控制台)
import multiprocessing
import time
def action(name='default'):
print(name)
time.sleep(1)
if __name__ == '__main__':
pool = multiprocessing.Pool(processes=4)# 创建包含4条进程的进程池
pool.apply_async(action)# 将action分3次提交给进程池
pool.apply_async(action, args=('位置参数', ))
pool.apply_async(action, kwds={'name': '关键字参数'})
pool.close()
pool.join()
print('主进程结束')
import multiprocessing
def action(max):
my_sum = 0
for i in range(max):
print(i)#老样子,子进程不能输出到控制台
my_sum += i
return my_sum
if __name__ == '__main__':
with multiprocessing.Pool(processes=4) as pool:# 创建一个包含4条进程的进程池
results = pool.map(action, (50, 100, 150))
for r in results:print(r)
#队列通信
import multiprocessing
def f(q):
print('(%s) 进程开始放入数据...' % multiprocessing.current_process().pid)
q.put('Python')
if __name__ == '__main__':
q = multiprocessing.Queue()# 创建进程通信的Queue
p = multiprocessing.Process(target=f, args=(q,))# 创建子进程
p.start()# 启动子进程
p.join()
print('(%s) 进程开始取出数据...' % multiprocessing.current_process().pid)
print(q.get()) # 取出数据 Python
#管道通信
import multiprocessing
def f(conn):
print('(%s) 进程开始发送数据...' % multiprocessing.current_process().pid)
conn.send('Python')# 使用conn发送数据
if __name__ == '__main__':
parent_conn, child_conn = multiprocessing.Pipe()# 创建Pipe,该函数返回两个PipeConnection对象
p = multiprocessing.Process(target=f, args=(child_conn, ))# 创建子进程
p.start()# 启动子进程
print('(%s) 进程开始接收数据...' % multiprocessing.current_process().pid)
print(parent_conn.recv()) # 通过conn读取数据 Python
p.join()
#第十五章:网络编程
'''基本模块
传输层
socket------------重点(TCP/UDP服务器与客户端通讯)
asyncore
asynchat
应用层
email
mailbox
mailcap
ftplib
httplib
imaplib
nntplib
smtplib------------重点(发邮件)
poplib-------------重点(收邮件)
telnetlib
urllib-------------重点(分析网址内容,分析网页内容,cookie)
其他
xmlrpc,xmlrpc.server,xmlrpc.client
cgi
'''
#urllib
#urllib.request:open and read URL
#urllib.error:catch error
#urllib.parse:解析URL
#urllib.robotparser解析robots.txt文件
from urllib.parse import *#分析网址内容
result = urlparse('http://www.crazyit.org:80/index.php;yeeku?name=fkit#frag')# 解析URL字符串
print(result)# 下面通过属性名和索引来获取URL的各部分
print('scheme体系:', result.scheme, result[0])
print('主机和端口:', result.netloc, result[1])
print('主机:', result.hostname)
print('端口:', result.port)
print('资源路径:', result.path, result[2])
print('参数:', result.params, result[3])
print('查询字符串:', result.query, result[4])
print('fragment碎片:', result.fragment, result[5])
print(result.geturl())
print('---a--------------')
result = urlunparse(('http','www.crazyit.org:80','index.php','yeeku','name=fkit','frag'))
print('URL为:', result)
print('---b--------------')
result = urlparse('//www.crazyit.org:80/index.php')# 解析以//开头的URL
print('scheme:', result.scheme, result[0])
print('主机和端口:', result.netloc, result[1])
print('资源路径:', result.path, result[2])
print('---c--------------')
result = urlparse('www.crazyit.org/index.php')
print('scheme:', result.scheme, result[0])# 解析没有scheme,也没有以双斜线(//)开头的URL
print('主机和端口:', result.netloc, result[1])
print('资源路径:', result.path, result[2])# 从开头部分开始就会被当成资源路径
print('---d--------------')
result = parse_qs('name=fkit&name=%E7%96%AF%E7%8B%82java&age=12')# 解析查询字符串,返回dict
print(result)
result = parse_qsl('name=fkit&name=%E7%96%AF%E7%8B%82java&age=12')# 解析查询字符串,返回list
print(result)
print(urlencode(result))# 将列表格式的请求参数恢复成请求参数字符串
print('---e--------------')
# 被拼接URL以多少个/开头就会中踢掉后面多少个/段
result = urljoin('http://www.crazyit.org/users/login.html', 'help.html')
print(result) # http://www.crazyit.org/users/help.html
result = urljoin('http://www.crazyit.org/users/login.html', 'book/list.html')
print(result) # http://www.crazyit.org/users/book/list.html
result = urljoin('http://www.crazyit.org/users/login.html', '/help.html')# 被拼接URL以斜线(代表根路径path)开头
print(result) # http://www.crazyit.org/help.html
result = urljoin('http://www.crazyit.org/users/login.html', '//help.html')# 被拼接URL以双斜线(代表绝对URL)开头
print(result) # http://help.html
#urlopen(需要先在本地部署web应用,不然就改网址)
from urllib.parse import *#下面三例是不提交data,提交data-str及dict
with urlopen(url='https://www.baidu.com/') as f:
print(f.read().decode('utf-8'))# 读取服务器全部响应
with urlopen(url='https://www.baidu.com/',data='测试数据'.encode('utf-8')) as f:
print(f.read().decode('utf-8'))# 读取服务器全部响应
params = urllib.parse.urlencode({'name': '疯狂软件', 'password': '123888'}).encode('utf-8')
with urlopen("https://www.baidu.com/", data=params) as f:# 使用data指定请求参数
print(f.read().decode('utf-8'))
import requests #需求(分析网页内容,常结合re匹配要找的串)
from bs4 import BeautifulSoup #BeautifulSoup库解析代码
url='http://www.wsbookshow.com'#定义网址
html=requests.get(url) #引用需求库的获取网址HTML文件
html.encoding="GBK" #编码是GBK
soup=BeautifulSoup(html.text,'html.parser')#分析文件标签划分
print(soup)
#htmllist=html.text.splitlines() #把文本分隔
#for row in htmllist:print(row)
links=soup.find_all(["a","img"])#得到a,img两个标签的内容
for link in links:#逐个连接扫一次
href=link.get("href")#获取此连接中href关键字内容
if href!=None and href.startswith("http://"):#HREF以http://开头
print(href)#输出
#爬虫网站中的图片
import requests,os
from bs4 import BeautifulSoup
from urllib.request import urlopen
url='http://www.tooopen.com/img/87.aspx' #定义网址
html=requests.get(url) #获取HTML文件
html.encoding="utf-8" #定义编码方式
sp=BeautifulSoup(html.text,'html.parser') #解释
images_dir="images/" #定义路径
if not os.path.exists(images_dir): #如果路径不存在
os.mkdir(images_dir) #创建路径
all_links=sp.find_all(['a','img']) #寻获取所有A与IMG标签中的内容
for link in all_links:#遍历每一个标签内容
src=link.get('src')#获得标签内容中含SRC的串
href=link.get('href')#获得标签内容中含HREF的串
attrs=[href,src]#定义一个列表,两个元素分别是两个串
for attr in attrs:#遍历一次,这里要注意一个标签里可以有多个串含SRC或HREF
if attr!=None and ('.jpg' in attr or '.png' in attr):#如果非空且含JPG与PNG后缀
full_path=attr#读回其路径
filename=full_path.split('/')[-1]#文件名是按/划分的子串的倒数第一个
ext=filename.split('.')[-1]#后缀名是按.划分的子串中的倒数第一个
filename=filename.split('.')[-2]#文件名是按.划分的子串中的到数第二个
if 'jpg' in ext: filename=filename+'.jpg'#文件名加上后缀
else: filename=filename+'.png'#文件名加上后缀
print(filename)#输出文件名
try:#尝试
image=urlopen(full_path)#通过完整路径获取图片
f=open(os.path.join(images_dir,filename),'wb')#wb:以二进制写模式打开本地文件(由路径知其实是图片)
f.write(image.read())#写入文件(就是复制图片)
f.close()#关闭
except:#失败
print("error") #报错
#爬虫PM2.5实例
from bs4 import BeautifulSoup
import requests
url1='http://www.PM25X.com/'
html=requests.get(url1)
sp1=BeautifulSoup(html.text,'html.parser')
city=sp1.find("a",{"title":"北京PM2.5"})#find返回匹配结果的第一个元素
print(city)#输出
citylink=city.get("href")#获取href关键字的内容
print(citylink)#输出
url2=url1+citylink#由此可以得到子网页的网址
print(url2)#get the suburl!
html2=requests.get(url2)#获HTML
sp2=BeautifulSoup(html2.text,'html.parser')#分析
data1=sp2.select(".aqivalue")#选择
pm25=data1[0].text#得第0个元素的值
print("now Beijing's PM2.5 is: "+pm25)
'''
find_all(name,attrs,recursive,text,**kwargs)根据标签名/属性/内容查找文档,返回一个列表
text结果返回的是查到的所有的text='***'的文本
find(name,attrs,recursive,text,**kwargs)返回的匹配结果的第一个元素
get_text()可以获取文本内容
attrs可以传入字典的方式来查找标签,这里有个特殊的就是class,因为class在python中是特殊的字段,所以如果想要查找class相关的可以更改attrs={'class_':'element'}或者soup.find_all('',{"class":"element}),特殊的标签属性可以不写attrs,例如id
'''
#cookie保存(没服务器运行不了)
from urllib.request import *
import http.cookiejar, urllib.parse
cookie_jar = http.cookiejar.MozillaCookieJar('a.txt')# 以指定文件创建CookieJar对象,对象将可以把cookie保存在文件中
cookie_processor = HTTPCookieProcessor(cookie_jar)# 创建HTTPCookieProcessor对象
opener = build_opener(cookie_processor)# 创建OpenerDirector对象
user_agent = r'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36' \
r' (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36'# 定义模拟Chrome浏览器的user_agent
headers = {'User-Agent':user_agent, 'Connection':'keep-alive'}# 定义请求头
#-------------下面代码发送登录的POST请求----------------
params = {'name':'crazyit.org', 'pass':'leegang'}# 定义登录系统的请求参数
postdata = urllib.parse.urlencode(params).encode()
request = Request('http://localhost:8888/test/login.jsp',data = postdata, headers = headers)# 创建向登录页面发送POST请求的Request
response = opener.open(request)# 使用OpenerDirector发送POST请求
print(response.read().decode('utf-8'))
cookie_jar.save(ignore_discard=True, ignore_expires=True) # 将cookie信息写入磁盘文件
#-------------下面代码发送访问被保护资源的GET请求----------------
request = Request('http://localhost:8888/test/secret.jsp',headers=headers)# 创建向"受保护页面"发送GET请求的Request
response = opener.open(request)
print(response.read().decode())
#cookie加载(没服务器运行不了)
from urllib.request import *
import http.cookiejar, urllib.parse
cookie_jar = http.cookiejar.MozillaCookieJar('a.txt')# 以指定文件创建CookieJar对象,对象将可以把cookie保存在文件中
cookie_jar.load('a.txt',ignore_discard=True,ignore_expires=True)# 直接加载a.txt中的Cookie信息
for item in cookie_jar:# 遍历a.txt中保存的cookie信息
print('Name ='+ item.name)
print('Value ='+ item.value)
cookie_processor = HTTPCookieProcessor(cookie_jar)# 创建HTTPCookieProcessor对象
opener = build_opener(cookie_processor)# 创建OpenerDirector对象
user_agent = r'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36' \
r' (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36'# 定义模拟Chrome浏览器的user_agent
headers = {'User-Agent':user_agent, 'Connection':'keep-alive'}# 定义请求头
request = Request('http://localhost:8888/test/secret.jsp',headers=headers)# 创建向"受保护页面"发送GET请求的Request
response = opener.open(request)
print(response.read().decode())
'''
下面是本章重点,涉及编码问题
首先重申一下上一章的内容
二、字符串前加 b
b" "前缀表示后面字符串是bytes类型
网络编程中,服务器和浏览器只认bytes类型数据
在 Python3 中,bytes 和 str 的互相转换方式是
str.encode('utf-8')
bytes.decode('utf-8')
'''
with open('utf-8_test.txt','rb+',True) as f:
print(f.read().decode('utf-8'))#得到字符串注意编译器默认就是uft-8编码
with open('utf-8_test.txt','rb+',True) as f:
print(f.read())#得到字节类对象注意汉字是用24位二进制表示,如‘我’是\xe9\x99\x88
#UDP服务器端
import socket
s = socket.socket(type=socket.SOCK_DGRAM)#UDP
s.bind(('127.0.0.1',30000))#将该socket绑定到本机的指定IP和端口(注意这是本机IP与端口)
for i in range(3):#采用循环接收数据,此处设置接收三次就要结束连接
data,addr=s.recvfrom(4096)#读取s中的数据(最大4KB)的数据及发送地址(即源机IP与端口)
if data.decode('utf-8')=='exit':break#如果是退出就断开连接
else: print(data.decode('utf-8'))#否则将接收到的内容转换成字符串后输出
s.sendto('I love you.'.encode('utf-8'),addr)#将数据报发送给addr地址
s.close()
#UDP客户端
import socket
s=socket.socket(type=socket.SOCK_DGRAM)#创建基于UDP协议的socket
while True:
line=input('')#不断地读取键盘输入
s.sendto(line.encode('utf-8'),("127.0.0.1",30000))#往目的IP与PORT发送数据报
if line=='exit':break
print(s.recv(4096).decode('utf-8'))#读取socket中的数据,最大4KB
s.close()
#UDP多点广播(主客端一样的代码,SENDERPORT与TARGETPORT改同一个端口即可多点互通,下面用两个端口是因为只有一台机不能同一个端口绑定两次)
import socket, threading
SENDERIP = '127.0.0.1'# 定义本机IP地址
SENDERPORT = 30030# 定义本地发送端口,也是本机接收信息的端口
TARGETPORT = 30031# 定义目的接收端口,也是目的发送信息的端口
MYGROUP = '230.0.0.1'# 定义本程序的多点广播IP地址
s = socket.socket(type=socket.SOCK_DGRAM)# 通过type属性指定创建基于UDP协议的socket
s.bind(('0.0.0.0', SENDERPORT))#将该socket绑定到0.0.0.0的虚拟IP,在多点广播组内只要端口对就能接收
s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 64)# 设置广播消息的TTL(Time-To-Live)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)# 设置允许多点广播使用相同的端口
status=s.setsockopt(socket.IPPROTO_IP,socket.IP_ADD_MEMBERSHIP,socket.inet_aton(MYGROUP)+socket.inet_aton(SENDERIP))#将socket进入广播组
def read_socket(sock):
while True:#多线程循环执行体,从socket读取数据并输出
data = sock.recv(2048)#读回来的data是字节类对象
if data.decode('utf-8')=='exit':break#转成str才可以比较
print("\n收到的信息:", data.decode('utf-8'))
t=threading.Thread(target=read_socket, args=(s, ))
t.start()# 以read_socket作为target启动多线程
while True:#主线程循环执行体,采用循环不断读取键盘输入,并输出到socket中
line=input("发送的信息: ")#输入的line就是字符串类型
s.sendto(line.encode('utf-8'),(MYGROUP, TARGETPORT))#多点广播输出到广播IP中
if line=='exit':break#可以直接比较
t.join()
import time
time.sleep(0.1)
s.close()
#TCP例一:基本通讯
#server
import socket
import threading
ss = socket.socket()#创建socket对象
ss.bind(('192.168.101.9', 30003))#将socket绑定到本机IP和端口
ss.listen()#服务端开始监听来自客户端的连接
def server_target(s): #采用循环不断地从socket中读取客户端发送过来的数据
for i in range(3): #改成while True:可以一直死循环
content = s.recv(2048).decode('utf-8')#获得信息内容
print(content)
s.send(content.encode('utf-8'))
for i in range(1): #改成while True:可以一直死循环
s,addr=ss.accept() #此行代码会阻塞,将一直等待别人的连接
threading.Thread(target=server_target, args=(s,)).start()#每当客户端连接后启动一个线程为该客户端服务
#client
import socket
import threading
s = socket.socket() #创建socket对象
s.connect(('192.168.101.9', 30003)) #连接远程主机
def read_from_server(s): #客户端启动线程不断地读取来自服务器的数据
for i in range(3): #改成while True:可以一直死循环
print(s.recv(2048).decode('utf-8'))
threading.Thread(target=read_from_server, args=(s, )).start()
for i in range(3): #改成while True:可以一直死循环
line=input('')
if line=='exit':break
s.send(line.encode('utf-8'))#将用户的键盘输入内容写入socket
#补充一:要实现保存每个socket对应的数据,如用户名及密码,可用dict或创建新的类来维护
#补充二:要实现帐号密码登陆的,只需要在多线程执行体的循环前加上两次帐号密码通迅即可
#补充三、要实现TCP的多人聊天广播,每个群用一个列表(元素类型socket)来维护即可,发送到群就改为列表里逐个socket发
#TCP例二:半关闭的socket
#server
import socket
s = socket.socket() # 创建socket对象
s.bind(('192.168.101.9', 30000)) # 将socket绑定到本机IP和端口
s.listen() # 服务端开始监听来自客户端的连接
skt, addr = s.accept() #每当接收到客户端socket的请求时,该方法返回对应的socket和远程地址
skt.send("服务器的第一行数据".encode('utf-8'))
skt.send("服务器的第二行数据".encode('utf-8'))
skt.shutdown(socket.SHUT_WR) #关闭socket的输出,但仍可以接受数据,相当于发送空串
while True:
line = skt.recv(2048).decode('utf-8')# 从socket读取数据
if line is None:break
print(line)
skt.close()
s.close()
#client
import socket
s = socket.socket()# 创建socket对象
s.connect(('192.168.101.9', 30000))# 连接远程主机
while True:
line = s.recv(2048).decode('utf-8') #从socket读取数据
if line is None:break #读到空就break
print(line)
s.send("客户端的第一行数据".encode('utf-8'))
s.send("客户端的第二行数据".encode('utf-8'))
s.close()#相当于发送空串
#TCP例三:非阻塞读selectors
#好处:设置了监听事件后,不用死循环!
#server
import selectors,socket,time
sel = selectors.DefaultSelector()# 创建默认的selectors对象
def read(skt, mask):# 负责监听“有数据可读”事件的函数
try:
data = skt.recv(1024)# 读取数据
if data:
for s in socket_list:# 将读取的数据采用循环向每个socket发送一次
s.send(data) # Hope it won't block
else:# 如果该socket已被对方关闭,关闭该socket,并从socket_list列表中删除
print('关闭', skt)
sel.unregister(skt)
skt.close()
socket_list.remove(skt)
except:# 如果捕捉到异常, 将该socket关闭,并从socket_list列表中删除
print('关闭', skt)
sel.unregister(skt)
skt.close()
socket_list.remove(skt)
socket_list = []
def accept(sock, mask):# 负责监听“客户端连接进来”事件的函数
conn, addr = sock.accept()
socket_list.append(conn)# 使用socket_list保存代表客户端的socket
conn.setblocking(False)
sel.register(conn, selectors.EVENT_READ, read)#使用sel为conn的EVENT_READ事件注册read监听函数
sock = socket.socket()
sock.bind(('192.168.101.9', 30000))
sock.listen()
sock.setblocking(False) #设置该socket是非阻塞的
sel.register(sock, selectors.EVENT_READ, accept)#使用sel为sock的EVENT_READ事件注册accept监听函数
while True: #采用死循环不断提取sel的事件
time.sleep(1) #这一秒可以去做其他的事情
events = sel.select() #回顾过去一秒监听到的事件
for key, mask in events: #逐个事件调取对应的监听函数
callback = key.data #key的data属性获取为该事件注册的监听函数
callback(key.fileobj, mask) #调用监听函数, key的fileobj属性获取被监听的socket对象
#client
import selectors, socket, threading
sel = selectors.DefaultSelector() # 创建默认的selectors对象
def read(conn, mask): # 负责监听“有数据可读”事件的函数
data = conn.recv(1024) # Should be ready
if data:
print(data.decode('utf-8'))
else:
print('closing', conn)
sel.unregister(conn)
conn.close()
s = socket.socket() # 创建socket对象
s.connect(('192.168.101.9', 30000))# 连接远程主机
s.setblocking(False) # 设置该socket是非阻塞的
sel.register(s, selectors.EVENT_READ, read)#使用sel为s的EVENT_READ事件注册read监听函数
def keyboard_input(s): # 定义不断读取用户键盘输入的函数
while True:
line = input('')
if line == 'exit':break
s.send(line.encode('utf-8'))# 将用户的键盘输入内容写入socket
threading.Thread(target=keyboard_input, args=(s, )).start()# 采用线程不断读取用户的键盘输入
while True:
events = sel.select()# 获取事件
for key, mask in events:
callback = key.data# key的data属性获取为该事件注册的监听函数
callback(key.fileobj, mask)# 调用监听函数, key的fileobj属性获取被监听的socket对象
#SMTP发送
import smtplib
import email
from email.message import EmailMessage
#一、设置变量
smtp_server='smtp.qq.com'#定义SMTP服务器地址:
from_addr='[email protected]'#定义发件人地址
password='lllchhbtzygrbfbb'#定义登录邮箱的密码,但这里是授权码
to_addr='[email protected]'#定义收件人地址
#二、连接登陆
#conn=smtplib.SMTP(smtp_server, 25)#创建SMTP连接普通版
conn=smtplib.SMTP_SSL(smtp_server,465)#创建SMTP连接SSL版
conn.set_debuglevel(1)#显示调试过程
conn.login(from_addr, password)#登陆帐号
#三、创建邮件
msg = EmailMessage()#创建邮件对象
pic_id=email.utils.make_msgid()
with open('F:\ProjectPython\hello_test2\images\z.png','rb') as f:#正文中图片
msg.add_attachment(f.read(),maintype='image',subtype='png',filename='z.png', cid=pic_id)
with open('F:\ProjectPython\hello_test2\images\z.png','rb') as f:#附件
msg.add_attachment(f.read(),maintype='application',subtype='png',filename='z.png',)
msg.set_content('老婆我爱你!'+'
','html','utf-8')#设置邮件内容,指定邮件内容为HTML
msg['subject']='情书'
msg['from']='老公<%s>'%from_addr
msg['to']='老婆<%s>'%to_addr
#四、发送邮件
conn.sendmail(from_addr, [to_addr], msg.as_string())#发送邮件
conn.quit()#退出连接
#POP3接收
import poplib, os.path, mimetypes
from email.policy import default
#一、输入邮件地址, 口令和POP3服务器地址:
email = '[email protected]'
password = 'lllchhbtzygrbfbb'
pop3_server = 'pop.qq.com'
#二、连接到POP 3服务器:
#conn = poplib.POP3(pop3_server, 110)
conn = poplib.POP3_SSL(pop3_server, 995)
conn.set_debuglevel(0)# 可以打开或关闭调试信息
#print(conn.getwelcome().decode('utf-8'))# 可选:打印POP 3服务器的欢迎文字:
conn.user(email)#发送POP 3的user命令输入用户名、密码信息
conn.pass_(password)#发送POP 3的pass命令获取邮件统计信息,相当于发送POP 3的stat命令
message_num, total_size = conn.stat()
print('邮件数: %s. 总大小: %s' % (message_num, total_size))
resp, mails, octets = conn.list()# 发送POP 3的list命令获取服务器上的邮件列表
#print(resp, mails)# resp保存服务器的响应码,mails列表保存每封邮件的编号、大小
resp,data,octets=conn.retr(len(mails))#发送POP3的retr命令获取指定邮件内容(传入总长度是获取最后一封邮件),resp响应码data邮件内容
# data保存该邮件的内容
msg_data = b'\r\n'.join(data)# 将data的所有数据(原本是一个字节列表)拼接在一起
msg=BytesParser(policy=default).parsebytes(msg_data)# 将字符串内容解析成邮件类对象,此处一定要指定policy=default
print('发件人:' + msg['from'])
print('收件人:' + msg['to'])
print('主题:' + msg['subject'])
print('第一个收件人名字:' + msg['to'].addresses[0].username)
print('第一个发件人名字:' + msg['from'].addresses[0].username)
for part in msg.walk():#分开正文与附件,其中正文
counter = 1
if part.get_content_maintype()=='multipart':continue#multipart是容器(用于包含正文附件)
elif part.get_content_maintype()=='text':print(part.get_content())#text是邮件正文部分
else : # 处理附件
filename = part.get_filename() # 获取附件的文件名
if not filename: # 如果没有文件名,程序要负责为附件生成文件名
ext = mimetypes.guess_extension(part.get_content_type())# 根据附件的contnet_type来推测它的后缀名
if not ext:ext = '.bin' # 如果推测不出后缀名,使用.bin作为后缀名
filename = 'part-%03d%s' % (counter, ext) # 程序为附件来生成文件名
counter += 1
with open(os.path.join('.', filename), 'wb') as fp: # 将附件写入的本地文件
fp.write(part.get_payload(decode=True))
conn.quit() # 退出服务器,相当于发送POP 3的quit命令
#第十六章:文档测试
#doctest:自动执行注释里的样例并生成错误报告
def square (x):
'''
一个用于计算平方的函数
例如
>>> square(2)
4
>>> square(3)
9
>>> square(-3)
9
>>> square(0)
0
'''
return x * 2 # ①、故意写错的
return x ** 2
class User:
'''
定义一个代表用户的类,该类包含如下两个属性:
name - 代表用户的名字
age - 代表用户的年龄
例如
>>> u = User('fkjava', 9)
>>> u.name
'fkjava'
>>> u.age
9
>>> u.say('i love python')
'fkjava说: i love python'
'''
def __init__(self, name, age):
self.name = name
self.name = 'fkit' # ②、故意写错的
self.age = age
def say(self, content):
return self.name + '说: ' + content
if __name__=='__main__':
import doctest
doctest.testmod()
#单元测试逻辑覆盖
def test (a, b, m):
if a > 10 and b == 0:
m = a + b
if a == 20 or m > 15:
m += 1
'''
一、语句覆盖:每条语句都至少执行一次
a=20,b=0,m=3 两真
二、判定(边)覆盖/分支覆盖:每个判断分支取真取假各至少执行一次(a>10与b==0是同一分支)
a=20,b=0,m=3 两真
a=10,b=0,m=3 两假
三、条件覆盖:每个判断中每个条件的可能取值都至少满足一次(a>10与b==0是两个条件)
a=20,b=1,m=10 先假再真
a=9,b=0,m=20 先假再真
四、判定-条件覆盖:每个条件所有可能的组合至少出现一次
a=20,b=0,m=3 两真
a=20,b=1,m=10 先假再真
a=10,b=0,m=20 两假
a=1,b=2,m=3 两假
五、路径覆盖:覆盖所有路径
a=20,b=0,m=3 两真
a=5,b=0,m=2 两假
a=20,b=1,m=10 先假再真
a=20,b=0,m=7 先真再假
'''
#测试用类例
#fk_math.py
def one_equation(a , b):
'''
求一元一次方程a * x + b = 0的解
参数a - 方程中变量的系数
参数b - 方程中的常量
返回 方程的解
'''
# 如果a = 0,则方程无法求解
if a == 0:
raise ValueError("参数错误")
# 返回方程的解
else:
# return -b / a # ①
return b / a
def two_equation(a , b , c):
'''
求一元二次方程a * x * x + b * x + c = 0的解
参数a - 方程中变量二次幂的系数
参数b - 方程中变量的系数
参数c - 方程中的常量
返回 方程的根
'''
if a == 0:raise ValueError("参数错误")# 如果a == 0,变成一元一次方程
elif b * b - 4 * a * c < 0:raise ValueError("方程在有理数范围内无解")
elif b * b - 4 * a * c == 0:return -b / (2 * a)# 方程有唯一的解
else:
r1 = (-b + (b * b - 4 * a * c) ** 0.5) / 2 / a
r2 = (-b - (b * b - 4 * a * c) ** 0.5) / 2 / a
return r1, r2# 方程的两个解
#test_fk_math.py
import unittest
from fk_math import *
class TestFkMath(unittest.TestCase):
def test_one_equation(self):# 测试一元一次方程的求解
self.assertEqual(one_equation(5 , 9) , -1.8)# 断言该方程求解应该为-1.8
self.assertTrue(one_equation(4 , 10) == -2.5 , .00001)# 断言该方程求解应该为-2.5
self.assertTrue(one_equation(4 , -27) == 27 / 4)# 断言该方程求解应该为27/4
with self.assertRaises(ValueError):one_equation(0 , 9)# 断言当a == 0时的情况,断言引发ValueError
def test_two_equation(self):# 测试一元二次方程的求解
self.assertCountEqual(two_equation(1 , -3 , 2), (1.0, 2.0), '求解出错')
self.assertCountEqual(two_equation(2 , -7 , 6), (1.5, 2.0), '求解出错')
self.assertEqual(two_equation(1 , -4 , 4), 2.0, '求解出错')# 断言只有一个解的情形
with self.assertRaises(ValueError):two_equation(0, 9, 3)# 断言当a == 0时的情况,断言引发ValueError
with self.assertRaises(ValueError):two_equation(4, 2, 3)# 断言引发ValueError
if __name__ == '__main__':
unittest.main()
#测试包与运行器(就是把前面的测试用例组合起来)
#hello.py
def say_hello():
return "Hello World."
def add(nA, nB):
return nA + nB
#test_hello.py
import unittest
from hello import *
class TestHello(unittest.TestCase):
def test_say_hello(self):
self.assertEqual(say_hello() , "Hello World.")
def test_add(self):
self.assertEqual(add(3, 4) , 7)
self.assertEqual(add(0, 4) , 4)
self.assertEqual(add(-3, 0) , -3)
#suite_test.py
import unittest
from test_fk_math import TestFkMath
from test_hello import TestHello
test_cases = (TestHello, TestFkMath)
def whole_suite():
loader = unittest.TestLoader()# 创建测试加载器
suite = unittest.TestSuite()# 创建测试包
for test_class in test_cases:# 遍历所有测试类
tests = loader.loadTestsFromTestCase(test_class)# 从测试类中加载测试用例
suite.addTests(tests)# 将测试用例添加到测试包中
return suite
if __name__ == '__main__':
with open('fk_test_report.txt', 'a') as f:
runner = unittest.TextTestRunner(verbosity=2, stream=f)#创建测试运行器(TestRunner),测试报告输出到文件中
runner.run(whole_suite())#测试
#第十七章:pyinstaller
#Python_test2.py文件
def say_hello(name):
return name + ",您好!"
#Python_test3.py文件
from Python_test2 import *
def main():
print('程序开始执行')
print(say_hello('孙悟空'))
# 增加调用main()函数
if __name__ == '__main__':
main()
#命令行的代码
#pyinstaller -F F:\ProjectPython\hello_test2\Python_test3.py
#-F表示生成一个大EXE文件,-D表示生成一个目录(动态重定位),加-w取消命令行
#-n NAME或-name NAME可以指定项目名字,如果省略则第一个脚本的主文件名将作为spec名字(其实就是main.py,你在开发的时候把这个主程序入口的py文件命名好就行了,例如tank_game.py则最后就会生成tank_game.exe)
#现在还未知道如何改图标
#第十八章:pygame
import pygame
def main():
pygame.init() #初始化
screen=pygame.display.set_mode((1024,640)) #开窗口
pygame.display.set_caption("tank game") #定标题
background=pygame.Surface(screen.get_size())#获大小
background=background.convert() #屏幕转像素
background.fill((100,100,100)) #白色填充
clock=pygame.time.Clock() #开定时器
running=True #运行标志
while running: #主程序大循环
clock.tick(30) #最大每秒30帧
for event in pygame.event.get(): #检测退出信息
if event.type==pygame.QUIT: #如果有的话
running=False #更改标志位
screen.blit(background,(0,0)) #位块传送把背景回到左上角
#鼠标事件
buttons=pygame.mouse.get_pressed() #获鼠标按下事件
if buttons[0]:print(pygame.mouse.get_pos()) #按左键输出坐标
#键盘事件
keys=pygame.key.get_pressed() #获键盘按下事件
if keys[pygame.K_SPACE]:print('space') #按下空格输出space
#绘图:画矩形(在screen上画,[r,g,b],[左上角x,y,长,宽],线宽),线宽取0是填充
pygame.draw.rect(screen,[255,0,0],[600,600,10,10],0)
#贴图
maps = pygame.image.load('GJL.png') #获取图片
screen.blit(maps,(0,0)) #贴到screen的左上角
pygame.display.update() #更新显示
pygame.quit() #退出游戏
main()
'''
KeyASCII ASCII 描述
K_BACKSPACE \b 退格键(Backspace)
K_TAB \t 制表键(Tab)
K_CLEAR 清楚键(Clear)
K_RETURN \r 回车键(Enter)
K_PAUSE 暂停键(Pause)
K_ESCAPE ^[ 退出键(Escape)
K_SPACE 空格键(Space)
K_EXCLAIM ! 感叹号(exclaim)
K_QUOTEDBL " 双引号(quotedbl)
K_HASH # 井号(hash)
K_DOLLAR $ 美元符号(dollar)
K_AMPERSAND & and 符号(ampersand)
K_QUOTE ' 单引号(quote)
K_LEFTPAREN ( 左小括号(left parenthesis)
K_RIGHTPAREN ) 右小括号(right parenthesis)
K_ASTERISK * 星号(asterisk)
K_PLUS + 加号(plus sign)
K_COMMA , 逗号(comma)
K_MINUS - 减号(minus sign)
K_PERIOD . 句号(period)
K_SLASH / 正斜杠(forward slash)
K_0 0 0
K_1 1 1
K_2 2 2
K_3 3 3
K_4 4 4
K_5 5 5
K_6 6 6
K_7 7 7
K_8 8 8
K_9 9 9
K_COLON : 冒号(colon)
K_SEMICOLON ; 分号(semicolon)
K_LESS < 小于号(less-than sign)
K_EQUALS = 等于号(equals sign)
K_GREATER > 大于号(greater-than sign)
K_QUESTION ? 问号(question mark)
K_AT @ at 符号(at)
K_LEFTBRACKET [ 左中括号(left bracket)
K_BACKSLASH \ 反斜杠(backslash)
K_RIGHTBRACKET ] 右中括号(right bracket)
K_CARET ^ 脱字符(caret)
K_UNDERSCORE _ 下划线(underscore)
K_BACKQUOTE ` 重音符(grave)
K_a a a
K_b b b
K_c c c
K_d d d
K_e e e
K_f f f
K_g g g
K_h h h
K_i i i
K_j j j
K_k k k
K_l l l
K_m m m
K_n n n
K_o o o
K_p p p
K_q q q
K_r r r
K_s s s
K_t t t
K_u u u
K_v v v
K_w w w
K_x x x
K_y y y
K_z z z
K_DELETE 删除键(delete)
K_KP0 0(小键盘)
K_KP1 1(小键盘)
K_KP2 2(小键盘)
K_KP3 3(小键盘)
K_KP4 4(小键盘)
K_KP5 5(小键盘)
K_KP6 6(小键盘)
K_KP7 7(小键盘)
K_KP8 8(小键盘)
K_KP9 9(小键盘)
K_KP_PERIOD . 句号(小键盘)
K_KP_DIVIDE / 除号(小键盘)
K_KP_MULTIPLY * 乘号(小键盘)
K_KP_MINUS - 减号(小键盘)
K_KP_PLUS + 加号(小键盘)
K_KP_ENTER \r 回车键(小键盘)
K_KP_EQUALS = 等于号(小键盘)
K_UP 向上箭头(up arrow)
K_DOWN 向下箭头(down arrow)
K_RIGHT 向右箭头(right arrow)
K_LEFT 向左箭头(left arrow)
K_INSERT 插入符(insert)
K_HOME Home 键(home)
K_END End 键(end)
K_PAGEUP 上一页(page up)
K_PAGEDOWN 下一页(page down)
K_F1 F1
K_F2 F2
K_F3 F3
K_F4 F4
K_F5 F5
K_F6 F6
K_F7 F7
K_F8 F8
K_F9 F9
K_F10 F10
K_F11 F11
K_F12 F12
K_F13 F13
K_F14 F14
K_F15 F15
K_NUMLOCK 数字键盘锁定键(numlock)
K_CAPSLOCK 大写字母锁定键(capslock)
K_SCROLLOCK 滚动锁定键(scrollock)
K_RSHIFT 右边的 shift 键(right shift)
K_LSHIFT 左边的 shift 键(left shift)
K_RCTRL 右边的 ctrl 键(right ctrl)
K_LCTRL 左边的 ctrl 键(left ctrl)
K_RALT 右边的 alt 键(right alt)
K_LALT 左边的 alt 键(left alt)
K_RMETA 右边的元键(right meta)
K_LMETA 左边的元键(left meta)
K_LSUPER 左边的 Window 键(left windows key)
K_RSUPER 右边的 Window 键(right windows key)
K_MODE 模式转换键(mode shift)
K_HELP 帮助键(help)
K_PRINT 打印屏幕键(print screen)
K_SYSREQ 魔术键(sysrq)
K_BREAK 中断键(break)
K_MENU 菜单键(menu)
K_POWER 电源键(power)
K_EURO 欧元符号(euro)
'''
第十九章:matplotlib
#入门
import matplotlib.pyplot as plt
import numpy as np
plt.figure()
plt.subplot(2,1,1)#将整个figure分成两行两列,并将下面图形放在第4个网格
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
y_data = [58000, 60200, 63000, 71000, 84000, 90500, 107000]
y_data2 = [52000, 54200, 51500,58300, 56800, 59500, 62700]
ln1,=plt.plot(x_data,y_data,color='red',linewidth=2.0,linestyle='--',label='cj')#折线颜色、线宽和样式
ln2,=plt.plot(x_data,y_data2,color='blue',linewidth=3.0,linestyle='-.',label='gjl')#-实线--虚线:点线-.点虚线
plt.legend(loc='lower right')#调用legend函数设置图例,location默认是'best'自动选择最佳位置
plt.xlabel('year')
plt.ylabel('salary')
plt.title('gogogo')
#plt.yticks([50000,70000,100000],[r'A',r'B',r'C'])#这行出现就会代替Y坐标值
#plt.show()# 调用show()函数显示图形
ax = plt.gca()#返回的是axis坐标轴
ax.spines['bottom'].set_position(('data',70000))#设置坐标轴的bottom处的位置是data=70000处
#ax.yaxis.set_ticks_position('left')#设置坐标轴的Y轴的位置在left处,可以无视,默认就是这样
#ax.xaxis.set_ticks_position('bottom')#设置坐标轴的X轴的的位置在bottom处,可以无视,默认就是这样
#ax.spines['right'].set_color('red')#设置右边坐标轴线的颜色(设置为none表示不显示),可以无视,没啥用
#ax.spines['top'].set_color('blue')#设置顶部坐标轴线的颜色(设置为none表示不显示),可以无视,没啥用
plt.subplot(2,1,2)#将整个figure分成两行两列,第三个参数表示下面的图形放在第1个网格
x_data=np.linspace(-np.pi,np.pi,64,endpoint=True)#利用np.pi线性均分成64个点
plt.plot(x_data, np.sin(x_data))#开始绘制正弦曲线,注意此时的plt是画在212位置的
plt.gca().spines['right'].set_color('none')
plt.gca().spines['top'].set_color('none')
plt.gca().spines['bottom'].set_position(('data', 0))
plt.gca().spines['left'].set_position(('data', 0))
plt.title('sin')
plt.show()
#子图
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.gridspec as gridspec
plt.figure()
x_data = np.linspace(-np.pi, np.pi, 64, endpoint=True)#取生成x点
gs = gridspec.GridSpec(2, 3)# 将绘图区域分成2行3列
ax1 = plt.subplot(gs[0, :])# 指定ax1占用第零行
ax2 = plt.subplot(gs[1, 0])# 指定ax1占用第一行的第零格
ax3 = plt.subplot(gs[1, 1:3])# 指定ax1占用一行的第二、三格
ax1.plot(x_data, np.sin(x_data))# 绘制正弦曲线
ax1.spines['right'].set_color('none')
ax1.spines['top'].set_color('none')
ax1.spines['bottom'].set_position(('data', 0))
ax1.spines['left'].set_position(('data', 0))
ax1.set_title('sin')
ax2.plot(x_data, np.cos(x_data))# 绘制余弦曲线
ax2.spines['right'].set_color('none')
ax2.spines['top'].set_color('none')
ax2.spines['bottom'].set_position(('data', 0))
ax2.spines['left'].set_position(('data', 0))
ax2.set_title('cos')
ax3.plot(x_data, np.tan(x_data))# 绘制正切曲线
ax3.spines['right'].set_color('none')
ax3.spines['top'].set_color('none')
ax3.spines['bottom'].set_position(('data', 0))
ax3.spines['left'].set_position(('data', 0))
ax3.set_title('tan')
plt.show()
#饼图
import matplotlib.pyplot as plt
data=[0.16881, 0.14966, 0.07471, 0.06992,0.04762, 0.03541, 0.02925, 0.02411, 0.02316, 0.01409, 0.36326]
labels=['Java','C','C++','Python','Visual Basic .NET','C#','PHP','JavaScript','SQL','Assembly langugage','other']
explode = [0, 0, 0, 0.3, 0, 0, 0, 0, 0, 0, 0]# 将第4个语言(Python)分离出来
colors=['red', 'pink', 'magenta','purple','orange'] # 使用自定义颜色
plt.axes(aspect='equal')#正圆
plt.xlim(0,8)#边框大小
plt.ylim(0,8)#边框大小
plt.pie(x = data, # 绘图数据
labels=labels, # 添加编程语言标签
explode=explode, # 突出显示Python
colors=colors, # 设置饼图的自定义填充色
autopct='%.3f%%', # 设置百分比的格式,此处保留3位小数
pctdistance=0.8, # 设置百分比标签与圆心的距离
labeldistance = 1.15, # 设置标签与圆心的距离
startangle = 180, # 设置饼图的初始角度
center = (4, 4), # 设置饼图的圆心(相当于X轴和Y轴的范围)
radius = 3.8, # 设置饼图的半径(相当于X轴和Y轴的范围)
counterclock = False, # 是否逆时针,这里设置为顺时针方向
wedgeprops = {'linewidth': 1, 'edgecolor':'green'},# 设置饼图内外边界的属性值
textprops = {'fontsize':12, 'color':'black'}, # 设置文本标签的属性值
frame = 1) # 是否显示饼图的圆圈,此处设为显示
plt.xticks(())
plt.yticks(())
plt.title('2018-08 languagu rank')
plt.show()
#竖柱状图
import matplotlib.pyplot as plt
import numpy as np
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
y_data = [58000, 60200, 63000, 71000, 84000, 90500, 107000]
y_data2 = [52000, 54200, 51500,58300, 56800, 59500, 62700]
bar_width=0.3
#range(len(x_data)就是0、1、2控制中心坐标故np.arange(len(x_data))是左柱中心坐标,加+bar_width就是右柱中心坐标
plt.bar(x=range(len(x_data)),height=y_data,label='CJ',color='steelblue', alpha=0.8, width=bar_width)
plt.bar(x=np.arange(len(x_data))+bar_width+0.05, height=y_data2,label='GJL', color='indianred', alpha=0.8, width=bar_width)
for x,y in enumerate(y_data):plt.text(x,y,'%s'%y,ha='center',va='bottom')#x,y是坐标,'%s'%y是内容
for x,y in enumerate(y_data2):plt.text(x+bar_width,y,'%s'%y,ha='center',va='top')#ha水平对齐, va垂直对齐
plt.xticks(np.arange(len(x_data))+bar_width/2, x_data)# 为X轴设置刻度值
plt.title("CJ&GJL")#设置标题
plt.xlabel("year")#X标签
plt.ylabel("salary")#Y标答
plt.legend()#图例
plt.show()
#横柱状图
import matplotlib.pyplot as plt
import numpy as np
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
y_data = [58000, 60200, 63000, 71000, 84000, 90500, 107000]
y_data2 = [52000, 54200, 51500,58300, 56800, 59500, 62700]
bar_width=0.3
plt.barh(y=range(len(x_data)), width=y_data, label='CJ',color='steelblue', alpha=0.8, height=bar_width)
plt.barh(y=np.arange(len(x_data))+bar_width, width=y_data2,label='GJL', color='indianred', alpha=0.8, height=bar_width)
for y, x in enumerate(y_data):plt.text(x+5000,y-bar_width/2,'%s'%x,ha='center',va='bottom')
for y, x in enumerate(y_data2):plt.text(x+5000,y+bar_width/2,'%s'%x,ha='center',va='bottom')
plt.yticks(np.arange(len(x_data))+bar_width/2, x_data)# 为Y轴设置刻度值
plt.title("CJ&GJL")#设置标题
plt.xlabel("year")#X标签
plt.ylabel("salary")#Y标答
plt.legend()#图例
plt.show()
#散点图
import matplotlib.pyplot as plt
import numpy as np
plt.figure()
x_data = np.linspace(-np.pi, np.pi, 64, endpoint=True)# 定义从-pi到pi之间的数据,平均取64个数据点
plt.scatter(x_data, #x值
np.sin(x_data), #y值
c='purple', #设置点的颜色
s=50, #设置点半径
alpha = 0.5, #设置透明度
marker='p', #设置使用五边形标记
linewidths=1, #设置边框的线宽
edgecolors=['green', 'yellow']) # 设置边框的颜色
plt.scatter(x_data[0], np.sin(x_data)[0], c='red',s=150, alpha = 1)
plt.scatter(x_data[63], np.sin(x_data)[63], c='black',s=150,alpha = 1)
plt.gca().spines['right'].set_color('none')
plt.gca().spines['top'].set_color('none')
plt.gca().spines['bottom'].set_position(('data', 0))
plt.gca().spines['left'].set_position(('data', 0))
plt.title('sin')
plt.show()
#等高线图
import matplotlib.pyplot as plt
import numpy as np
delta = 0.025
x=np.arange(-3.0,3.0,delta)#生成代表X轴数据的列表
y=np.arange(-2.0,2.0,delta)#生成代表Y轴数据的列表
X,Y=np.meshgrid(x, y)#对x、y数据执行网格化
Z1=np.exp(-X**2-Y**2)
Z2=np.exp(-(X-1)**2-(Y-1)**2)
Z=(Z1-Z2)*2# 计算Z轴数据(高度数据)
plt.contourf(x,y,Z,16,alpha=0.75,cmap='rainbow')#使用颜色映射来区分16种不同高度的区域
C=plt.contour(x,y,Z,16,#绘制等高线
colors='black',#指定等高线的颜色
linewidth=0.5)#指定等高线的线宽
plt.clabel(C, inline = True, fontsize = 10)#绘制等高线数据
plt.xticks(())#去除坐标轴
plt.yticks(())#去除坐标轴
plt.title("contour")
plt.xlabel("x")
plt.ylabel("y")
plt.show()
#3D图形
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure(figsize=(12, 8))
ax = Axes3D(fig)
delta = 0.125
x = np.arange(-3.0, 3.0, delta)# 生成代表X轴数据的列表
y = np.arange(-2.0, 2.0, delta)# 生成代表Y轴数据的列表
X, Y = np.meshgrid(x, y)# 对x、y数据执行网格化
Z1 = np.exp(-X**2 - Y**2)
Z2 = np.exp(-(X - 1)**2 - (Y - 1)**2)
Z = (Z1 - Z2) * 2# 计算Z轴数据(高度数据)
ax.plot_surface(X, Y, Z, # 绘制3D图形
rstride=1, # rstride(row)指定行的跨度
cstride=1, # cstride(column)指定列的跨度
cmap=plt.get_cmap('rainbow')) # 设置颜色映射
ax.set_zlim(-2, 2)# 设置Z轴范围
plt.title("3D")# 设置标题
plt.show()
#pygal:实在太简单了,缺点是必须用浏览器看
import pygal
#例一柱图
y_data = [58000, 60200, 63000, 71000, 84000, 90500, 107000]
y_data2 = [52000, 54200, 51500,58300, 56800, 59500, 62700]
bar = pygal.Bar()# 创建pygal.Bar对象(柱状图)
bar.add('Java', y_data)# 添加两组代表条柱的数据
bar.add('Android', y_data2)
bar.render_to_file('fk_books.svg')# 添加两组代表条柱的数据
#例二柱图加强版
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
bar.x_labels = x_data# 设置X轴的刻度值
bar.title = '销量'
bar.x_title = '年份'
bar.y_title = '销量'
bar.x_label_rotation = 45# 设置X轴的刻度值旋转45度
bar.legend_at_bottom = True# 设置将图例放在底部
bar.margin = 35# 设置数据图四周的页边距,也可通过margin_bottom、margin_left、margin_right、margin_top只设置单独一边的页边距
bar.show_y_guides=False# 隐藏Y轴上的网格线
bar.show_x_guides=True# 显示X轴上的网格线
bar.render_to_file('fk_books.svg')# 指定将数据图输出到SVG文件中
#例三折线图
line = pygal.Line()# 创建pygal.Line对象(折线图)
line.add('Java', y_data)# 添加两组代表折线的数据
line.add('Android', y_data2)
line.x_labels = x_data# 设置X轴的刻度值
line.y_labels = [20000, 40000, 60000, 80000, 100000]# 重新设置Y轴的刻度值
line.title = '销量'
line.x_title = '年份'
line.y_title = '销量'
line.legend_at_bottom = True# 设置将图例放在底部
line.render_to_file('fk_books.svg')# 指定将数据图输出到SVG文件中
#水平柱状图
horizontal_bar = pygal.HorizontalBar()# 创建pygal.HorizontalBar对象(水平柱状图)
horizontal_bar.add('Java', y_data)# 添加两组数据
horizontal_bar.add('Android', y_data2)
horizontal_bar.x_labels = x_data# 设置Y轴的刻度值(注意xy这里掉乱说的,有点迷糊)
horizontal_bar.y_labels = [20000, 40000, 60000, 80000, 100000]# 重新设置X轴的刻度值
horizontal_bar.title = '销量'
horizontal_bar.x_title = '销量'
horizontal_bar.y_title = '年份'
horizontal_bar.legend_at_bottom = True# 设置将图例放在底部
horizontal_bar.render_to_file('fk_books.svg')# 指定将数据图输出到SVG文件中
#水平折线图
horizontal_line = pygal.HorizontalLine()# 创建pygal.HorizontalLine对象(水平折线图)
horizontal_line.add('Java', y_data)# 添加两组代表折线的数据
horizontal_line.add('Android', y_data2)
horizontal_line.x_labels = x_data# 设置Y轴(确实如此)的刻度值
horizontal_line.y_labels = [20000, 40000, 60000, 80000, 100000]# 重新设置X轴(确实如此)的刻度值
horizontal_line.title = '销量'
horizontal_line.x_title = '销量'
horizontal_line.y_title = '年份'
horizontal_line.legend_at_bottom = True# 设置将图例放在底部
horizontal_line.render_to_file('fk_books.svg')# 指定将数据图输出到SVG文件中
#叠加柱状图
stacked_bar = pygal.StackedBar()
stacked_bar.add('Java', y_data)# 添加两组数据
stacked_bar.add('Android', y_data2)
stacked_bar.x_labels = x_data# 设置X轴的刻度值
stacked_bar.y_labels = [20000, 40000, 60000, 80000, 100000]# 重新设置Y轴的刻度值
stacked_bar.title = '销量'
stacked_bar.x_title = '销量'
stacked_bar.y_title = '年份'
stacked_bar.legend_at_bottom = True# 设置将图例放在底部
stacked_bar.render_to_file('fk_books.svg')# 指定将数据图输出到SVG文件中
#叠加折线图
stacked_line = pygal.StackedLine()
stacked_line.add('Java', y_data)# 添加两组数据
stacked_line.add('Android', y_data2)
stacked_line.x_labels = x_data# 设置X轴的刻度值
stacked_line.y_labels = [20000, 40000, 60000, 80000, 100000]# 重新设置Y轴的刻度值
stacked_line.title = '销量'
stacked_line.x_title = '销量'
stacked_line.y_title = '年份'
stacked_line.legend_at_bottom = True# 设置将图例放在底部
stacked_line.render_to_file('fk_books.svg')# 指定将数据图输出到SVG文件中
#点图
dot = pygal.Dot()
dot.dots_size = 5
dot.add('Java', y_data)# 添加两组数据
dot.add('Android', y_data2)
dot.x_labels = x_data# 设置X轴的刻度值
dot.y_labels = ['Java', 'Android']# 重新设置Y轴的刻度值
dot.y_label_rotation = 45# 设置Y轴刻度值的旋转角度
dot.title = '销量'
dot.x_title = '年份'
dot.legend_at_bottom = True# 设置将图例放在底部
dot.render_to_file('fk_books.svg')# 指定将数据图输出到SVG文件中
#饼图
data=[0.16881,0.14966,0.07471,0.06992,0.04762,0.03541,0.02925,0.02411,0.02316,0.01409,0.36326]
labels=['Java','C','C++','Python','Visual Basic .NET','C#','PHP','JavaScript','SQL','Assembly langugage','其他']# 准备标签
pie = pygal.Pie()# 创建pygal.Pie对象(饼图)
for i, per in enumerate(data): pie.add(labels[i], per)# 采用循环为饼图添加数据
pie.title = '2018年8月编程语言'
pie.legend_at_bottom = True# 设置将图例放在底部
pie.inner_radius = 0.4# 设置内圈的半径长度
pie.half_pie = True# 创建半圆数据图
pie.render_to_file('fk_books.svg')# 指定将数据图输出到SVG文件中
#仪表图
gauge = pygal.Gauge()# 创建pygal.Gauge对象(仪表图)
gauge.range = [0, 1]
for i, per in enumerate(data):gauge.add(labels[i], per)# 采用循环为仪表图添加数据
gauge.title = '2018年8月编程语言'
gauge.legend_at_bottom = True# 设置将图例放在底部
gauge.render_to_file('fk_books.svg')# 指定将数据图输出到SVG文件中
#雷达图
data = [[5, 4.0, 5, 5, 5],# 准备数据
[4.8, 2.8, 4.8, 4.8, 4.9],
[4.5, 2.9, 4.6, 4.0, 4.9],
[4.0, 4.8, 4.9, 4.0, 5],
[3.0, 4.2, 2.3, 3.5, 2],
[4.8, 4.3, 3.9, 3.0, 4.5]]
labels = ['Java', 'C', 'C++', 'Python','C#', 'PHP']# 准备标签
rader = pygal.Radar()# 创建pygal.Radar对象(雷达图)
for i, per in enumerate(labels):rader.add(labels[i], data[i])# 采用循环为雷达图添加数据
rader.x_labels = ['平台健壮性', '语法易用性', '社区活跃度','市场份额', '未来趋势']
rader.title = '编程语言对比图'
rader.dots_size = 8# 控制各数据点的大小
rader.legend_at_bottom = True# 设置将图例放在底部
rader.render_to_file('fk_books.svg')# 指定将数据图输出到SVG文件中
#csv
import csv
import pygal
from datetime import datetime
from datetime import timedelta
with open('guangzhou-2017.csv') as f:# 打开文件
reader = csv.reader(f)# 创建cvs文件读取器
header_row = next(reader)# 读取第一行,这行是表头数据。
print(header_row)
shades, sunnys, cloudys, rainys = 0, 0, 0, 0# 准备展示的数据
prev_day = datetime(2016, 12, 31)
for row in reader:
try:
cur_day = datetime.strptime(row[0], '%Y-%m-%d')# 将第一列的值格式化为日期
description = row[3]
except ValueError:
print(cur_day, '数据出现错误')
else:
diff = cur_day - prev_day# 计算前、后两天数据的时间差
if diff != timedelta(days=1):# 如果前、后两天数据的时间差不是相差一天,说明数据有问题
print('%s之前少了%d天的数据' % (cur_day, diff.days - 1))
prev_day = cur_day
if '阴' in description:shades += 1
elif '晴' in description:sunnys += 1
elif '云' in description:cloudys += 1
elif '雨' in description:rainys += 1
else:print(description)
pie = pygal.Pie()# 创建pygal.Pie对象(饼图)
pie.add("阴", shades)# 为饼图添加数据
pie.add("晴", sunnys)
pie.add("多云", cloudys)
pie.add("雨", rainys)
pie.title = '2017年广州天气汇总'
pie.legend_at_bottom = True# 设置将图例放在底部
pie.render_to_file('fk_books.svg')# 指定将数据图输出到SVG文件中
#json
import json
with open('gdp_json.json') as f:
gpd_list = json.load(f)
for gpd_dict in gpd_list:# 遍历列表的每个元素,每个元素是一个GDP数据项
if gpd_dict['Year']==2016 and gpd_dict['Country Code']=='CHN':#中国2016年GDP
print(gpd_dict['Country Name'], gpd_dict['Value'])
#第二十章:自动登陆及刷阅读量
from selenium import webdriver
from time import sleep
url='http://www.51cto.com'#定义网址
browser=webdriver.Chrome()#打开浏览器并获句柄
browser.maximize_window() #最大化窗口
browser.get(url) #打开URL
browser.find_element_by_xpath('//*[@id="login_status"]/a[1]').click()#点击登陆按钮
browser.find_element_by_xpath('//*[@id="loginform-username"]').clear()#帐户框清空
browser.find_element_by_xpath('//*[@id="loginform-username"]').send_keys('13690670863')#输入帐号
browser.find_element_by_xpath('//*[@id="loginform-password"]').clear()#密码框清空
browser.find_element_by_xpath('//*[@id="loginform-password"]').send_keys('abcde123456789')#输入密码
sleep(3)#延时三秒
browser.find_element_by_xpath('//*[@id="login-form"]/div[3]/input').click()#点击确定
sleep(3)#延时三秒
browser.quit()#退出
补充一句:spyder中一键注释快捷键是ctrl+1