【python第四日】 文件处理 生成器 迭代器

文件处理

input()

所有输入都是字符串,想变成整数可以这样map(int,str.split())

文件处理

打开方式

  •  file=open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)

file:文件名称;
mode:制定了文件打开的方式,函数提供了如下方式,其中,'rt'为默认方式。
'r'       open for reading (default)——只读,默认方式
'w'       open for writing, truncating the file first——写入,会覆盖源文件内容
'x'       create a new file and open it for writing——创建新文件,并写入内容,如果文件已存在,将会报错:FileExistsError
'a'       open for writing, appending to the end of the file if it exists——写入,如果文件有内容,则在末尾追加写入
'b'       binary mode——二进制模式
't'       text mode (default)——文本模式,默认方式
'+'       open a disk file for updating (reading and writing)——更新磁盘文件,读写
'U'       universal newline mode (deprecated)——在paython3中已经弃用
buffering:用于设置缓存策略
在二进制模式下,使用0来切换缓冲;在文本模式下,通过1表示行缓冲(固定大小的缓冲区)。
在不给参数的时候,二进制文件的缓冲区大小由底层设备决定,可以通过io.DEFAULT_BUFFER_SIZE获取,通常为4096或8192字节
文本文件则采用行缓冲。
encoding:编码或者解码方式。默认编码方式依赖平台,如果需要特殊设置,可以参考codecs模块,获取编码列表。
errors:可选,并且不能用于二进制模式,指定了编码错误的处理方式,可以通过codecs.Codec获得编码错误字符串
newline:换行控制,参数有:None,' ',' ',' '。
输入时,如果参数为None,那么行结束的标志可以是:' ',' ',' '任意一个,并且三个控制符都首先会被转化为:' ',然后才会被调用;
如果参数为'',所有的通用的换行结束标志都可以用,但是行结束标识符返回调用不会被编码。
输出时,如果参数为None,那么行结束的标志可以是:' '被转换为系统默认的分隔符;如果是'',' '则不会被编码。

 windows默认换行符' ',linux默认是' ',如果不设置newline,都会转为' ',但是tell()的时候会变计算' '2个字节,当newline=‘’时候,‘ ’是不转换的,就是这个东西
closefd:false:文件关闭时,底层文件描述符仍然为打开状态,这是不被允许的,所以,需要设置为ture
opener:可以通过调用*opener*方式,使用自定义的开启器。底层文件描述符是通过调用*opener*或者*file*, *flags*获得的。
*opener*必须返回一个打开的文件描述。将os.open作为*opener*的结果,在功能上,类似于通过None。

#如果在do_something的时候,程序错误就是报出异常错误,但是如果再__exit__()时候return True 则不会报出异常
class Test:

    def __enter__(self):
        print('__enter__() is call!')
        return self

    def dosomething(self):
        x = 1/0
        print('dosomethong!')


    def __exit__(self, exc_type, exc_value, traceback):
        print('__exit__() is call!')
        print(f'type:{exc_type}')
        print(f'value:{exc_value}')
        print(f'trace:{traceback}')
        print('__exit()__ is call!')
        return True

with Test() as sample:
    sample.dosomething()


输出如下:

__enter__() is call!
__exit__() is call!
type:<class 'ZeroDivisionError'>
value:division by zero
trace:<traceback object at 0x034715A8>
__exit()__ is call!

 json.dump()后面会讲

read readline readlines

如果文件很小,read()一次性读取最方便
如果不能确定文件大小,反复调用read(size)比较保险
如果是配置文件,调用readlines()最方便;redlines()读取大文件会比较占内存
如果是大文件,调用redline()最方便
如果是特殊需求输出某个文件的n行,调用linecache模块
 
read()  按照字符读取,seek 是按照字节读取,但是如果文件是按照二进制读取就会按照字节read()

seek tell truncate

 1. seek有三种移动方式0,1,2,其中1和2必须在b模式下进行,但无论哪种模式,都是以bytes为单位移动的

 2. truncate是截断文件,所以文件的打开方式必须可写,但是不能用w或w+等方式打开,因为那样直接清空文件了,所以truncate要在r+或a或a+等模式下测试效果

  3.seek有三种移动方式0,1,2,其中1和2必须在b模式下进行,但无论哪种模式,都是以bytes为单位移动的

文件方法

f.close()      关闭文件对象f,并将属性f.close设置为True;
f.closed       文件已关闭,则返回True;
f.encoding     byte与str之间进行转换时使用的编码;
f.fileno()     返回底层文件的文件描述符;
f.flush()      清空文件对象;
f.isatty()     如果文件对象与控制台关联,就返回True;
f.mode         文件对象打开时使用的模式;
f.name         文件对象f的文件名(如果有);
f.newlines     文本文件f中的换行字符串的类型;
f.__next__()   返回文件对象f的下一行;
f.peek(n)      返回n个字节,而不移动文件指针的位置;
f.readable()   如果f已经打开等待读取,则返回True;
f.read(count)  文件对象f中读取至多count个字节,如果没有指定count,就读取从当前文件指针直到最后的每个字节,以二进制模式时,返回bytes对象;以文件模式时,返回str对象;
f.readinto(ba) 将至多len(ba)个字节读入到bytearray ba中,并返回读入字节数,如果在文件结尾,就为0;
f.readline(count)      读取下一行,包括
;
f.readlines(sizehint)     读入到文件结尾之前的所有行,并以列表形式返回;
f.seek(offset,whence)     如果没有给定whence,或其为os.SEEK_SET,就按给定的offset移动文件指针...
f.seekable()    如果f支持随机存取,就返回True;
f.tell()      返回当前指针位置;
f.truncate(size)截取文件到当前文件指针所在位置,如果给定size,就到size大小处;
f.writable()    如果f是为写操作而打开的,就返回True;
f.write(s)      将文本对象s写入到文件;
f.writelines(seq)将对象序列写入到文件;

