文件处理
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。
- with open('1.txt','r') as f1, open('2.txt','w')as f2: #连续打开两个 with 上下文管理,必须待__enter__(),__exit__(), 容易处理异常
#如果在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
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参数传递采用的肯定是“传对象引用”的方式。这种方式相当于传值和传引用的一种综合。如果函数收到的是一个可变对象(比如字典或者列表)的引用,就能修改对象的原始值--相当于通过“传引用”来传递对象。如果函数收到的是一个不可变对象(比如数字、字符或者元组)的引用,就不能直接修改原始对象--相当于通过“传值'来传递对象。