文件操作到函数
他来了,他来了,他憋着尿来了
各位好,我来了,今天不困,很奇怪,破天荒,感觉有大事要发生了,果然,晚上就有朋友说我博客写得好,给我打赏了十块钱。
好了,开心的进入打气环节,今天的憨憨们有没有给自己打气呀?
今日洗脑金句: 加油,对抗赖床不容易,python给你爆发力!
文件的高级应用
一、可读and可写
- r+t: 可读、可写 (没用)
- w+t: 可写、可读 (没用 too)
- a+t: 可追加、可读 (没用 too too)
不是,没用的东西为什么要造出来呢。
原来是因为有弊端
来我们看看
我们知道读写文件的时候的写法open方法里面的第二个参数是写r 或者 w 或者 a,各是什么用的如果你们忘记了,先毒打自己一顿,然后去看我上一篇博客。
但是,其实第二个参数是要写rt 或者wt 或者at的,因为这样就是以文本的形式读取文件,把t改成b的话就是以二进制的形式读取文件,通常用来读取图片音频之类的。
所以,不写的话就是默认t,以文本的方式读取文件。
来讲讲为什么这些没用吧
因为有延迟。
如果你已既可读又可写的形式打开了一个文件,然后往里头写了点东西,然后又读,有可能会出现你没有读取到你刚写进去的东西,为什么呢,因为时间延迟啊,这个时候你并不知道发生了什么,于是死倔强的你又憨批的重新写了一次,这时候会怎么样,报错!
所以这就是为什么他们没卵用的原因,不仅没卵用,更是不提倡大家去用啊。
二、文件内指针移动
好的,这个就是有用的东西了
这个东西是干嘛用的呢
如果我们想要在文件内容中的某一行增加内容,实用基础的r/w/a模式实现是非常困难的(但并不是不行,老子就行),因此我们需要对文件内的指针进行移动。哦这个时候就有同学会问了
”为什么我不可以去文件里面直接增加内容呢?“
你为什么不直接把电脑机箱打开用机械手臂去刮磁道增加呢?
我们在讲的是用代码实现,代码!代码!
首先,先搞清楚什么是指针,指针就是光标,指针在哪里,你的输入内容就在哪里。
with open('36r.txt', 'r+t', encoding='utf-8') as fr:
fr.readline()
fr.write('力哥真帅啊') # 写在文件的最后一行
硬盘上从来没有修改一说,硬盘上只有覆盖,即新内容覆盖新内容。
1.seek(offset,whence): offset代表文件指针的偏移量,偏移量的单位是字节个数
# seek()
with open('36r.txt', 'rb') as fr:
print(f"fr.seek(4, 0): {fr.seek(4, 0)}") # 0相当于文件头开始;1相当于当前文件所在位置;2相当于文件末尾
# fr.seek(0,2) # 切换到文件末尾
fr.seek(4, 0): 3
2.tell(): 每次统计都是从文件开头到当前指针所在位置
# tell()
with open('36r.txt', 'rb') as fr:
fr.seek(4, 0)
print(f"fr.tell(): {fr.tell()}")
fr.tell(): 4
3.read(n): 只有在模式下的read(n),n代表的是字符个数,除此之外,其他但凡涉及文件指针的都是字节个数
# read()
with open('36r.txt', 'rt', encoding='utf-8') as fr:
print(f"fr.read(3): {fr.read(3)}")
fr.read(3): sdf
4.truncate(n): truncate(n)是截断文件,所以文件的打开方式必须可写,但是不能用w或w+等方式打开,因为那样直接清空文件了,所以truncate()要在r+或a或a+等模式下测试效果。它的参照物永远是文件头。并且truncate()不加参数,相当于清空文件。
# truncate()
with open('36r.txt', 'ab') as fr:
fr.truncate(2) # 截断2个字节后的所有字符,如果3个字节一个字符,只能截断2/3个字符,还会遗留1/3个字符,会造成乱码
以上的方法都是极其重要的方法,所以为了各位能够不被影响的学会这些方法,我就用了比较朴素易懂的话语来表述了一下,绝对不是因为CV大法真香
记得不要用既可读又可写的模式打开文件哦!
修改文件的两种方式
文件的数据是存放在硬盘上的,他只存在覆盖的情况,不存在修改的说法,我们看到的修改都是假象。
是不是就像告诉你你从小吃的饭都是牛粪变的一样让你无法接受?
来我解释给你听,这里不得不再一次祭出我璀璨星辰一般的画技了。
首先我们看,这是一块内存,上面有系统文件,你要修改的文件,以及若干大数量毛片。这个时候你要往你要修改的文件中加一些内容,那么他的内存占用是不是会变大?大了怎么办,叫系统文件往前挤挤?让毛片往后挪挪?很明显都不行,其实在你修改的时候,都是有缓存文件的,你改完之后直接就删除了原来的文件,然后把缓存文件改名为原来文件的名字,让你看上去就好像是修改了一样,实则是覆盖!
好,接下来介绍一下两种修改的方式
一、方式一(憨批方式)
将硬盘存放的该文件的内容全部加载到内存,在内存中是可以修改的,修改完毕后,再由内存覆盖到硬盘(word,vim,nodpad++等编辑器)。
import os
with open('37r.txt') as fr, \
open('37r_swap.txt', 'w') as fw:
data = fr.read() # 全部读入内存,如果文件很大,会很卡
data = data.replace('tank', 'tankSB') # 在内存中完成修改
fw.write(data) # 新文件一次性写入原文件内容
# 删除原文件
os.remove('37r.txt')
# 重命名新文件名为原文件名
os.rename('37r_swap.txt', '37r.txt')
print('done...')
done...
直接把文件全读出来然后改,这还不憨批?
对不起,对不起,今天是8/19号,我来改博客了,截至目前为止,我一直都是用这种方式改文件的,不憨批,一点儿也不憨批。
二、方式二
将硬盘存放的该文件的内容一行一行地读入内存,修改完毕就写入新文件,最后用新文件覆盖源文件。
import os
with open('37r.txt') as fr,\
open('37r_swap.txt', 'w') as fw:
# 循环读取文件内容,逐行修改
for line in fr:
line = line.replace('jason', 'jasonSB')
# 新文件写入原文件修改后内容
fw.write(line)
os.remove('37r.txt')
os.rename('37r_swap.txt', '37r.txt')
print('done...')
done...
总而言之,修改文件内容的思路为:以读的方式打开原文件,以写的方式打开一个新的文件,把原文件的内容进行修改,然后写入新文件,之后利用os模块的方法,把原文件删除,重命名新文件为原文件名,达到以假乱真的目的。
函数的定义
一、函数体系
这玩意儿看过一下就好了,到时候会一个一个讲的
- 什么是函数?
- 为什么要用函数?
- 函数的分类:内置函数与自定义函数
- 如何自定义函数
- 语法
- 定义有参数函数,及有参函数的应用场景
- 定义无参数函数,及无参函数的应用场景
- 定义空函数,及空函数的应用场景
- 调用函数
- 如何调用函数
- 函数的返回值
- 函数参数的应用:形参和实参,位置形参,位置实参,关键字实参,默认形参,*args,**kwargs
- 高阶函数(函数对象)
- 函数嵌套
- 作用域与名称空间
- 装饰器
- 迭代器与生成器及协程函数
- 三元运算,列表解析、生成器表达式
- 函数的递归调用
- 内置函数
- 面向过程编程与函数式编程
二、什么是函数
假设你是一个恐怖分子,要去爆破一个军事要塞。正常人都会带zhayao过去,而不会去军事要塞现场制作zhayao,弟弟行为。这个zhayao,就是你要是用的工具,就是函数,当然函数是可以重复使用的,这点就不要说zhayao是一次性的跟我刚了,再刚你也是一次性的了。
三、为什么要用函数
就是这个带zhayao还是现场制作的问题。
四、如何使用函数
用def +函数名 +‘:’就好了
定义函数的三种形式
一、无参函数
定义函数时参数是函数体接收外部传值的一种媒介,其实就是一个变量名
在函数阶段括号内没有参数,称为无参函数。需要注意的是:定义时无参,意味着调用时也无需传入参数。
如果函数体代码逻辑不需要依赖外部传入的值,必须得定义成无参函数。
def func():
print('hello nick')
func() # hello nick
二、有参函数
如果函数体代码逻辑需要依赖外部传入的值,必须得定义成有参函数。
def sum_self(x, y):
"""求和"""
res = x+y
print(res)
sum_self(1,2) # 3
三、空函数
def func():
pass
函数的返回值
一、什么是返回值
就是你炸弹的结果啦,
用return返回
炸弹的结果是爆炸
当然可以用return返回各种类型的数据
二、为什么要有返回值
没返回值的函数,就相当于不会爆炸的哑弹。毫无意义
你说你辛辛苦苦写的函数,最后什么回馈都没有,你写她来做什么,有什么意义呢?
函数的调用
一、什么是函数的调用
就是你把函数名写下来,他就被调用了,直到碰到return 或者执行完函数里面的全部代码之后才会停下来。如果没有写return,就会返回一个none
二、调用函数的三种形式
def max_self(x,y):
if x>y:
return x
else:
return y
# 1.
max_self(1,2)
# 2.
res = max_self(1,2)*12
# 3.
max_self(max_self(20000,30000),40000)
函数的参数
1.1形参
def func(x, y):
print(x)
print(y)
1.2 实参
func(1, 2)
二、位置参数
**位置形参
def func(x, y):
print(x)
print(y)
特点:按照位置定义的形参,都必须被传值,多一个不行,少一个也不行。
2.2 位置实参
func(1, 2)
特点:按照位置为对应的形参依次传值。
三、关键字实参(憨批东西,这辈子我都不用,除非有特殊情况)
在调用函数时,按照key=value的形式为指定的参数传值,称为关键字实参。
func(y=2, x=1)
特点:可以打破位置的限制,但仍能为指定的形参赋值。
注意:
- 可以混用位置实参和关键字实参,但是位置实参必须在关键字实参的左边。
- 可以混用位置实参和关键字实参,但不能对一个形参重复赋值。
func(x, y=2)
func(y=2, x) # SyntaxError: positional argument follows keyword argument
func(x, x=1) # NameError: name 'x' is not defined
四、默认形参
在定义阶段,就已经被赋值。
def func(x, y=10):
print(x)
print(y)
func(2)
特点:在定义阶段就已经被赋值,意味着在调用时可以不用为其赋值。
注意:
- 位置形参必须放在默认形参的左边。
- 默认形参的值只在定义阶段赋值一次,也就是说默认参数的值在函数定义阶段就已经固定了。
m = 10
def foo(x=m):
print(x)
m = 111
foo() # 10
- 默认参数的值通常应该是不可变类型。
# 演示形参是可变类型
def register(name, hobby, hobby_list=[]):
hobby_list.append(hobby)
print(f"{name} prefer {hobby}'")
print(f"{name} prefer {hobby_list}")
register('nick', 'read')
register('tank', 'zuipao')
register('jason', 'piao')
nick prefer read'
nick prefer ['read']
tank prefer zuipao'
tank prefer ['read', 'zuipao']
jason prefer piao'
jason prefer ['read', 'zuipao', 'piao']
# 修改形参是可变类型代码
def register(name, hobby, hobby_list=None):
if hobby_list is None:
hobby_list = []
hobby_list.append(hobby)
print(f"{name} prefer {hobby}'")
print(f"{name} prefer {hobby_list}")
register('nick', 'read')
register('tank', 'zuipao')
register('jason', 'piao')
nick prefer read'
nick prefer ['read']
tank prefer zuipao'
tank prefer ['zuipao']
jason prefer piao'
jason prefer ['piao']
总而言之,用什么还是看个人习惯
func(这里放几个参数不就完事儿了?搞得花里胡哨,人生苦短啊!)
今日朝贡就到这里了,没事就退下吧,朕乏了。去尿尿了。