练习
DVD管理系统的解析
1.利用ElementTree来解析dvd管理系统信息
输入一个dvd管理代码文件
-
- #usr/bin/puthon
- #-*-coding:utf-8-*-
- from 基础 import dvd_read as dr
- class DVD:
- def __init__(self):
- self.name = ""
- self.price = ""
- self.state = ""
- # if len(args)>0:
- # self.name=args[0]
- # self.price=args[1]
- # self.state=args[3]
- if '__main__'==__name__:
- # xiyouji=DVD('西游记',100,0)#0代表未借出 1 代表已借出
- # sanguo=DVD('三国',100,1)
- # shuihuzhuan=DVD('水浒传',100,0)
- # dvds={xiyouji.name:xiyouji,sanguo.name:sanguo,shuihuzhuan.name:shuihuzhuan}
- dvds=dr.getdvds()
- while True:
- print('1.查询所有DVD')
- print('2.增加DVD')
- print('3.借出DVD')
- print('4.归还DVD')
- print('5.退出')
- num=int(input('请输入数字:'))
- if num==1:
- print('名称\t价格\t状态')
- for key in dvds.keys():
- if dvds.get(key).state.__eq__('0'):
- print(key+' \t'+str(dvds.get(key).price)+' \t'+'未借出')
- else:
- print(key+' \t'+str(dvds.get(key).price)+' \t'+'已借出')
- elif num==2:
- name=input('请输入新的DVD:')
- while name in dvds.keys():
- name=input('此DVD已存在 请重新输入名字:')
- price=int(input('请输入新DVD价格:'))
- new_dvd=DVD()
- new_dvd.name=name
- new_dvd.price=price
- new_dvd.state=0
- dvds[name]=new_dvd
- print('增加成功')
- elif num==3:
- name = input('请输入你所需要的DVD:')
- while name not in dvds.keys():
- name=input('此DVD不存在 请重新输入名字:')
-
- if dvds.get(name).state==1:
- print(name,'已借出')
- else:
- dvds.get(name).state=1
- print('借出成功')
- elif num==4:
- name = input('请输入你所归还的DVD:')
- while name not in dvds.keys():
- name=input('此DVD不存在,请重新输入DVD名字')
- if dvds.get(name).state==0:
- print('此DVD未借出')
- else:
- dvds.get(name).state=0
- date=int(input('请输入借书日期'))
- print('扫一扫付款',int(date*int(dvds.get(name).price)),'元')
- print('归还成功')
- elif num==5:
- print('欢迎使用')
- break
输入一个dvd.xml文件
- <span style="font-size:16px;"><strong>
- <?xml version="1.0" encoding="UTF-8" ?>
- <dvds>
- <dvd>
- <name>西游记</name>
- <price>200</price>
- <state>1</state>#0代表未借出 1代表已借出
-
- </dvd>
- <dvd>
- <name>水浒传</name>
- <price>250</price>
- <state>0</state>
- </dvd>
- <dvd>
- <name>三国</name>
- <price>300</price>
- <state>1</state>
- </dvd>
- </dvds></strong></span>
通过ElementTree解析xml文件
- <span style="font-size:16px;"><strong>
- import xml.etree.ElementTree as ET
-
- from 基础.DVD import DVD
-
- tree=ET.parse('dvd.xml')
- root=tree.getroot()
- dvds={}
- def getdvds():
- for dvd in root:
- n_dvd = DVD()
- for ele in dvd:
-
- if ele.tag=='name':
- n_dvd.name=ele.text
- elif ele.tag=='price':
- n_dvd.price=ele.text
- elif ele.tag=='state':
- n_dvd.state=ele.text
- dvds[n_dvd.name]=n_dvd
- return dvds</strong></span>
2.利用sax解析器来处理dvd管理系统信息
通过sax来解析xml文件
- <span style="font-size:16px;"><strong>
- import xml.sax
- class dvdHandler(xml.sax.ContentHandler):
- def __init__(self):
- self.CurrentData = ""
- self.name = ""
- self.price = ""
- self.state = ""
-
- def startElement(self, tag, attributes):
- self.CurrentData = tag
-
- def endElement(self, tag):
- if self.CurrentData == "name":
- print ("name:", self.name)
- elif self.CurrentData == "price":
- print ("price:", self.price)
- elif self.CurrentData == "state":
- print ("state:", self.state)
- self.CurrentData = ""
- def characters(self, content):#
- if self.CurrentData == "name":
- self.name = content
- elif self.CurrentData == "price":
- self.price = content
- elif self.CurrentData == "state":
- self.state = content
- if ( __name__ == "__main__"):
- parser = xml.sax.make_parser()
- parser.setFeature(xml.sax.handler.feature_namespaces, 0)
- Handler = dvdHandler()
- parser.setContentHandler( Handler )
- parser.parse("dvd.xml")</strong></span>
执行命令得
- <span style="font-size:16px;"><strong>
- name: 西游记
- price: 200
- state: 1
- name: 水浒传
- price: 250
- state: 0
- name: 三国
- price: 300
- state: 1</strong></span>
二、CSV文件
Python处理csv文件
CSV(Comma-Separated Values)及逗号隔开值,可以用Excek打开查看.由于是纯文本,任何编辑器也都可打开.与Excel文件不同,CSV文件中:
<1>值没有类型,所有值都是字符串
<2>不能指定字体颜色等样式
<3>不能指定单元格的宽高,不能合并单元格
<4>没有多个工作表
<5>不能嵌入图像图表
在CSV文件中,以(,)作为分隔符,分割两个单元格.像这样a,,c表示单元格a和单元格c之间有个空白格.以此类推,不是每个逗号都表示单元格之间的分界.所以即使CSV是纯文本文件,也坚持使用专门的模块进行处理.Python内置了CSV模块
我们常常需要读取和处理CSV文件的数据.处理CSV数据的一个最常用的方法就是把它转换为一个字典列表
DictReader类将会自动的使用CSV文件的第一行作为字典的key属性名.DictReader类返回一个将会遍历csv文件所有行的对象.
这个文件对象通过open()函数产生.我们提供了open()两个函数第一个是csv文件名,第二个是模式.在这个例子中,'rU'有两个意思,'r'表示只读模式打开文件.'U'表示我们将会接受通用换行符:'\n' '\r' '\r\n'(注:\n: 回车,光标在下一行 \r:换行,光标在上一行 \r\n回车加换行)
例:
准备一个csv文件
- <span style="font-size:16px;"><strong>
- 1,2,3,4,5
- a,b,c,d,e
- 11,22,33,44,55</strong></span>
读取csv文件
- <span style="font-size:16px;"><strong>
- import csv
- #调用csv文件的读取方法csv.DictReader()
- Dict=csv.DictReader(open('文件.csv','rU'))#可迭代
- print(type(Dict))
- print(Dict)
- print([x for x in Dict])</strong></span>
执行命令得
- <span style="font-size:16px;"><strong>
- <class 'csv.DictReader'>
- <csv.DictReader object at 0x057902B0>
- [OrderedDict([('1', 'a'), ('2', 'b'), ('3', 'c'), ('4', 'd'), ('5', 'e')]), OrderedDict([('1', '11'), ('2', '22'), ('3', '33'), ('4', '44'), ('5', '55')])]
- </strong></span>
当需要读取key或者values时
- <span style="font-size:16px;"><strong>
- import csv
- Dict=csv.DictReader(open('文件.csv','rU'))#可迭代
- print([d.keys() for d in Dict])
- # print([c.values() for c in Dict])</strong></span>
执行命令得
- <span style="font-size:16px;"><strong>
- [odict_keys(['1', '2', '3', '4', '5']), odict_keys(['1', '2', '3', '4', '5'])]
- #[odict_values(['a', 'b', 'c', 'd', 'e']), odict_values(['11', '22', '33', '44', '55'])]
- </strong></span>
三、进程和线程
1.概念
进程是什么?线程是什么?二者之间有什么区别和联系?
<1>进程是资源分配的基本单位
<2>线程是CPU独立运行和独立调度的基本单位
两者的联系:进程和线程都是操作系统所运行的程序运行的基本单位
区别:
<1>进程具有独立的空间地址,一个进程崩溃后,在保护模式下不会对其他进程产生影响
<2>线程是一个进程的不同执行路径.线程有自己的堆栈和全局变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉
多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差些,对于一些要求同时进行并且有要共享某些变量的并发操作,只能用线程,不能用进程
什么是多线程?
多线程:是指从软件或者硬件上实现多个线程的并发技术,如在一个进程中同时运行了多个线程,用来完成不同的工作,则称之为'多线程,多个线程交替占用CPU资源,而非真正的并行执行'
多线程的好处:
<1>使用多线程可以把程序中占据时间长的任务放到后台去处理,如图片视频的下载
<2>发挥多核处理器的优势,并发执行让系统运行的更快更顺畅用户体验好
多线程的缺点:
<1>大量的线程降低代码的可读性
<2>更多的线程需要更多的储存空间
<3>当多个线程对同一个资源出现争夺时候要注意县城的安全问题
进程的特点:独立(内存独立,CPU使用独立)启动进程开销大(速率低),进程之间很难共享数据,和数据通信, 但数据安全性高.
线程的特点:依赖进程(内存共享,CPU使用独立)启动开销小,进程之间共享数据容易,方便通信,不安全
2.开始学习Python线程
调用:
Python2:thread
Python3:_thread
threading(功能比_thread更强大,推荐使用)
2.线程模块
Python通过两个标准库thread和threading提供对线程的支持,thread提供了低级别的,原始的线程以及一个简单的锁
threading模块提供的其他方法
方法 |
描述 |
threading.currentThread() |
返回当前的线程变量 |
threading.enumerate() |
返回一个包含正在运行的线程的list.正在运行指线程启动后,结束前,不包括启动前和终止后的线程 |
threading.activeCount() |
返回正在运行的线程数量,与len(threading.enumerate())有相同的结果. |
例:
-
- import threading
-
- print([x for x in range(9)])#创建一个线程
- thread=threading.current_thread()#返回获取当前线程变量
- thread.setName('主线程')#设置线程名字
- print('线程名字:',thread.getName())#获取当前线程名字
- new_th=threading.enumerate()#获取正在运行的线程
- print('正在运行的线程',new_th)
- print('正在运行的线程个数:',threading.active_count())#正在运行的线程个数
执行命令得
-
- [0, 1, 2, 3, 4, 5, 6, 7, 8]
- 线程名字: 主线程
- 正在运行的线程 [<_MainThread(主线程, started 12184)>]
- 正在运行的线程个数: 1
除了使用方法外,线程模块同样提供了Thread类来处理线程,Thread类提供了以下方法
方法 |
描述 |
run() |
用以表示线程活动的方法 |
start() |
启动线程活动 |
join([time]) |
等待至线程终止,这阻塞调用线程直至线程的join()方法 被调用终止,正常退出或者抛出未处理的异常或者是可选的超时发生 |
isAlive() |
返回线程是否活动的 |
getName() |
返回线程名 |
setName() |
设置线程名 |
线程的状态
Python中使用线程有两种方式:函数或者类来包装线成对像.
3.函数式:调用thread模块中的start_new_thread()函数来产生新线路.语法如下
thread.start_new_thread(function,args[,kwargs])
参数说明:
function--线程函数
args--传递给线程函数的参数,他必须是个tuple类型
kwargs--可选参数
注意:函数实现方式:线程必须依赖函数实现,不能单独运行.当函数结束,线程结束.所以如果想知道线程一直运行,就要想办法让程序不结束,比如在程序最后加一个input(),或死循环
-
- import threading,time
- def something(x):
- for i in range(1,x):
- print(i)
- time.sleep(0.2)
- threading._start_new_thread(something,(10,))#启动一个新的线程 括号里添加参数并且参数必须是元组
- input()
执行命令得
例:
时间线程
- <span style="font-size:16px;"><strong>
- import time,_thread
-
-
- # 为线程定义一个函数
- def print_time(threadName, delay):
- count = 0
- while count < 5:
- time.sleep(delay)
- count += 1
- print( "%s: %s" % (threadName, time.ctime(time.time())))
-
-
- # 创建两个线程
- try:
- _thread.start_new_thread(print_time, ("Thread-1", 2,))
- _thread.start_new_thread(print_time, ("Thread-2", 4,))
- except:
- print("Error: unable to start thread")
-
- while 1:
- pass</strong></span>
执行命令得
- <span style="font-size:16px;"><strong>
- Thread-1: Thu May 31 11:48:44 2018
- Thread-2: Thu May 31 11:48:46 2018
- Thread-1: Thu May 31 11:48:46 2018
- Thread-1: Thu May 31 11:48:48 2018
- Thread-2: Thu May 31 11:48:50 2018
- Thread-1: Thu May 31 11:48:50 2018
- Thread-1: Thu May 31 11:48:52 2018
- Thread-2: Thu May 31 11:48:54 2018
- Thread-2: Thu May 31 11:48:58 2018
- Thread-2: Thu May 31 11:49:02 2018</strong></span>
4.线程类
<1>继承threading.Thread
<2>写构造方法,且必须调用父类的构造方法
<3>重写父类run方法,会在start之后自动调用
<4>实现开始方法,如果重写了start()方法,一定要调用父类的start()
程序交替执行
- <span style="font-size:16px;"><strong>
- import threading,time
- class Mythread(threading.Thread):<span style="color:rgb(170,85,0);font-family:Menlo, Monaco, Consolas, 'Andale Mono', 'lucida console', 'Courier New', monospace;white-space:pre-wrap;background-color:rgb(255,255,255);">#继承父类threading.Thread</span>
- def __init__(self):
- threading.Thread.__init__(self)
- print('Mythread __init__()')
- def run(self):<span class="hl-code" style="border:0px;margin:0px;padding:0px;color:#808080;font-family:Menlo, Monaco, Consolas, 'Andale Mono', 'lucida console', 'Courier New', monospace;white-space:pre-wrap;"> </span><span class="hl-comment" style="border:0px;margin:0px;padding:0px;color:rgb(170,85,0);font-family:Menlo, Monaco, Consolas, 'Andale Mono', 'lucida console', 'Courier New', monospace;white-space:pre-wrap;">#把要执行的代码写到run函数里面 线程在创建后会直接运行run函数 </span>
- for i in range(3):
- print(self.getName(),i)
- time.sleep(1)#等待时间
- t1=Mythread()
- t2=Mythread()
- t1.start()
- t2.start()
- print('正在运行的线程个数:',threading.active_count())</strong></span>
执行命令得
- <span style="font-size:16px;"><strong>
- Mythread __init__()
- Mythread __init__()
- Thread-1 0
- Thread-2 0
- 正在运行的线程个数: 3
- Thread-1 1
- Thread-2 1
- Thread-1 2
- Thread-2 2</strong></span>
程序先后执行(并没有以线程格式去执行而是调用了run方法)
- <span style="font-size:16px;"><strong>
- import threading,time
- class Mythread(threading.Thread):
- def __init__(self):
- threading.Thread.__init__(self)
- print('Mythread __init__()')
- def run(self):
- for i in range(3):
- print(self.getName(),i)
- time.sleep(1)#等待时间
- t1=Mythread()
- t2=Mythread()
- t1.run()
- t2.run()
- print('正在运行的线程个数:',threading.active_count())
- </strong></span>
执行命令得
- <span style="font-size:16px;"><strong>
- Mythread __init__()
- Mythread __init__()
- Thread-1 0
- Thread-1 1
- Thread-1 2
- Thread-2 0
- Thread-2 1
- Thread-2 2
- 正在运行的线程个数: 1
- </strong></span>
join()#加入并阻断主线程的执行.即执行完才执行主线程,可以加时间,join(3)阻断3秒结束阻断
- <span style="font-size:16px;"><strong>
- import threading,time
- class Mythread(threading.Thread):
- def __init__(self):
- threading.Thread.__init__(self)
- print('Mythread __init__()')
- def run(self):
- for i in range(6):
- print(self.getName(),i)
- time.sleep(1)#等待时间
- t1=Mythread()
- t1.start()
- for i in range(6):
- print(threading.current_thread().getName(), i)
- time.sleep(1) # 等待时间
- if i ==2:
- # 哪个线程调用停止哪个
- t1.join()</strong></span>
执行命令得
- <span style="font-size:16px;"><strong>
- Mythread __init__()
- MainThread 0
- Thread-1 0
- MainThread 1
- Thread-1 1
- MainThread 2
- Thread-1 2
- Thread-1 3
- Thread-1 4
- Thread-1 5
- MainThread 3
- MainThread 4
- MainThread 5</strong></span>
练习
数据的共享
抢票系统
第一种方法:(此方法只有一条主线程在执行)
- <span style="font-size:16px;"><strong>
- import threading,time
- num=10
- count=0
- def qiangpiao(x):
- global num,count
- while True:
- if num==0:
- return#结束当前方法
- num=num-1
- count=count+1
- print('{0}抢到了 第{1}张 剩余{2}'.format(x,count,num))
- time.sleep(0.2)
- threading._start_new_thread(qiangpiao,('张三',))
- threading._start_new_thread(qiangpiao,('李四',))
- threading._start_new_thread(qiangpiao,('王五',))
- input()
- </strong></span>
执行命令得
- <span style="font-size:16px;"><strong>
- 王五抢到了 第1张 剩余9
- 张三抢到了 第2张 剩余8
- 李四抢到了 第3张 剩余7
- 李四抢到了 第4张 剩余6
- 王五抢到了 第6张 剩余4
- 张三抢到了 第5张 剩余5
- 李四抢到了 第7张 剩余3
- 张三抢到了 第8张 剩余2
- 王五抢到了 第9张 剩余1
- 张三抢到了 第10张 剩余0</strong></span>
第二种方法:(多线程同时交替执行)
- <span style="font-size:16px;"><strong>
- import threading,time
- num=20
- count=0
- class qiangpiao(threading.Thread):
- def __init__(self,name):
- threading.Thread.__init__(self)
- self.setName(name)
- def run(self):
- global num,count
- while True:
- if num==0:
- return
- num=num-1
- count=count+1
- print('{0}抢到了第{1}张 剩余{2}张'.format(self.getName(),count,num))
- time.sleep(0.2)
- if __name__=='__main__':
- huangniu=qiangpiao('黄牛')
- phone=qiangpiao('手机')
- chuangkou=qiangpiao('窗口')
- huangniu.start()
- phone.start()
- chuangkou.start()
- print('正在运行的线程个数:', threading.active_count())
- </strong></span>
执行命令得
- <span style="font-size:16px;"><strong>
- 黄牛抢到了第1张 剩余19张
- 手机抢到了第2张 剩余18张
- 窗口抢到了第3张 剩余17张
- 正在运行的线程个数: 4
- 手机抢到了第4张 剩余16张
- 黄牛抢到了第5张 剩余15张
- 窗口抢到了第6张 剩余14张
- 手机抢到了第7张 剩余13张
- 黄牛抢到了第8张 剩余12张
- 窗口抢到了第9张 剩余11张
- 手机抢到了第10张 剩余10张
- 窗口抢到了第11张 剩余9张
- 黄牛抢到了第12张 剩余8张
- 手机抢到了第13张 剩余7张
- 黄牛抢到了第14张 剩余6张
- 窗口抢到了第15张 剩余5张
- 手机抢到了第16张 剩余4张
- 黄牛抢到了第17张 剩余3张
- 窗口抢到了第18张 剩余2张
- 手机抢到了第19张 剩余1张
- 黄牛抢到了第20张 剩余0张</strong></span>
5.线程同步
如果多个线程共同对某个数据修改,则可能出现不可预料的结果,为了保证数据的正确性,需要对多个线程进行同步所以有了锁的概念,我们通过锁来使多个线程任务更加安全(效率低)
lock=threading.Lock()
cond=threading.Condition(lock=lock)
由于并发的问题,需要加锁:
锁当然有锁定和未锁定两种状态,当一个线程需要访问共享数据时,必须要先获得锁定,如果已经有别的线程获得锁定,那么久进入暂停状态,等别的线程把锁释放后,再进行操作
Condition:更精确的控制锁,提供了四个方法,
上锁(acquire())
等待(wait())
解锁(release())
唤醒(notify(),notify_all())
(加锁后让资源更加安全不会出现)
例:
遍历出1-10 和 30-20 当第一个线程得到3时加锁等待第二个线程完成后继续遍历
- <span style="font-size:16px;"><strong>import threading,time
- class Thread1(threading.Thread):
- def run(self):
- for i in range(1,11):
- if i==3:
- cond.acquire()#某个线程获得资源就加上锁
- cond.wait() #等待
- cond.release()#某个线程完成了处理就释放锁
- print(i)
- time.sleep(1)
-
-
- class Thread2(threading.Thread):
- def run(self):
- for i in range(30,19,-1):
- print(i)
- time.sleep(1)
- cond.acquire()
- cond.notify()
- cond.release()
-
- lock = threading.Lock()#创建一把锁
- cond = threading.Condition(lock=lock)#管理一把锁
- t1 = Thread1()
- t2 = Thread2()
- t1.start()
- t2.start</strong></span>()
-
- 1
- 30
- 29
- 2
- 28
- 27
- 26
- 25
- 24
- 23
- 22
- 21
- 20
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
练习
蒸包子吃包子循环系统
-
- import threading,time
- zhenglong=[]#共享数据--蒸笼
- #创建两把锁
- # 一把蒸包子三的锁 由伙夫掌管
- #另外一把吃包子的锁 由吃货掌管
- zheng_lock=threading.Lock()
- chi_lock=threading.Lock()
- zheng_Cond=threading.Condition(lock=zheng_lock)
- chi_Cond=threading.Condition(lock=chi_lock)
-
- class huofu(threading.Thread):
- def __init__(self,name):
- threading.Thread.__init__(self)
- self.setName(name)
- def run(self):
- while True:
- chi_Cond.acquire()# 被谁唤醒
- if len(zhenglong)==0:
- #开始蒸包子
- for i in range(1,11):
- zhenglong.append(i)
- time.sleep(0.1)
- print('正在蒸第{0}个包子'.format(i))
- print('包子蒸完了 唤醒吃货')
- chi_Cond.notify_all()#唤醒吃货们
- chi_Cond.release()#唤醒了伙夫 他就解锁
- #伙夫进入休眠
- zheng_Cond.acquire()
- zheng_Cond.wait()
- zheng_Cond.release()
- class chihuo(threading.Thread):
- def __init__(self,name):
- threading.Thread.__init__(self)
- self.setName(name)
- def run(self):
- while True:
- chi_Cond.acquire()#同一时刻只有一个吃货在获取吃包子的资源
- global zhenglong
- if len(zhenglong)==0:
- #开始呼唤伙夫 只交叫一次 蒸包子 我和其他吃货一同进入休眠
- zheng_Cond.acquire()#锁定叫醒伙夫的线程
- zheng_Cond.notify()#唤醒
- zheng_Cond.release()#释放
- chi_Cond.wait()#这个吃货进入休眠
- else:
- baozi=zhenglong.pop()
- print('{0}吃了第{1}个包子 剩余{2}个包子'.format(self.getName(),baozi,len(zhenglong)))
- time.sleep(0.1)
- chi_Cond.release()
- w=huofu('伙夫')
- xiaoming=chihuo('小明')
- xiaopang=chihuo('小胖')
- w.start()
- xiaoming.start()
- xiaopang.start()
- input()
执行命令得
-
- 正在蒸第1个包子
- 正在蒸第2个包子
- 正在蒸第3个包子
- 正在蒸第4个包子
- 正在蒸第5个包子
- 正在蒸第6个包子
- 正在蒸第7个包子
- 正在蒸第8个包子
- 正在蒸第9个包子
- 正在蒸第10个包子
- 包子蒸完了 唤醒吃货
- 小明吃了第10个包子 剩余9个包子
- 小胖吃了第9个包子 剩余8个包子
- 小胖吃了第8个包子 剩余7个包子
- 小明吃了第7个包子 剩余6个包子
- 小明吃了第6个包子 剩余5个包子
- 小胖吃了第5个包子 剩余4个包子
- 小胖吃了第4个包子 剩余3个包子
- 小胖吃了第3个包子 剩余2个包子
- 小明吃了第2个包子 剩余1个包子
- 小明吃了第1个包子 剩余0个包子
- 正在蒸第1个包子
- 正在蒸第2个包子
- .....