主要从数据(记录)的表示出发,讲述数据(记录)存储(内存、pickle、shelves),包括:格式化、持久化、图形化(GUI,tkinter)、控制台交互、OOP;最后还从Web界面引出CGI基础;
#定义一个列表
bob = ['Bob Smith',42,30000,'software']
sue = ['Sue Jones',45,40000,'hardware']
#获取姓名、薪水
print(bob[0],sue[2])
#获取姓,split()分割,不传参数及是以空格分割;举例:bob[0].split("b")---->结果:['Bo',' Smith'],注意空格在第二个元素中;
print(bob[0].split())#结果:['Bob', 'Smith']
print(bob[0].split()[-1])
#给sue加薪25%
sue[2] *=1.25
print(sue)#['Sue Jones', 45, 50000.0, 'hardware']
#-----------------------------------------------------------------------------------------------------------
#创建一个新列表的将bob与sue存储在一起;
people = [bob, sue]
for person in people:
print(person)
#使用索引层层取值
print(people[1][0])
#打印姓氏,每个人涨工资25%
for person in people:
print(person[0].split()[0])
person[2] *=1.25
#检测薪资:
for person in people:print(person[2])
#收集薪资^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#列表解析:
pays =[ person[2] for person in people ]
print(pays)
#map:map(function, iterable, ...);function -- 函数;iterable -- 一个或多个序列;
pays =map((lambda x: x[2]), people)#返回迭代器对象
#使用关键字=索引号,将列表中的字段关联
NAME,AGE,PAY = range(3)
bob = ['Bob Smith',42,30000]
print(bob[NAME])
#但是上面的也不是长久之计,数据变了,这个字段名称就得维护;下面提供更优de方式:
bob = [['name','Bob Smith'],['age',42],['pay',10000]]
sue = [['name','Sue Jones'],['age',29],['pay',20000]]
people = [bob, sue]
#上面也没有从根本上解决问题,还是要通过索引来取值;只是知道其字段意思;
for person in people:
print(person[0][1],person[2][1],sep=":")#name:pay
#更优de方式,使用元组赋值来拆开名/值对:
for person in people:
for (name,value) in person :
if name =='name':print(value)#寻找特定字段,这里举例name;还可以age、pay
#将上面得元组赋值拆分名/值对de方式封装成函数:
def field(record,label):
for(fname,fvalue) in record:
if fname == label:
msg =label+":"+str(fvalue)
return msg
for person in people:
print(field(person,"age"))
#使用字典:
bob = {'name':'Bob Smith', 'age':42, 'pay':30000, 'job': 'dev'}
sue = {'name':'Sue Jnoes', 'age':56, 'pay':50000, 'job': 'pre'}
print(bob['name'])
#其他建立字典的方法:dict(key=value,……)
bob = dict(name='Bob Smith',age=42,pay=30000,job='dev')
sue = dict(name='Sue Jnoes',age=35,pay=35000,job='pre')
print(bob)
print(sue)
#一次一个字段填写字典;
sue={}
sue['name']='Sue Jones'
sue['age']=45
sue['pay']=5600
sue['job']='pre'
print(sue)
#使用zip函数将key/value列表链在一起:
names=['name','age','pay','job']
values=['Sue Jones',45,56000,'pre']
sue=dict(zip(names,values))#{'name': 'Sue Jones', 'age': 45, 'pay': 56000, 'job': 'pre'}
print(list(zip(names,values)))#[('name', 'Sue Jones'), ('age', 45), ('pay', 56000), ('job', 'pre')]
print(sue)
#使用dict的fromkeys来初始化所有key的value,只不过这些value都是一个值(可用于初始化字典):
data_keys=('name','age','job','pay')
record = dict.fromkeys(data_keys,'?')
print(record)#{'name': '?', 'age': '?', 'job': '?', 'pay': '?'}
#88888888888888888888888888888888888888888888888888888888888888888888888888888888
#同样列表与字典结合;
bob = {'name':'Bob Smith', 'age':42, 'pay':30000, 'job': 'dev'}
sue = {'name':'Sue Jnoes', 'age':56, 'pay':50000, 'job': 'pre'}
people = [bob,sue]
for person in people:
print(person['name'],person['age'],person['pay'],sep=":")
#列表解析
names=[person['name'] for person in people]
print(names)
#map
print(list(map((lambda x:x['name']),people)))
#sum
print(sum(person['pay'] for person in people))
#奇妙的是:列表解析和按需生成器表达式,可以达到sql的效果:
thing = [rec['name'] for rec in people if rec['age'] >=45]
print(thing)#['Sue Jnoes']
thing1=[(rec['pay']**2 if rec['age']>45 else rec['pay']) for rec in people]
print(thing1)
#字典在python中是常见的对象,使用一般的方式更新、访问:
for person in people:
print(person['name'].split()[0])
person['pay'] *=1.25
t=[person['pay'] for person in people]
print(t)
###################################################################################
#嵌套结构
bob2={
'name':{'first':'Bob','last':'Smith'},
'age':42,
'job':['software','writing'],
'pay':(40000,50000)
}
#上面的通过索引两层就可访问数据;
#全部的工作:
for job in bob2['job']:print(job)
bob2['job'].append('tester')#添加新工作
print(bob2)
#################################################################################
#字典的字典
bob = dict(name='Bob Smith',age=42,pay=30000,job='dev')
sue = dict(name='Sue Jnoes',age=35,pay=35000,job='pre')
db = {}
db["bob"] = bob
db["sue"] = sue
print(db)#{'bob': {'name': 'Bob Smith', 'age': 42, 'pay': 30000, 'job': 'dev'}, 'sue': {'name': 'Sue Jnoes', 'age': 35, 'pay': 35000, 'job': 'pre'}}
import pprint
pprint.pprint(db)#打印出更易于清晰的格式
#{'bob': {'age': 42, 'job': 'dev', 'name': 'Bob Smith', 'pay': 30000},
# 'sue': {'age': 35, 'job': 'pre', 'name': 'Sue Jnoes', 'pay': 35000}}
#访问字典的字典:
for key in db:
print(key,'=>',db[key]['name'])
#要么使用迭代字典的值集合来直接访问:
for record in db.values():print(record)
#使用迭代字典的值集合来直接访问记录:
x=[db[key]['name'] for key in db]
print(x)
#遇上等效:
x=[rec['name'] for rec in db.values()]
print(x)
#类似sql的查询:
tt=[rec['name'] for rec in db.values() if rec['age'] >=5]
print(tt)
目前为止,上面所见到的对象都是暂时的;他们只是保存在内存当中;并会随着我们退出python或者创建他们的python程序而烟消云散;为了使其永久化,它们需要保存在某种类型的文件中;
在程序运行时保存数据的一种方法---》是把所有数据以格式化的方式写入一个简单的文本文件中,要用时,在取出来重构
class WSave:
def __init__(self,db,dbfilename = 'people-file'):
self.db = db
self.dbfilename = dbfilename
self.ENDDB = 'enddb'
self.ENDREC = 'endrec'
self.RECSEP = '=>'
def storeDB(self):
'''
将数据库格式化保存为普通文件
:return:
'''
with open(self.dbfilename,'w') as dbfile:
for key in self.db:
print(key,file=dbfile)
for (key,value) in self.db[key].items():
#下面的方式==等效于==》》print(key+"=>"+repr(value),file=dbfile)
dbfile.write(key+"=>"+repr(value)+"\n")#repr() 函数将对象转化为供解释器读取的形式
# print(key + self.RECSEP + repr(value), file=dbfile)
print(self.ENDREC, file=dbfile)
print(self.ENDDB, file=dbfile)
def loadDbase(self):
'''
将文件中的数据解析,重构db
:return:
'''
dbfile = open(self.dbfilename)
import sys
sys.stdin = dbfile#sys.stdin:标准输入
db = {}
key = input()
while key != self.ENDDB:
rec = {}
field = input()
while field !=self.ENDREC:
name, value = field.split(self.RECSEP)
rec[name] = eval(value)#函数用来执行一个字符串表达式,并返回表达式的值:eval( '3 * 7' ),21
field = input()
db[key] = rec
key = input()
return db
if __name__ == '__main__':
from initdata import db
# dbpath=r'D:\pythonProject\project_hack\testDB'
writeDB = WSave(db)
# writeDB.storeDB()
db=writeDB.loadDbase()
import pprint
pprint.pprint(db)
for key in db:
print(key,"=>\n",db[key])
print(db['sue']['name'])
#pickle包的初衷:可以将任意类型的python数据转化成可以保存在文件中的格式
#pickle模块将内存中的python对象转化成序列化的字节流;这是一种可以写入任何类似文件对象的字节串;;;
# pickle模块也可以根据序列化的字节流重新构建原来内存中的对象:转换成原来的对象;
# pickle模块取代了专有的数据格式;pickle感觉像XML的表达方式;但是,它是Python专用的方式并且比较容易编写代码
from initdata import db#最初创建的数据
import pickle
dbfile = open('people-file', 'wb')#二进制写
#已字节流写入文件,而非字符串
pickle.dump(db,dbfile)
dbfile.close()
dbfile1 = open('people-file', 'rb')#二进制读
#字节流重新构建原来内存中的对象
db=pickle.load(dbfile1)
dbfile1.close()
import pprint
pprint.pprint(db)
#上面的例子都有一个缺陷,每更新一条记录,就需要读出和重新写入整个数据库;
# 我们可以通过一条记录到一个普通文件的方式来改进;
from initdata import bob,sue,tom #最初创建的数据
import pickle
#每个文件一个名称记录一条数据;
for (key, record) in [('bob',bob),('tom',tom),('sue',sue)]:
recfile = open(key+'.pkl','wb')
pickle.dump(record,recfile)
recfile.close()
import glob#glob该方法返回所有匹配的文件路径列表
for filename in glob.glob('*.pkl'):
recfile = open(filename,'rb')
record = pickle.load(recfile)
print(filename,'=>\n',record)
#修改一条记录后,在写入
dbfile = open('sue.pkl','rb')
v = pickle.load(dbfile)
v['pay'] *= 1.10
dbfile.close()
new_dbf= open('sue.pkl','wb')
pickle.dump(v,new_dbf)
new_dbf.close()
#更高级的库:shelves;用键来访问记录;shelve系统自动分隔存储记录,并且只获取和更新访问和修改的记录;
# shelve使用起来很像一堆只存储一条记录的pickle 文件;但更容易编辑;
from initdata import bob,sue
import shelve
db = shelve.open('people-shelve')
db['bob'] = bob
db['sue'] = sue
db.close()
#执行上面的代码后,出现了people-shelve.bak;people-shelve.dat;people-shelve.dir目录;
# 千万不要删除(它们就是你的数据库)
#shelve就像一个持久化的字典。
db = shelve.open('people-shelve')
for key in db:
print(key,'=>\n',db[key])
db.close()
#修改(在内存中修改,在重新对键进行赋值来更新shelve)、添加;
db = shelve.open('people-shelve')
sue = db['sue']
sue['pay'] *=1.50#内存中修改后
db['sue'] = sue#重新对键进行赋值
from initdata import tom
db['tom'] = tom#添加新记录
db.close()
#OOP:python一切皆对象;这是一种程序设计的思路:Structure(结构)、Encapsulation(封装)、Customiztion(定制)
#Structure(结构):类既提供了程序单元将逻辑与数据合并在单独的包中,又提供了一个层级结构;使得代码更容易组织从而防止代码冗余;
# Encapsulation(封装):我们可以自由的更改方法的实现而不会破坏调用者的代码;
# Customiztion(定制):通过编写新的子类就可以扩展和定制类,同时不会更改或破坏已工作的代码;
#1.类记录数据---》对象的属性取代了字典的key;
class Person:
def __init__(self,name,age,pay = 0, job = None):
self.name = name
self.age = age
self.pay = pay
self.job = job
if __name__ == '__main__':
bob = Person('Bob Smith',42,30000,'software')
sue = Person('Sue Jones',45,40000,'harware')
print(bob.name,sue.pay)
#2.类添加行为(函数)---》数据与行为的结合,函数(或者说方法)提供了解释和更新数据的逻辑(称之为面向对象,因为它们总是处理对象的数据/属性)
class Person:
def __init__(self,name,age,pay=0,job=None):
self.name=name
self.age=age
self.pay=pay
self.job=job
def lastName(self):
return self.name.split()[-1]
def giveRaise(self,percent):
self.pay *= (1.0+percent)
0000000000000000000000000000000000000000000000000000000000000
#3.类的继承--》继承后子类包含了父类所有的属性、和函数;子类可以重新覆盖父类中的函数
class Manager(Person):
def giveRaise(self,percent,bonus= 0.1):
self.pay *=(1.0+bonus+percent)
#4.格式化显示:当对象需要整体的打印输出时,该方法可以返回对象的格式化字符串
class Person:
def __init__(self, name, age, pay=0, job=None):
self.name = name
self.age = age
self.pay = pay
self.job = job
def lastName(self):
return self.name.split()[-1]
def giveRaise(self, percent):
self.pay *= (1.0 + percent)
#格式化显示:当对象需要整体的打印输出时,该方法可以返回对象的格式化字符串;
def __str__(self):
return "<%s ==> %s>" % (self.__class__.__name__, [self.name, self.age, self.pay, self.job])
#增强方法:和上面重写函数相比,这种方式不但可以降低代码冗余,而且实践中尤其利于启动父类的构造函数
class Manager1(Person):
def giveRaise(self,percent,bonus= 0.1):
Person.giveRaise(self,percent+bonus)
tom = Manager1('Tom iThing',25,150000)
print(tom)# ['Tom iThing', 25, 150000, None]>
#5.#自定义构造函数
class Person:
def __init__(self, name, age, pay=0, job=None):
self.name = name
self.age = age
self.pay = pay
self.job = job
def lastName(self):
return self.name.split()[-1]
def giveRaise(self, percent):
self.pay *= (1.0 + percent)
def __str__(self):
return "<%s ==> %s>" % (self.__class__.__name__, [self.name, self.age, self.pay, self.job])
class Manger(Person):
# 自定义构造函数
def __init__(self, name, age, pay):
Person.__init__(self, name, age, pay,'manager')#这里使用的技巧就是明确调用父类的构造函数,job直接写死manager;
def giveRaise(self,percent,bonus=0.1):
Person.giveRaise(self,percent+bonus)
#下面看多态:
bob = Person('Bob Smith', 44)
sue = Person('Sue Joner',23,12000,'hardware')
tom = Manger('iThing Tom',29,150000)
for obj in (bob,sue,tom):
obj.giveRaise(.10)
print(obj)
#上面运行的结果是:
# ['Bob Smith', 44, 0.0, None]>
# ['Sue Joner', 23, 13200.000000000002, 'hardware']>
# ['iThing Tom', 29, 180000.0, 'manager']>
#6#增添持久化
#为了更明了,我将上面的两个class分别写在两个py文件中
from Person import Person
from Manager import Manager
import shelve
bob = Person('Bob Smith', 44)
sue = Person('Sue Joner',23,12000,'hardware')
tom = Manager('iThing Tom',29,1500000)
db = shelve.open('class-shelve')
db['bob'] = bob
db['sue'] = sue
db['tom'] = tom
db.close()
#上面将对象存储在了shelve数据库中;下面取出来,看看可以使用对象的函数不?
db0 = shelve.open('class-shelve')
for person in db0:
print(db0[person])
bob=db0['bob']
print(bob.lastName())
tom=db0['tom']
tom.giveRaise(.20)
db0['tom']=tom
db0.close()
print(tom)
#shelve的控制台界面
import shelve
fieldnames = ('name','age','job','pay')
maxfield = max(len(f) for f in fieldnames)
db = shelve.open('class-shelve')
while True:
key = input('\nKey? => ')
if not key:break
try:
record = db[key]
except:
print('没有找到对应的数据记录')
else:
for field in fieldnames:
print(field.ljust(maxfield),'=>',getattr(record,field))
tkinter包含超过20多种控件,多种获取用户的输入的方式,多行文本、画布、下拉菜单、单选和复选、滚动条等
访问寻求更多:https://www.runoob.com/python/python-gui-tkinter.html
from test4 import MyGui
from tkinter import *
from tkinter.messagebox import showinfo
#Tk():创建应用程序主窗口
#Frame():创建控件容器,可依附在窗口中
#TopLevel():创建弹出式窗口
#获取用户的输入:
from tkinter import *
from tkinter.messagebox import showinfo
def reply(msg):
showinfo(title='Reply',message='Hello %s' % msg)
top = Tk()
top.title('Echo')#改变窗口title
top.iconbitmap('expand.ico')#改变图标
Label(top,text='Enter your name:').pack(side=TOP)
#使用Entry控件获取用户输入并在弹出对话框中加以显示
ent = Entry(top)
ent.pack(side=TOP)
#这里使用lambda来延迟对reply函数的调用;使输入数据得以传入,这是tkinter常用的编程模式;
# 如果不使用lamdba,reply方法在按钮创建时就会被调用,而不是等到按钮单击时;
btn = Button(top,text='Submit',command=(lambda :reply(ent.get())))
btn.pack(side=LEFT)
top.mainloop()
from tkinter import *
from tkinter.messagebox import showerror
import shelve
shelvename = 'class-shelve'
fieldnames = ('name','age','job','pay')
def makeWidgets():
global entries
window =Tk()
window.title('People Shelve')
form = Frame(window)
form.pack()
entries = {}
for (ix,label) in enumerate(('key',)+fieldnames):
lab = Label(form,text=label)
ent = Entry(form)
lab.grid(row=ix,column=0)#网格
ent.grid(row=ix,column=1)
entries[label] = ent
Button(window, text="Fetch",command=fetchRecord).pack(side=LEFT)
Button(window,text="Update",command=updateRecord).pack(side=LEFT)
Button(window,text="Quit",command=window.quit).pack(side=RIGHT)
return window
def fetchRecord():
key = entries['key'].get()
try:
record = db[key]#使用键获取数据,并在GUI中展示
except:
showerror(title='Error',message='No such key!')
else:
for field in fieldnames:
entries[field].delete(0,END)
entries[field].insert(0,repr(getattr(record,field)))
def updateRecord():
key = entries['key'].get()
if key in db:
record = db[key]
else:
from Person import Person
record = Person(name="?",age="?")
for field in fieldnames:
setattr(record,field,eval(entries[field].get()))
db[key] = record
if __name__ == '__main__':
import shelve
db =shelve.open(shelvename)
window = makeWidgets()
window.mainloop()
db.close()
from tkinter import *
import random
fontsize = 30
colors = ['red','green','blue','yellow','orange','cyan','purple']
def onSpam():
popup = Toplevel()
color = random.choice(colors)
Label(popup,text='Popup',bg='black',fg=color).pack(fill=BOTH)
mainLabel.config(fg=color,bg=random.choice(colors))
def onFlip():
mainLabel.config(fg=random.choice(colors))
main.after(250, onFlip)
def onGrow():
global fontsize
fontsize +=2
mainLabel.config(font=('arial',fontsize,'italic'))
main.after(100,onGrow)
main = Tk()
mainLabel = Label(main,text='Fun Gui!',relief=RAISED)
mainLabel.config(font=('arial',fontsize,'italic'),fg='cyan',bg='navy')
mainLabel.pack(side=TOP,expand=YES,fill=BOTH)
Button(main,text='spam',command=onSpam).pack(fill=X)
Button(main,text='flip',command=onFlip).pack(fill=X)
Button(main,text='grow',command=onGrow).pack(fill=X)
Button(main,text='关闭',command=main.quit).pack(fill=X)
main.mainloop()
浏览器--服务器--后端逻辑;
特别注意:目录结构
#-*-coding:utf-8-*-
import os,sys
from http.server import HTTPServer,CGIHTTPRequestHandler
webdir = "."#存放HTML和cgi脚本文件夹的所在
port = 80
os.chdir(webdir)#在HTML根目录中运行
srvraddr =('',port)#我的主机和端口
srvrobj = HTTPServer(srvraddr,CGIHTTPRequestHandler)
srvrobj.serve_forever()#永久守护进程运行