17复习
map
l=[1,2,3,4,5]
print(list(map(str,l))) #相当于for循环依次处理 ['1', '2', '3', '4', '5']
reduce #以一定的作用合并到一起输出是一个
from functools import reduce
l=[1,2,3,4,5]
# reduce(func,l)
res=reduce(lambda x,y:x+y,l,3)
print(res)
filter 判断f t 然后是否保存
name=['alex_sb','linhaifeng']
res=filter(lambda x:not x.endswith('sb'),name)
print(res)
print(list(res))
文件操作
文件路径 只写 编码格式
f=open('test11.py','w',encoding='utf-8') #获取文件句柄f
f.write('1111\n') #w模式是光标的来回移动 再次打开写入的话会整个文件都覆盖
f.write('1111\n') #r+模式只是覆盖光标到的位置,其他如果没有修改则不会修改
f.write('1111\n')
f.close()
f=open('test11.py','a',encoding='utf-8')
f.write('这是a模式的内容') #a模式是追加模式,都是在最后写
f.close()
f=open('test11.py','r+',encoding='utf-8')
f.write('hello') #r+模式只是覆盖光标到的位置,其他如果没有修改则不会修改
更改前
111
2222
333333
更改后
hello
2222
333333
http://www.cnblogs.com/linhaifeng/articles/5984922.html#_label1
文件处理b模式
# f=open('test11.py','rb',encoding='utf-8') #报错,binary模式的方式不能指定编码
f=open('test11.py','rb') # 内存内部是二进制编码存储,b的方式不能指定编码
data=f.read()
# #'字符串'---------编码encode---------》bytes
# #bytes---------解码decode---------》'字符串'
print(data) #b'hello\r\n2222\r\n333333\r\n\xe8\x8c\x83\xe5\xbe\xb7\xe8\x90\xa8'
print(data.decode('utf-8')) #以utf8解码显示
# hello
# 2222
# 333333
# 范德萨
# f.close()
f=open('test22.py','wb') #b的方式不能指定编码
f.write('12222\n') #报错,b方式 要的是bytes类型 而不是字符串类型
f.write(bytes('1111\n',encoding='utf-8')) #转换成bytes类型,字符串转换二进制一定要经过字符编码
f.write('杨件'.encode('utf-8')) #也可以用.encode()来完成以一定的编码方式转换成bytes
f=open('test22.py','ab') #b的方式不能指定编码 追加
# f.write('杨件'.encode('utf-8'))
二进制方式代表处理数据的方式,而不是最后显示的内容,
好处,1文件包括open函数默认是以t 文本的方式处理,
文本,视频 图片 这些都是用二进制进行处理,默认t文本方式处理不了了,只能用b
2. 二进制在不同操作系统中都能用
# open('a;ltxt','wt')
文件操作其他方法
f=open('a.txt','r+',encoding='gb2312') #r+光标位置覆盖,不是整个文件覆盖
# data=f.read()
# print(data)
f.write('你好')
暂时不需要吧
f=open('b.txt','r+',encoding='latin-1') #open打开默认系统编码,latin-1包含大多数编码解码,当不知道文件内编码方式或者一个文件有多种编码方式的时候
data=f.read()
print(data)
f.write('aaaaaaaaaaa') #不能写中文
# 还是乱码???
# ä½ å¥½fdsaf
# heé
f=open('b.txt','r',encoding='utf-8',newline='') #读取文件中真正的换行符号
f=open('b.txt','r+',encoding='utf-8',newline='') #newline=''读取文件中真正的换行符号
print(f.closed) #判断是否关
print(f.encoding) #读取编码方式
f.flush() #自动更新,将最近更改的文件保存到硬盘上,防止掉电失去文件内容
print(f.readlines()) #当有newline=' ,输出['你好fdsaf\r\n', 'he阀aaaaaaaaaaaaaaaaaaaaaa']
实际上windows下,回车是\r\n 但是没有写newline=''默认python多余做的一件事,统一转换成\n
print(f.tell()) # 如果没有newline='' 默认\r\n ,记得加上\r\n 的两个字节 一个中文用utf8需要3字节
f.readline()
print(f.tell())
f.seek(1) #控制光标的移动
print(f.tell())
print(f.readlines())
f.seek(3)
print(f.tell())
print(f.read())
data=f.read(1) #read 读的是字符,而不是字节
print(data)
f.truncate(10) #文件截取 开头到第10个位置 不能w+ 直接清空文件内容了
f.flush() #讲文件内容从内存刷到硬盘
f.closed #文件如果关闭则返回True
f.encoding #查看使用open打开文件的编码
f.tell() #查看文件处理当前的光标位置
#
f.seek(3) #从开头开始算,将光标移动到第三个字节
f.truncate(10) #从开头开始算,将文件只保留从0-10个字节的内容,文件必须以写方式打开,但是w和w+除外
f=open('d.txt','r',newline='')
data=f.readline().encode('utf-8')
print(data)
print(f.tell())
f=open('seek.txt','r',encoding='utf-8')
print(f.tell())
f.seek(10)
print(f.tell())
f.seek(3) #3字节 默认从文件开头算 是绝对位置
print(f.tell()) #打印从3字节后的内容
f=open('seek.txt','rb') #注意,seek寻找的是字节,要以b的方式操作,
# 如果默认模式0则不用指定b ,用1模式seek要指定b
print(f.tell())
f.seek(10,1)#1模式 ,代表相对上次光标的位置
print(f.tell())
f.seek(3,1)
print(f.tell())
seek2模式
f=open('seek.txt','rb')
print(f.tell())
f.seek(-5,2) #从文件末尾seek 倒序 要负着写
print(f.tell())
print(f.read()) #输出光标到最后的那些-5字节到0字节的 b'33\xe4\xbd\xa0' 实际字符串是 33你
print(f.tell())
f.seek(3,1)
print(f.tell())
read方法读的是字符
1. seek有三种移动方式0,1,2,其中1和2必须在b模式下进行,
但无论哪种模式,都是以字节bytes为单位移动的不是字符
读取文件最后一行
f=open('日志文件','rb')
data=f.readlines()
print(data[-1].decode('utf-8')) #2016/12/30 sb 干了件sb事情
f=open('日志文件','r',encoding='utf-8')
data=f.readlines()
print(data)
#['2016/12/25 alex 干了件25事情\n', '2016/12/26 alex 干但是11情\n', '2016/12/27 alex 干了件事情\n', '2016/12/28 alex 干了件事情\n', '2016/12/29 alex 干了件事情\n', '2016/12/30 sb 干了件sb事情\n']
print(data[-1]) #2016/12/30 sb 干了件sb事情
f=open('日志文件','rb')
for i in f.readlines(): #一行一行地全部读 f.readlines()这个是以列表形式,内是b字节方式显示每一行
print(i) #将文件一起都放到内存中,要的内存空间多
循环文件的推荐方式
for i in f: # 放一行到内存,如果不是需要的释放,再到下一条,直到得需要的 省内存
print(i)
for i in f: #得到句柄,并且这个占用内存少
offs=-10 # 大概估算一行的字节数
while True:
f.seek(offs,2)
data=f.readlines() #从当前位置到最后读成一个列表,每行一个内容
if len(data) > 1: # 得到的列表长度大于1个
print('文件的最后一行是%s' %(data[-1].decode('utf-8')))
break
offs*=2
迭代器和生成器
三 python中强大的for循环机制
for循环的本质:循环所有对象,全都是使用迭代器协议。
正本清源:
很多人会想,for循环的本质就是遵循迭代器协议去访问对象,那么for循环的对象肯定都是迭代器了啊,没错,那既然这样,for循环可以遍历(字符串,列表,元组,字典,集合,文件对象),那这些类型的数据肯定都是可迭代对象啊?但是,我他妈的为什么定义一个列表l=[1,2,3,4]没有l.next()方法,打脸么。
(字符串,列表,元组,字典,集合,文件对象)这些都不是可迭代对象,只不过在for循环式,调用了他们内部的__iter__方法,把他们变成了可迭代对象
然后for循环调用可迭代对象的__next__方法去取值,而且for循环会捕捉StopIteration异常,以终止迭
x='hello'
# print(dir(x)) #x可以执行的函数操作
iter_test=x.__iter__()
#
print(iter_test) #变成了可迭代对象,有_next_()方法
print(iter_test.__next__())
print(iter_test.__next__())
print(iter_test.__next__())
print(iter_test.__next__())
print(iter_test.__next__())
print(iter_test.__next__())
l=[1,2,3]
for i in l: #实际上此for循环是先执行 i_l=l.__iter_() ,然后执行 i_l.__next__() 并且自动终止,防止超出个数限制报异常
print(i)
index=0
while index < len(l):
print(l[index]) #索引取值 列表元祖 字符串这几个序列类型都可以 ;集合,字典,文件对象这些非序列类型不行
index+=1
for循环就是基于迭代器协议提供了一个统一的可以遍历所有对象的方法,
即在遍历之前,先调用对象的__iter__方法将其转换成一个迭代器,
然后使用迭代器协议去实现循环访问,这样所有的对象就都可以通过for循环来遍历了,
iter_l=l.__iter__() #遵循迭代器协议,转换生成可迭代对象
print(iter_l.__next__())
print(iter_l.__next__())
for i in l:
print(i)
s={1,2,3}
for i in s: #调用iter方法 变成可迭代对象
print(i)
iter_s=s.__iter__()
print(iter_s)
print(iter_s.__next__())
print(iter_s.__next__())
print(iter_s.__next__())
print(iter_s.__next__())
dic={'a':1,'b':2}
iter_d=dic.__iter__()
print(iter_d.__next__()) #a 打印的是key值,默认返回的是key
f=open('test.txt','r+') #文件
# # for i in f: #for循环要一行取一行,立马释放,减少内存使用
iter_f=f.__iter__()
# print(iter_f)
print(iter_f.__next__(),end='') #1111
print(iter_f.__next__(),end='') #2222
print(iter_f.__next__(),end='')
用while去模拟for循环做的事情
l=[1,2,3,4,5]
diedai_l=l.__iter__()
while True:
try:
print(diedai_l.__next__())
except StopIteration: #防止next导致的异常
print('迭代完毕了,循环终止了')
break
l=['die','erzi','sunzi','chongsunzi']
#
iter_l=l.__iter__()
print(iter_l) # 转换成迭代器形式,减少内存使用
print(iter_l.__next__())
print(iter_l.__next__())
print(iter_l.__next__())
print(iter_l.__next__())
print(iter_l.__next__())
print(next(iter_l)) #也可以,next()-就是调用--->iter_l.__next__()
生成器
什么是生成器?
可以理解为一种数据类型,这种数据类型自动实现了迭代器协议(其他的数据类型需要调用自己内置的__iter__方法),所以生成器就是可迭代对象
生成器分类及在python中的表现形式:(Python有两种不同的方式提供生成器)
1.生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行
2.生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表
def test():
yield 1
yield 2
yield 3 #可以返回多个
g=test()
print('来自函数',g) #来自函数
print(g.__next__())
print(g.__next__())
三元表达式
1 2 3 2,3是表达式 ,1是输出结果
name='alex'
name='linhaifeng'
res='SB' if name == 'alex' else '帅哥' #1 2 3 如果判断2 T 则返回1 ,F返回3 并且将结果给res
print(res)
列表解析
l=['鸡蛋%s' %i for i in range(10)] 但是 生成就是真实完整的列表,耗内存
egg_list=[]
for i in range(10):
egg_list.append('鸡蛋%s' %i)
print(egg_list)
等效
l=['鸡蛋%s' %i for i in range(10)] #1 '鸡蛋%s' %i; 2 for i in range(10)
l1=['鸡蛋%s' %i for i in range(10) if i > 5 ] #1 2 3 if i > 5
# l1=['鸡蛋%s' %i for i in range(10) if i > 5 else i] #没有四元表达式
l2=['鸡蛋%s' %i for i in range(10) if i < 5] #没有四元表达式
print(l) #['鸡蛋0', '鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4', '鸡蛋5', '鸡蛋6', '鸡蛋7', '鸡蛋8', '鸡蛋9']
print(l1) #['鸡蛋6', '鸡蛋7', '鸡蛋8', '鸡蛋9']
print(l2)
#
#生成器表达式
laomuji=('鸡蛋%s' %i for i in range(10)) #生成器表达式
print(laomuji) # at 0x00000000028D9150>生成器对象 不用_ _ 直接有_next_()
print(laomuji.__next__())
print(laomuji.__next__())
print(next(laomuji))
print(next(laomuji))
print(next(laomuji))
print(next(laomuji))
print(next(laomuji))
print(next(laomuji))
print(next(laomuji))
print(next(laomuji))
# print(next(laomuji))
l=[1,2,3,34]
map(func,l)
print(sum(l)) #先生成l列表在内存中,再执行sum 如果列表大会占用过多内存
print(sum())
print(sum(i for i in range(10000000000000))) #for 生成器表达式 占用一条后直接释放,节省内存 i for i in range(10000000000000)三元函数1 2