文件处理方式

  •   重命名  
    os.rename(current_file_name, new_file_name)
  • 删除文件
    os.remove(file_name)
  • python目录
    os.mkdir("newdir")  创建目录
    os.chdir("newdir")   改变当前目录
    os.getcwd()   获取当前工作目录
    os.rmdir('dirname')  删除目录

迭代器

  • 凡是可作用于 next() 函数的对象都是 Iterator 类型
  • 迭代器都可以用于for map filter,sorted,max.min循环,但是列表,元组和字符串,字典,zip对象,集合都可以用于for循环,但是不是迭代对象,他是通过__iter__变成可迭代对象

列表生成式

  三元运算符    值 if x>5 else 否定值      比如   5 if x>5 else 6

        值 for i in range(10)  if i >5    比如  i for i in range(10) 

  矩阵     [[0 for col in range(cols)] for row in range(rows)]

  列表表达式  在三元运算符外面加上【】,[i*5  for i in range(10) ]

生成器

生成器是迭代器的一种

  • 函数生成式   待yield    相当于return     x=yield 等待别人到这里需要别人send

yield:调用foo()得到一个生成器,此时函数内的代码不会执行,当调用next()时,函数被触发执行,碰到yield程序挂起,然后调用g.send(数值),程序从挂起时开始执行,此时数值先给了yield,然后yield赋值给x,程序继续执行,直到碰到yield程序挂起,并将yield后的结果返回给函数。如果此时再次调用next(g)那么yield的值就是None然后赋值给x,程序继续执行,这个效果和g.send(None)一样。So,send的作用有两个:

1.将值传递给yield,然后yield赋值给x。
2.触发函数的执行,直到遇到yield停止,yield后的值返回给函数,此步的操作和next()一样。

def test():
    for i in range(4):
        yield  i
a  = test()
t = (i for i in a)
t1 = (i for i in t)
print(list(t1))   #生成器只能用一次,谁用完就没有了
print(list(t))
#输出如下
[0, 1, 2, 3]
[]
def test():
    print("test要开始了")
    yield  1
    print("test运行1处")
    x = yield 2
    print("test 运行:",x)
    yield 4

a = test()
print("第一次:",a.__next__())
print("第二次:",a.__next__()) 
print("第三次:",a.send("10"))  #说明停止在yield 2处,等待下一次接收,

#输出如下
test要开始了
第一次: 1
test运行1处
第二次: 2
test 运行: 10
第三次: 4
#消费者 生产者模型
MAX_NUM = 30 SINGLE_MAX=10 s_cons={} jishu={} def consumer(name, num): start = 0 while start <= num : baozi = yield print(f'{name}正在吃第{start+1}个{baozi}') start = start + 1 # del s_cons[name] def producer(): baozizonghe=["素馅包子", "肉馅包子", "豆沙包子"] start = 1 while start < MAX_NUM: baozixuanzhe = random.choice(baozizonghe) for i in s_cons: time.sleep(0.5) if jishu[i] == 0: continue print(jishu) s_cons[i].send(baozixuanzhe) print(f" {i}的倒数第{jishu[i]}个{baozixuanzhe}送完") jishu[i] = jishu[i] - 1 break else: print(f"做了一个{baozixuanzhe},但是没人吃") print("包子卖完了") cons_num = 3 for i in range(cons_num): con_name = "顾客%d" %(i + 1) num_max = random.randint(1,SINGLE_MAX) print(f"{con_name}最大获取{num_max}") jishu[con_name] = num_max tmp = consumer(con_name, num_max) #这一步并不执行任何语句,只是创建一个生成器,需要__next__才到yield地方 tmp.__next__() s_cons[con_name] = tmp print(s_cons) producer()
  • 生成器表达式   用()放在三元运算符外面
a = (x ** 2 for x in range(1, 10))
b = (x * x for x in range(1, 11) if x % 2 == 0)
c = (m + n for m in 'ABC' for n in '123')
L = (k + '=' + v for k, v in d.items())   

字符串转字典

str ="{'one':1,'two':2}" dic = eval(str) print(type(dic),dic) #<class 'dict'> {'one': 1, 'two': 2}

代码区 

结论:python不允许程序员选择采用传值还是传引用。Python参数传递采用的肯定是“传对象引用”的方式。这种方式相当于传值和传引用的一种综合。如果函数收到的是一个可变对象(比如字典或者列表)的引用,就能修改对象的原始值--相当于通过“传引用”来传递对象。如果函数收到的是一个不可变对象(比如数字、字符或者元组)的引用,就不能直接修改原始对象--相当于通过“传值'来传递对象。

支付宝     
您的资助是我最大的动力!
金额随意,欢迎来赏!
微信

如果,您希望更容易地发现我的新博客,不妨点击一下绿色通道的关注我

如果,想给予我更多的鼓励,求打       付款后有任何问题请给我留言!!!

------------------------------------------------------------------------------------------
作者:【周sir】
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
原文地址:https://www.cnblogs.com/zhouguanglu/p/10168784.html