python学习 day3
一、python文件操作
文件操作基本流程:
计算机系统分为:计算机硬件,操作系统,应用程序三部分。
我们用python或其他语言编写的应用程序若想要把数据永久保存下来,必须要保存于硬盘中,这就涉及到应用程序要操作硬件,众所周知,应用程序是无法直接操作硬件的,这就用到了操作系统。操作系统把复杂的硬件操作封装成简单的接口给用户/应用程序使用,其中文件就是操作系统提供给应用程序来操作硬盘虚拟概念,用户或应用程序通过操作文件,可以将自己的数据永久保存下来。
有了文件的概念,我们无需再去考虑操作硬盘的细节,只需要关注操作文件的流程:
方法一:
#打开文件,得到文件句柄并赋值给一个变量
f = open('D:\code\\1.txt',encoding='utf-8',mode='r') #指定打开文件的自己,默认是以读模式打开
file = f.read() #通过句柄对文件进行操作
f.close() #关闭文件,使用该方法打开的文件,操作完成一定要进行关闭,不然会有内存溢出的风险
方法二:
#次方法的优点不需要担心关闭文件,只要在with语句下的代码执行完毕后,该方法会自动帮你将文件关闭
with open('D:\code\st.txt','w') as f:
f.write("hello") #绝对路径
文件打开方式:
#1. 打开文件的模式有(默认为文本模式):
r ,只读模式【默认模式,文件必须存在,不存在则抛出异常】
w,只写模式【不可读;不存在则创建;存在则清空内容】
a, 只追加写模式【不可读;不存在则创建;存在则只追加内容】
注:正常工作中使用r、w、a这三种模式就完全够用了,不建议使用r+、w+等模式
#2. 对于非文本文件,我们只能使用b模式,"b"表示以字节的方式操作(而所有文件也都是以字节的形式存储的,使用这种模式无需考虑文本文件的字符编码、图片文件的jgp格式、视频文件的avi格式)
rb
wb
ab
注:以b方式打开时,读取到的内容是字节类型,写入时也需要提供字节类型,不能指定编码
#3,‘+’模式(就是增加了一个功能)
r+, 读写【可读,可写】
w+,写读【可写,可读】
a+, 写读【可写,可读】
#4,以bytes类型操作的读写,写读,写读模式
r+b, 读写【可读,可写】
w+b,写读【可写,可读】
a+b, 写读【可写,可读】
常用的文件操作方法:
f1 = open('空姐护士老师主妇.txt', encoding='utf-8', mode='r')
content = f1.read()
print(content)
f1.close()
# read 全部读出,强烈不建议使用该方法,因为该方法会将全部文件都加载到内存中,如果文件过大的话会撑爆内存
f1 = open('log1', encoding='utf-8')
content = f1.read() #
print(content)
f1.close()
#read(n)
f1 = open('log1', encoding='utf-8')
content = f1.read(5) # r 模式 按照字符读取。
print(content)
f1.close()
f1 = open('log1', mode='rb')
content = f1.read(3) # rb模式 按照字节读取。
print(content.decode('utf-8'))
f1.close()
#readline()按行读取
f1 = open('log1', encoding='utf-8')
print(f1.readline())
print(f1.readline())
print(f1.readline())
print(f1.readline())
f1.close()
#readlines() 将每一行作为列表的一个元素并返回这个列表
f1 = open('log1', encoding='utf-8')
print(f1.readlines())
f1.close()
#for循环
f1 = open('log1', encoding='utf-8')
for i in f1:
print(i)
f1.close()
#我们在工作建议使用for循环的方法
#编码的补充:
s1 = b'\xd6\xd0\xb9\xfa'
s2 = s1.decode('gbk')
s3 = s2.encode('utf-8')
#将gbk编码转换为utf-8
print(s3) # b'\xe4\xb8\xad\xe5\x9b\xbd'
s1 = b'\xd6\xd0\xb9\xfa'.decode('gbk').encode('utf-8')
print(s1)
文件修改:
1,打开原文件,产生文件句柄。
2,创建新文件,产生文件句柄。
3,读取原文件,进行修改,写入新文件。
4,将原文件删除。
5,新文件重命名原文件。
#文件的数据是存放于硬盘上的,因而只存在覆盖、不存在修改这么一说,我们平时看到的修改文件,都是模拟出来的效果,具体的说有两种实现方式: 方式一:将硬盘存放的该文件的内容全部加载到内存,在内存中是可以修改的,修改完毕后,再由内存覆盖到硬盘(word,vim,nodpad++等编辑器) import os # 调用系统模块 with open('a.txt') as read_f,open('.a.txt.swap','w') as write_f: data=read_f.read() #全部读入内存,如果文件很大,会很卡 data=data.replace('Tom','jerry') #在内存中完成修改 write_f.write(data) #一次性写入新文件 os.remove('a.txt') #删除原文件 os.rename('.a.txt.swap','a.txt') #将新建的文件重命名为原文件 方法二:将硬盘存放的该文件的内容一行一行地读入内存,修改完毕就写入新文件,最后用新文件覆盖源文件 import os with open('a.txt') as read_f,open('.a.txt.swap','w') as write_f: for line in read_f: line=line.replace('Tom','jerry') write_f.write(line) os.remove('a.txt') os.rename('.a.txt.swap','a.txt')
二、函数
函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。
函数能提高应用的模块性,和代码的重复利用率。你已经知道Python提供了许多内建函数,比如print(),len()等。但你也可以自己创建函数,这被叫做用户自定义函数。
#函数定义 def mylen(): """计算s1的长度""" s1 = "hello world" length = 0 for i in s1: length = length+1 print(length) #函数调用 mylen() #函数名+() 执行函数 #函数的返回值 return ''' 1,遇到return,结束函数。 def func1(): print(11) print(22) return print(333) print(444) func1() 2,给函数的调用者(执行者)返回值。 无 return 返回None return 不写 或者 None 返回None return 返回单个数. return 返回多个数,将多个数放在元组中返回。 '''
函数参数:
#函数定义 def mylen(s1): """计算s1的长度""" length = 0 for i in s1: length = length+1 return length #函数调用 str_len = mylen("hello world") print('str_len : %s'%str_len)
我们告诉mylen函数要计算的字符串是谁,这个过程就叫做 传递参数,简称传参,我们调用函数时传递的这个“hello world”和定义函数时的s1就是参数。
实参与形参
参数还有分别:
我们调用函数时传递的这个“hello world”被称为实际参数,因为这个是实际的要交给函数的内容,简称实参。
定义函数时的s1,只是一个变量的名字,被称为形式参数,因为在定义函数的时候它只是一个形式,表示这里有一个参数,简称形参。
传递多个参数
参数可以传递多个,多个参数之间用逗号分割。
def mymax(x,y): the_max = x if x > y else y return the_max ma = mymax(10,20) print(ma)
动态参数 *args,**kwargs 万能参数
三、命名空间和作用域
我们回忆一下python代码运行的时候遇到函数是怎么做的。
从python解释器开始执行之后,就在内存中开辟了一个空间
每当遇到一个变量的时候,就把变量名和值之间的对应关系记录下来。
但是当遇到函数定义的时候解释器只是象征性的将函数名读入内存,表示知道这个函数的存在了,至于函数内部的变量和逻辑解释器根本不关心。
等执行到函数调用的时候,python解释器会再开辟一块内存来存储这个函数里的内容,这个时候,才关注函数里面有哪些变量,而函数中的变量会存储在新开辟出来的内存中。函数中的变量只能在函数的内部使用,并且会随着函数执行完毕,这块内存中的所有内容也会被清空。
注:我们给这个“存放名字与值的关系”的空间起了一个名字——叫做命名空间
代码在运行伊始,创建的存储“变量名与值的关系”的空间叫做全局命名空间,在函数的运行中开辟的临时的空间叫做局部命名空间
命名空间与作用域:
命名空间一共分为三种:
全局命名空间
局部命名空间
内置命名空间
*内置命名空间中存放了python解释器为我们提供的名字:input,print,str,list,tuple...它们都是我们熟悉的,拿过来就可以用的方法。
三种命名空间之间的加载与取值顺序:
加载顺序:内置命名空间(程序运行前加载)->全局命名空间(程序运行中:从上到下加载)->局部命名空间(程序运行中:调用时才加载)
取值:
在局部调用:局部命名空间->全局命名空间->内置命名空间
作用域
作用域就是作用范围,按照生效范围可以分为全局作用域和局部作用域。
全局作用域:包含内置名称空间、全局名称空间,在整个文件的任意位置都能被引用、全局有效
局部作用域:局部名称空间,只能在局部范围内生效
globals和locals方法
def func(): a = 12 b = 20 print(locals()) print(globals()) func()
输出:
{'b': 20, 'a': 12}
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0578A590>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'D:/Python/day4/练习.py', '__cached__': None, 'func': <function func at 0x0582B8E8>}
闭包
def func(): name = 'eva' def inner(): print(name)
闭包函数:
内部函数包含对外部作用域而非全剧作用域名字的引用,该内部函数称为闭包函数
#函数内部定义的函数称为内部函数
判断闭包函数的方法__closure__
#输出的__closure__有cell元素 :是闭包函数 def func(): name = 'eva' def inner(): print(name) print(inner.__closure__) return inner f = func() f() #输出的__closure__为None :不是闭包函数 name = 'egon' def func2(): def inner(): print(name) print(inner.__closure__) return inner f2 = func2() f2()
总结:
命名空间:
一共有三种命名空间从大范围到小范围的顺序:内置命名空间、全局命名空间、局部命名空间
作用域(包括函数的作用域链):
小范围的可以用大范围的
但是大范围的不能用小范围的
范围从大到小(图)
在小范围内,如果要用一个变量,是当前这个小范围有的,就用自己的
如果在小范围内没有,就用上一级的,上一级没有就用上上一级的,以此类推。
如果都没有,报错
函数的嵌套:
嵌套调用
嵌套定义:定义在内部的函数无法直接在全局被调用
函数名的本质:
就是一个变量,保存了函数所在的内存地址
闭包:
内部函数包含对外部作用域而非全剧作用域名字的引用,该内部函数称为闭包函数