日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

疯狂python讲义学习笔记——中十章完结

發布時間:2023/12/8 python 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 疯狂python讲义学习笔记——中十章完结 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

#第十一章 thinker import tkinter as tk print(help(tk.Button.__init__))#以按扭為例查看有什么屬性 class myApplication(tk.Frame):def __init__(self,master=None):#一、frametk.Frame.__init__(self,master)self.pack()#二、buttononButton=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'#禁用狀態前景色gray25onButton['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或DISABLE1onButton['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.setonButton.pack()#三、Labelw=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 = masterself.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)# 該容器放在左邊排列,就會挨著fm1Button(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 = masterself.initWidgets()def initWidgets(self):Entry(relief=SUNKEN,font=('Courier New',24),width=25).pack(side=TOP, pady=10)#創建輸入組件放頂部p=Frame(self.master)#創建framep.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的子對象Buttonb.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 = masterself.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_colorself.label['fg'] = 'black' if grayness > 125 else 'white' my_app=App()#bind from tkinter import * class App:def __init__(self, master):self.master = masterself.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('<Button-1>',self.one)self.bn.bind('<B2-Motion>',self.b2_motion)self.bn.bind('<Double-3>',self.double)self.bn.bind('<Motion>',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 = masterself.initWidgets()self.flag = 0def 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('<Button-1>', self.click)def click(self, event):if(event.widget['text'] != '='):self.show['text'] = self.show['text'] + event.widget['text']self.flag = 0elif(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 = masterself.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 = masterself.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 = masterself.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 = bmself.label['compound'] = Noneself.label.pack()f=ttk.Frame(self.master)# 創建Frame容器,用于裝多個Radiobuttonf.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就是說每個單選按鈕都綁定這個變量,變量值就是按鈕valueRadiobutton(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 = masterself.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 = masterself.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 = 1for book in books:ttk.Radiobutton(self.master,text=book,variable=self.intVar,command=self.change,value=i).pack(anchor=W)i += 1def 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 = masterself.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 = masterself.initWidgets()def initWidgets(self):#第一個frametopF = 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("<Double-1>", 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滾動條#第二個framef = 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/shiftttk.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 = masterself.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']#framef = 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 = masterself.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()#第一個framef = 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)#第一個framef = 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 HORIZONTALdef 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 = masterself.initWidgets()def initWidgets(self):self.scale=ttk.LabeledScale(self.master,from_=-100,to=100,compound=BOTTOM)#設置顯示數值在下方self.scale.value = -20self.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 = masterself.initWidgets()def initWidgets(self):lf = ttk.Labelframe(self.master, text='請選擇',padding=20)lf.pack(fill=BOTH, expand=YES, padx=10, pady=10)i = 0self.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 = masterself.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,insertpwindow.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 = masterself.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()#然后建個有標簽的framelf = 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 = 0self.intVar = IntVar()for direct in self.directions:Radiobutton(lf,text=direct,value=i,command=self.change,variable=self.intVar).pack(side=LEFT)i += 1def 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 = masterself.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 = masterself.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 = masterself.initWidgets()def initWidgets(self):#先弄個大frametopF = 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 = 0self.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 += 1self.iconVar.set(0)#大frame下設按鈕選擇lf2 = ttk.Labelframe(topF, text='請選擇按鈕類型')lf2.pack(side=LEFT,fill=BOTH, expand=YES, padx=10, pady=5)i = 0self.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 += 1self.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 = masterself.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 = masterself.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 = masterself.initWidgets()def initWidgets(self):#主界面就是一個textself.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('<Button-3>',self.popup)self.text.bind('<Up>', self.keyup)#右鍵一級菜單是m1與m2self.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 <KeyPress event state=Mod1|0x40000 keysym=Up keycode=38 x=149 y=261> 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','<Button-1>', first)# 為指定圖形項的左鍵單擊事件綁定處理函數 cv.tag_bind('r1','<Button-1>', second, add=True)# add為True是添加,否則是替代 cv.focus_set()#讓畫布得到焦點,才可以響應按鍵事件 cv.bind('<Left>',move_left) root.mainloop() #第十二章:文件IO #PurePath自動轉PureWindowsPath from pathlib import * print(type(PurePath('setup.py'))) # <class 'pathlib.PureWindowsPath'>,自動轉為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 = tagprint('類構造器: %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 = Nonedef step(self, value):if self.min_len is None : # 如果self.min_len還未賦值,直接將當前value賦值給self.min_linself.min_len = valuereturnif len(self.min_len) > len(value):# 找到一個長度更短的value,用value代替self.min_lenself.min_len = valuedef 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 0elif st1[1: -1] > st2[1: -1]:return 1else: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)的結構,數據類型,表之間的鏈接和約束等初始化工作上,他們大多在建立表時使用,不需要commitDML(data manipulation language): 它們是SELECT、UPDATE、INSERT、DELETE,就象它的名字一樣,這4條命令是用來對數據庫里的數據進行操作的語言,需要commitDCL(Data Control Language): 是數據庫控制功能。是用來設置或更改數據庫用戶或角色權限的語句,包括(grant,deny,revoke等)語句。在默認狀態下,只有sysadmin,dbcreator,db_owner或db_securityadmin等人員才有權力執行DCLTCL - 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 = 0def 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_noself._balance = balanceself.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_amountprint(threading.current_thread().name+"取錢"+str(draw_amount)+" 賬戶余額"+str(self._balance)+'\n',end='')self._flag = False# 將標識賬戶是否已有存款的旗標設為Falseself.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_amountprint(threading.current_thread().name+"存款"+str(deposit_amount)+" 賬戶余額"+str(self._balance)+'\n',end='')self._flag = True# 將表示賬戶是否已有存款的旗標設為Trueself.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 = 0for i in range(max):print(threading.current_thread().name + ' ' + str(i)+'\n',end='')my_sum += ireturn 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 = 0for i in range(max):print(threading.current_thread().name + ' ' + str(i)+'\n',end='')my_sum += ireturn 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 = 0for i in range(max):print(threading.current_thread().name + ' ' + str(i)+'\n',end='')my_sum += ireturn 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 += iexcept:mydata.x = iprint('%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)#timerfrom 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, countcount += 1if 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 = maxsuper().__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 = 0for i in range(max):print(i)#老樣子,子進程不能輸出到控制臺my_sum += ireturn 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()# 創建進程通信的Queuep = 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讀取數據 Pythonp.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或HREFif 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':breakprint(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':breaks.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:breakprint(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 #讀到空就breakprint(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 blockelse:# 如果該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保存代表客戶端的socketconn.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 readyif 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':breaks.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='1064789374@qq.com'#定義發件人地址 password='lllchhbtzygrbfbb'#定義登錄郵箱的密碼,但這里是授權碼 to_addr='15521108978@163.com'#定義收件人地址 #二、連接登陸 #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('老婆我愛你!'+'<img src="cid:'+pic_id[1:-1]+'">','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 = '1064789374@qq.com' 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 = 1if 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 += 1with open(os.path.join('.', filename), 'wb') as fp: # 將附件寫入的本地文件fp.write(part.get_payload(decode=True)) conn.quit() # 退出服務器,相當于發送POP 3的quit命令

?

?

?

?

?

?

?

?

?下面是聊天室程序

??

服務端:```pythonimport asyncore,asynchat # 導入兩包class ChatServer(asyncore.dispatcher): # 服務器類def __init__(self,port): # 構造函數asyncore.dispatcher.__init__(self) # 父類初始化(不寫會默認調用,但重寫了就要顯式用父類才調用)self.create_socket() # 創建socketself.set_reuse_addr() # 地址重用self.bind(('127.0.0.1',port)) # 綁定self.listen(5) # 偵聽,最大有五個連接等待被接入self.users={} # 創建用戶列表self.main_room=ChatRoom(self) # 主房間是聊天房間(為何放在server類這?因僅1服務器也僅1房間)def handle_accepted(self,sock,addr): # 處理用戶的接入print('socket:',sock,'addr:',addr) # 打印socket與addrChatSession(self,sock) # 創建一個聊天會話類,把self(下面的server)與socket傳過去class ChatSession(asynchat.async_chat): # 聊天會話類,負責與客戶端通訊def __init__(self,server,sock): # 構造函數asynchat.async_chat.__init__(self,sock) # 父類的構造函數就是顯式調用self.server=server # 復合類(把上面的類傳下來了)self.set_terminator(b'\n') # 數據結束標志self.data=[] # 接受客戶端的接口數據self.name=None # 保存用戶名字self.enter(LoginRoom(self.server)) # 變登陸狀態def enter(self,room): # 從當前房間移除自身,然后添加到指定房間try: # 嘗試cur=self.room # 取出當前狀態except AttributeError: # 沒有的話pass # 跳過else: # 否則,就是有當前狀態roomcur.remove(self) # 就移除self.room=room # 把新狀態更新為傳入的狀態(上面剛創建LoginRoom就存到這)room.add(self) # 新狀態增加我def collect_incoming_data(self, data): # 收集接口出現數據self.data.append(data.decode()) # 數據添加def found_terminator(self): # 找到了結束符line=''.join(self.data) # 將消息拼接成字符串self.data=[] # 把接口數據清空self.room.handle(self,line.encode()) # 處理接收的指令def handle_closed(self): # 關閉話柄asynchat.async_chat.handle_closed(self) # 父類結束方法class Room: # 狀態類def handle(self,session,line): # 處理line=line.decode() # 解碼if not line.strip(): # 空命令return # 返回parts=line.split(' ',1) # 切2份如login abc, say hello, 或無參的logout, lookcmd=parts[0] # 讀出下標為0的字段try: # 嘗試line=parts[1].strip() # 獲取下標為1的字段except IndexError: # 下標錯誤line='' # 指令為空method=getattr(self,'do_'+cmd,None) # 獲取'do_'+cmd的方法method(session,line) # 調用這個方法def __init__(self,server): # 構造函數self.server=server # 服務器成員屬性self.sessions=[] # 會話集合def add(self,session): # 添加會話(可看到基類方法的作用是子類重寫后可調用,避免重復寫)self.sessions.append(session) # 往會話群里加會話def remove(self,session): # 移除會話(五)self.sessions.remove(session) # 從會話群里減會話(六)def broadcast(self,line): # 廣播for session in self.sessions: # 逐個會話讀出來session.push(line) # 發送內容def do_logout(self,session,line): # 登出(一)self.remove(session) # 從當前狀態移出會話(二)del self.server.users[session.name] # 服務器的用戶列表移除用戶名字(八)class ChatRoom(Room): # 正在聊天的客戶(成員有服務器與會話集合)def add(self,session): # 當前狀態添加會話session.push(b'login success') # 發送login successself.broadcast((session.name+' has entered the room. \n').encode()) # 廣播self.server.users[session.name]=session # 用戶字典添加用戶名-會話鍵值對Room.add(self,session) # 狀態添加會話def remove(self,session): # 移除會話(三)Room.remove(self,session) # 狀態移除(四)self.broadcast((session.name+' has left the room.\n').encode()) # 廣播 (七)def do_say(self,session,line): # 發送信息self.broadcast((session.name+':'+line+'\n').encode()) # 廣播def do_look(self,session,line): # 查在線用戶session.push(b'Online Users:\n') # 發送Online Users:\nfor user in self.sessions: # 遍歷會話列表session.push((user.name+'\n').encode()) # 發送會話中的用戶名class LoginRoom(Room): # 正在登陸的用戶def add(self,session): # 增加Room.add(self,session) # 調用父類的添加(下面do_login末句enter會把self.room指向的對象改掉,則會話級別的LoginRoom由于不再有引用(或者說指針)指向他而被釋放,服務器級別的ChatRoom是永遠只有一個且不被釋放,這就是為什么要在ChatServer中初始化ChatRoom為main_room然后在LoginRoom中傳入self.server.main_room了)session.push(b'Connect Success') # 發送信息def do_login(self,session,line): # 登陸功能name=line.strip() # 取出指令if not name: # 如果用戶名為空session.push(b'Username empty') # 發送Username emptyelif name in self.server.users: # 如果名字已在服務器用戶名列表session.push(b'Username exists') # 發送Username existselse: # 否則session.name=name # 賦值session.enter(self.server.main_room) # 進入新的狀態(就是聊天狀態)if __name__=='__main__': # 主函數print('server will run on 127.0.0.1:6666') # 提示ChatServer(6666) # 聊天服務器asyncore.loop() # 循環檢查```客戶端:```pythonimport PySimpleGUI as sgimport telnetlibdef login(conn):is_login=Falselayout=[[sg.Text('登陸Python聊天室')],[sg.Text('請輸入您的用戶名:'),sg.InputText(key='-username-'),sg.Button('進入聊天室')]]window=sg.Window('Python聊天室',layout)while True:event,values=window.read() # 讀出窗口里面的事件if event=='進入聊天室': # 登入事件username=values['-username-'].strip() # 取出'-username-'控件的值if username: # 用戶名非空try: # 嘗試打開連接conn.open('127.0.0.1',6666,timeout=10) # 打開except: # 否則sg.popup('連接失敗,請檢查服務器設置') # 提示break # 跳出resp=conn.read_some() # 讀回響應if resp!=b'Connect Success': # 如果不是連接成功sg.popup('連接失敗,請檢查服務器設置') # 彈窗提示 break # 跳出conn.write(('login '+username+'\n').encode()) # 發送登陸指令resp=conn.read_some() # 讀回響應if resp==b'Username exists': # 如果收到Username existssg.popup('用戶名已存在') # 彈窗提示失敗else: # 否則sg.popup('登陸成功') # 彈窗提示成功is_login=True # 改變標記break # 跳出else: # 否則(用戶名為空)sg.popup('請輸入用戶名') # 彈窗提示失敗if event in (None,'Cancel'): # 退出事件break # 跳出循環window.close() # 關窗del window # 刪窗if is_login: # 判登陸標記chat(conn,username) # 是就彈下一個窗def chat(conn,username):layout=[[sg.Text('聊天窗口('+username+')')],[sg.Multiline(disabled=True,size=(80,20),key='-chathistory-')],[sg.InputText(size=(70,5),key='-message-'),sg.Button('發送信息')],[sg.Button('查詢在線用戶'),sg.Button('退出聊天室')]]window=sg.Window('Python聊天室',layout) # 建窗while True: # 循環event,values=window.read(timeout=10) # 讀窗口信息(含接收到的信息)if values: # 值非空history_msg=values['-chathistory-'] # 讀出對話聊天記錄框字段值result=conn.read_very_eager().decode() # 讀服務器發過來的所有消息if result.strip(): # 去掉result兩邊窗白非空(那就是服務器有信息傳入)if 'Online' in result: # 出現Onlinesg.popup('當前在線用戶',result) # 彈出顯示else: # 否則window['-chathistory-'].update(history_msg+'\n'+result.strip()) # 更新聊天對話窗口內容if event in (None,'退出聊天室'): # 點擊x或按退出 break # 跳出循環elif event.strip()=='發送信息': # 點擊發送信息send(conn,'say',values['-message-']) # 發送window['-message-'].update('') # 清空編輯框elif event=='查詢在線用戶': # 點擊查詢在線用戶send(conn,type='look') # 發送 conn.write(b'logout\n') # 發送指令conn.close() # 關閉連接window.close() # 關窗del window # 刪窗def send(conn,type=None,msg=None): # 發if type=='say': # 說conn.write(('say '+msg +'\n').encode()) # 發elif type=='look': # 查conn.write(b'look\n') # 發if __name__=='__main__': # 主函數conn=telnetlib.Telnet() # 創建連接login(conn) # 調用函數``````markdownpython原生socket編程存在哪些問題一、在整個通信過程中,有很多不同的事件,這些事件需要我們自己處理,如果沒有處理則極容易產生異常二、必須使用多線程/多進程方式處理多個socket客戶端的連接,而多線程在高并發場景下極容易發生C10K問題(C10指單機連接數過萬)·解決方案:IO多路復用。使用一個線程,通過記錄IO流的狀態來同時管理多個IO流,當其中任何一個IO流的狀態發生改變,比如客戶端發送了消息過來變成為可讀狀態,則再來通知該線程進行處理。通過這種可以大大提高服務器的吞吐能力,這種方式特別適合像socket網絡編程這種IO密集型應用(如果是計算密集型則的確需要多個線程)。網絡編程中幾個常見的易錯概念:并發:一個時間段內有幾個程序在同一個CPU上運行,但任意時刻只有一個程序在CPU上運行,這種情景叫并發并行:任意時刻點上,有多個程序同時運行在多個CPU上,所以最大并行數跟CPU的核心數相同同步與異步關注的是消息通信機制,關心被調用方的行為同步:代碼在調用IO操作時,必須等待IO操作完成才返回的調用方式異步:代碼在調用IO操作時,不必等待IO操作完成就返回的調用方式,計算完了再返回一次結果阻塞和非阻塞關注的是程序在等待調用結果時的狀態,也就是調用方的狀態阻塞:調用方當前線程被掛起,等結果回到了再激活非阻塞:調用方線程不會被掛起,而是立即返回做其他事情,過幾分鐘偶爾check一下有沒有返回結果總結:同步阻塞,同步非阻塞,異步阻塞,異步非阻塞asyncore框架概念asyncore模塊是Python自帶的一個原生模塊,提供簡單的API以實現異步socket通信,并且為我們提供了異步socket服務器端和客戶端的基礎架構在使用asyncore框架時,我們需要注意兩個東西:一、全局函數loop:創建asyncore事件循環,在事件循環中調用底層的select方法來檢測特定網絡信道,如果信道對應的socket對象狀態發生改變,則自動產生一個高層次的事件信息,然后針對該信息調用相應的回調方法進行處理。二、基類dispatcher:一個底層的socket類的封裝對象,編程中繼承于dispatchero在或其子類,dispatchero在里面已經定義好了socket通信中的各種事件,我們只需要重寫特定的事件即可在該事件發生時實現自動回調處理。為什么作為socket server的時候,服務器端的連接會自動斷開?因為socket連接是用完即斷,所以為了保持通信服務端必須在socket連接建立好后立即創建一個新的dispatcher實例來保存這個socket連接對象,否則socket連接會被服務器端自動斷開補充handle_accept是服務端接收信息b' ' 表示這是一個 bytes 對象asyncore聊天室實戰主要知識點:asyncore作為服務器端的主要用法async_chat模塊的使用pySimpleGUI界面框架telnetlib作為客戶端socket模塊如何設計一個聊天室的應用?必要條件:服務器端,多客戶端必要約束:數據傳輸協議——以換行符為消息分隔符原理:服務器監聽消息來源,客戶端連接服務器并發送消息到服務器async_chat模塊介紹:是dispatcher這個類的抽象子類,定義了一些專門用于數據傳輸方面的方法,非常有利于實現數據傳輸主要方法:collect_incoming_data:接收數據found_terminator:當輸入數據流符合由set_terminator設置的終止條件時被調用set_terminator:設置終止條件push:向數據傳輸隊列壓入要傳輸的數據···
#第十六章:文檔測試 #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.age9>>> u.say('i love python')'fkjava說: i love python''''def __init__(self, name, age):self.name = nameself.name = 'fkit' # ②、故意寫錯的self.age = agedef say(self, content):return self.name + '說: ' + content if __name__=='__main__':import doctestdoctest.testmod()#單元測試邏輯覆蓋 def test (a, b, m):if a > 10 and b == 0:m = a + bif 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 / ar2 = (-b - (b * b - 4 * a * c) ** 0.5) / 2 / areturn 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.8self.assertTrue(one_equation(4 , 10) == -2.5 , .00001)# 斷言該方程求解應該為-2.5self.assertTrue(one_equation(4 , -27) == 27 / 4)# 斷言該方程求解應該為27/4with self.assertRaises(ValueError):one_equation(0 , 9)# 斷言當a == 0時的情況,斷言引發ValueErrordef 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時的情況,斷言引發ValueErrorwith 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, # 突出顯示Pythoncolors=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 += 1elif '晴' in description:sunnys += 1elif '云' in description:cloudys += 1elif '雨' in description:rainys += 1else: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年GDPprint(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

總結

以上是生活随笔為你收集整理的疯狂python讲义学习笔记——中十章完结的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。