Python开发【第三篇】:文件操作与函数
内容概要
- 文件操作
- 初始函数
- 函数定义与调用
- 函数的返回值
- 函数的参数
- 函数进阶
- 函数参数--动态传参
- 名称空间
- 作用域
- 函数的嵌套
- 函数名的运用
- gloabal,nonlocal 关键字
1、文件操作
使用python来读写文件是非常简单的操作. 我们使用open()函数来打开一个文件, 获取到文件句柄. 然后通过文件句柄就可以进行各种各样的操作了. 根据打开方式的不同能够执行的操作也会有相应的差异.
打开文件的方式: r, w, a, r+, w+, a+, rb, wb, ab, r+b, w+b, a+b 默认使用的是r(只读)模式
1.1 只读操作
1. read() 将文件中的数据全部读取出来, 弊端: 占内存,如果文件过大,容易导致内存崩溃
f = open("文件练习",mode="r",encoding="utf-8") #encoding 表示编码集,即文件用什么编码写入的,就用什么编码获取到数据 content = f.read() print(content)
#执行结果:
民谣很好听,
但是很费烟啊。
read(n) 读取n个字符. 如果再次读取. 那么会在当前位置继续去读取不是从头读
f = open("文件练习",mode="r",encoding="utf-8") content1 = f.read(3) content2 = f.read(3) print(content1) print(content2)
#执行结果:
民谣很
好听,
2. readline() 每次读取一行数据, 注意: readline()结尾, 注意每次读取出来的数据都会有一个 \n 所以呢. 需要我们使用strip()方法来去掉\n或者空格
f = open("文件练习",mode="r",encoding="utf-8") content1 = f.readline() # 读取一行数据,光标会移动一行 content2 = f.readline() # seek(0) 移动光标到最开始位置 print(content1) print(content2) # 执行结果: 民谣很好听, 但是很费烟啊。
#print打印默认也带有 \n 换行,所以会有空行出来
3. readlines() 将每一行形成一个元素, 放到一个列表中. 将所有的内容都读取出来. 所以也是. 容易出现内存崩溃的问题
f = open("文件练习",mode="r",encoding="utf-8") lit = f.readlines() print(lit) # 执行结果: ['民谣很好听,\n', '但是很费烟啊。'] # 循环打印 for line in lit: print(line.strip())
4. 循环读取. 这种方式是最好的. 每次读取一行内容.不会产生内存溢出的问题.
# #重点:::: 文件句柄可以进行迭代 for line in f: # 每一行内容 print(line.strip())
f.close()
执行结果: 民谣很好听, 但是很费烟啊。
注意: 读取完的文件句柄一定要关闭 f.close()
1.2 写操作
# w(write) 写 如果文件不存在. 创建新文件, 如果文件存在. 清空文件
f = open("葫芦娃",mode="w",encoding="utf-8") f.write("蛇精") f.write("小金刚") print(f.read()) # io.UnsupportedOperation: not readable # 模式是w 不能执行读操作 f.flush() # 刷新,养成好习惯 f.close() # 关闭
# a(append) 追加
只要是a或者ab, a+ 都是在文件的末尾写入. 不论光标在任何位置
f = open("葫芦娃",mode="a",encoding="utf-8") f.write("大娃,二娃")
f.flush() # 刷新,养成好习惯 f.close() # 关闭
1.3 其他模式: rb, wb, ab b:bytes 不需要encoding
带b的用来操作非文本文件(图片, 视频, 音频)
# # 文件复制 # f1 = open("c:/hyf.jpg", mode="rb") # f2 = open("d:/hyf.jpg", mode="wb") # for b in f1: # 一部分一部分复制 # f2.write(b) # # f1.close() # f2.flush() # f2.close()
1.4 其他模式: r+, w+, a+ +:扩展
一个文件. 要么读, 要么写
r+ 在读的基础上扩展. 读写操作
w+ 写读操作
a+ 追加写读操作
# f = open("电影", mode="r+", encoding="utf-8") # r+ 读写:先读后写 # print(f.read()) # f.write("欢乐喜剧人") # 把原来的数据覆盖了 # # print(f.read()) # f.flush() # f.close()
其他模式:r+b, w+b, a+b 操作的是字节
1.5 文件修改操作
1. 读取源文件中的内容
2. 修改内容
3. 把新内容写入到副本文件
4. 删除源文件
5. 把副本文件重命名成源文件
import os
os.remove() 删除文件
os.rename() 重命名文件
文件内容: 10.2.12.17 10.2.12.40 10.2.12.17 10.2.12.13 把10.2.12.17 替换成 10.2.12.156 import os f1 = open("ip.txt",mode="r",encoding="utf-8") f2 = open("ip.txt.tmp",mode="w",encoding="utf-8") for content in f1: s = content.replace("10.2.12.17","10.2.12.156") f2.write(s) f1.close() f2.flush() f2.close() os.remove("ip.txt") os.rename("ip.txt.tmp","ip.txt") 使用with import os with open("ip.txt",mode="r",encoding="utf-8") as f1, \ open("ip.txt.tmp",mode="w",encoding="utf-8") as f2: for content in f1: s = content.replace("10.2.12.156","10.2.12.17") f2.write(s) os.remove("ip.txt") os.rename("ip.txt.tmp","ip.txt")
1.6 文件操作补充:
f.seek(0) 光标移动到开头
f.seek(0, 2) 光标移动到末尾
第二个参数表示模式:
0: 文件的开头,默认值
1: 光标当前位置
2: 文件的末尾
f.tell() 告诉你光标当前的位置
f.truncate() 截断文件
2、函数
1、 定义函数,函数是对功能或者动作的封装。
def 函数名(形参): 函数体 调用函数 函数名(实参) 例如: def func1(x): print("测试",x) func1("哈哈")
2、函数的返回值
执行完函数之后,可以使用 return来返回结果。
2.1 函数如果执行到return. 结束该函数
def func1(): print("测试") return print("测试") # 这句不会执行 func1()
2.2 return 值. 返回一个结果
def func1(): print("测试") return "ok"
res = func1()
print(res)
执行结果:
ok
2.3 只写return或者不写return. 返回None
def func1(): print("测试") return res = func1() print(res) #None
2.4 return 值1, 值2, 值3..... 返回多个结果
def func1(): print("测试") return "OK" ,"太好了" res = func1() print(res) print(type(res)) ('OK', '太好了') <class 'tuple'>
3、函数的参数
参数, 函数在调用的时候指定具体的一个变量的值. 就是参数. 语法:
def 函数名(参数列表):
函数体
关于参数:
形参
写在函数声明的位置的变量叫形参. 形式上的一个完整. 表示这个函数需要xxx
def func1(name): #形参 print("你的名字 %s" % name)
实参
在函数调用的时候给函数传递的值. 叫实参, 实际执⾏的时候给函数传递的信息. 表示给函数xxx
func1("周杰伦") # 实参
参数的分类
实参有三种: 位置参数、关键字参数、混合参数
位置参数
def func1(name,age,gender): print("%s %s %s" % (name,age,gender)) func1("周杰伦","18","男") # 一个值对应一个变量传上去

关键字参数
def func1(name,age,gender): print("%s %s %s" % (name,age,gender)) func1(gender="女",age=19,name="MM") #指定变量赋值
混合参数
两种参数混合着使用. 也就是说在调用函数的时候即可以给出位置参数, 也可以指定关键字参数.
def func1(name,age,gender): print("%s %s %s" % (name,age,gender)) func1("MM",gender="女",age=19)
注意: 在使用混合参数的时候, 关键字参数必须在位置参数后面 即,位置参数 --> 关键字参数
形参也分三种: 位置参数、默认值参数、动态参数
位置参数:按照位置来赋值
def func1(name,age,gender): print("%s %s %s" % (name,age,gender)) func1("周杰伦","18","男") # 一个值对应一个变量传上去
默认值参数:在函数声明的时候, 就可以给出函数参数的默认值. 在调用的时候可以给出具体的值, 也可以不给值, 使用默认值.
def func1(name,age,gender="男"): print("%s %s %s" % (name,age,gender)) func1("周杰伦","18")
注意, 必须先声明位置参数, 才能声明默认值参数
动态参数:
动态参数分为两种
1. *args 接收位置参数的动态传参
def func1(*args): # 接收所有位置参数,聚合为元祖 print(args) print("姓名:%s,年龄:%s,性别:%s" % args) # 元祖解包 func1("周杰伦","18","男")
# 执行结果: # ('周杰伦', '18', '男') # 姓名:周杰伦,年龄:18,性别:男
2. **kwargs 接收关键字参数的动态传参
def func1(**kwargs): # 接收所有关键字参数,聚合为字典 print(kwargs) func1(姓名="周杰伦",年龄=18,性别="男") # 执行结果: # {'姓名': '周杰伦', '年龄': 18, '性别': '男'}
动态接收所有参数,无敌的传几个参数,都可以接收:
def func1(*args,**kwargs): print(args) print(kwargs) func1(1,2,3,4,姓名="李世民") # 执行结果: (1, 2, 3, 4) {'姓名': '李世民'}
形参列表顺序:
位置 -> *args -> 默认值 -> **kwargs
动态参数的另一种传参方式:
在实参位置上给一个序列,列表,可迭代对象前面加个*表示把这个序列按顺序打散.
在形参的位置上的* 表示把接收到的参数组合成一个元组
def fun(*args): # 聚合 print(args)
lst = [1, 4, 7] fun(lst[0], lst[1], lst[2]) fun(*lst) # * 把一个列表按顺序 打散 s = "臣妾做不到" fun(*s) # 字符串也可以打散 (可迭代对象)
执行结果:
(1, 4, 7)
(1, 4, 7)
('臣', '妾', '做', '不', '到')
如果是一个字典, 那么也可以打散. 不过需要用两个*
def fun(**kwargs): # 聚合为字典 print(kwargs)
dic = {'a':1, 'b':2} fun(**dic) # 打散为一个个关键字参数
执行结果:
{'a': 1, 'b': 2}
函数的注释:
def chi(food, drink): """ 这⾥是函数的注释, 先写⼀下当前这个函数是⼲什么的, ⽐如我这个函数就是⼀个吃 :param :param food: 参数food是什么意思 :param :param drink: 参数drink是什么意思 :return :return: 返回的是什么东东 """ print(food, drink) return "very good"
2、命名空间
在python解释器开始执行之后, 就会在内存中开辟一个空间, 每当遇到一个变量的时候, 就把变量名和值之间的关系记录下来, 但是当遇到函数定义的时候, 解释器只是把函数名读入内存, 表示这个函数存在了, 至于函数内部的变量和逻辑, 解释器是不关心的. 也就是说一开始的时候函数只是加载进来, 仅此而已, 只有当函数被调用和访问的时候, 解释器才会根据函数内部声明的变量来进行开辟变量的内部空间. 随着函数执行完毕, 这些函数内部变量占用的空间也会随着函数执行完毕而被清空.
def fun(): a = 10 print(a) fun() print(a) # a 不存在了
我们给存放名字和值的关系的空间起一个名字叫: 命名空间. 我们的变量在存储的时候就是存储在这片空间中的.
- 命名空间分类:
- 内置命名空间 --> 存放python解释器为我们提供的名字, list, tuple, str, int这些都是内置命名空间
- 全局命名空间 --> 我们直接在py文件中, 函数外声明的变量都属于全局命名空间
- 局部命名空间 --> 在函数中声明的变量会放在局部命名空间
- 加载顺序:
- 内置命名空间
- 全局命名空间
- 局部命名空间(函数被执行的时候)
- 取值顺序:
- 局部命名空间
- 全局命名空间
- 内置命名空间
a = 10 def func1(): a = 20 print(a) #执行结果:20 会先在局部中找
def func2
print(a) #执行结果:10 一样先在局部找,局部没有 去全局找 func1()
func2()
执行结果:
# 20
# 10
3、作用域
作用域: 作用域就是作用范围, 按照生效范围来看分为 全局作用域和局部作用域
全局作用域: 包含内置命名空间和全局命名空间. 在整个文件的任何位置都可以使用(遵循从上到下逐行执行).
局部作用域: 在函数内部可以使用.
作用域命名空间:
1. 全局作用域: 全局命名空间 + 内置命名空间
2. 局部作用域: 局部命名空间
我们可以通过globals()函数来查看全局作用域中的内容, 也可以通过locals()来查看局部作用域中的变量和函数信息
a = 10 def func(): a = 40 b = 20 def abc(): print("哈哈") print(a, b) # 这里使用的是局部作用域 print(globals()) # 打印全局作用域中的内容 print(locals()) # 打印局部作用域中的内容 func()
4、函数的嵌套
1. 只要遇见了()就是函数的调用. 如果没有()就不是函数的调用
2. 函数的执行顺序
def fun1(): print(111) def fun2(): print(222) fun1() fun2() print(111)
# 函数的嵌套
def fun2(): print(222) def fun3(): print(666) print(444) fun3() print(888) print(33) fun2() print(555)
5、函数名
函数名就是变量,指向函数体的内存地址。
def f1(): print("f1") def f2(): print("f2") def f3(): print("f3") # fn 代理了f1 f2 f3函数的执行 def fn(x): # 函数名可以像变量一样作为参数进行传递 x() fn(f1) fn(f2) fn(f3)
函数名作为函数返回值。
def func(): def inner(): print("111") print(inner) return inner ret = func() # 把 inner 函数 返回给 ret变量 ret() # 此时 ret 存的就是inner函数体的内存地址 print(ret) #执行结果: 111 <function func.<locals>.inner at 0x00000000021FF158> <function func.<locals>.inner at 0x00000000021FF158> # 精简一下就是 def func(): def inner(): print("111") return inner func()() # 执行 inner()
函数名还可以作为列表的元素,字典的 value
def f1(): print("f1") def f2(): print("f2") def f3(): print("f3") func_list = [f1,f2,f3] for i in func_list: i() #执行结果: f1 f2 f3
# 作为字典的value
def f1(): print("f1") def f2(): print("f2") def f3(): print("f3") func_list = { 1: f1, 2: f2, 3: f3 } func_list[1]() func_list[2]() func_list[3]() # 执行结果: f1 f2 f3
6、关键字global和nonlocal
首先我们写这样一个代码, 首先在全局声明一个变量, 然后再局部调用这个变量, 并改变这个变量的值
a = 100 def func(): global a # 加了个global表示不再局部创建这个变量了. 而是直接使用全局的a a = 28 print(a) func() print(a)
global表示. 不再使用局部作用域中的内容了. 而改变全局作用域中的变量
lst = ["麻花藤", "刘嘉玲", "詹姆斯"] def func(): lst.append("马云云") # 对于可变数据类型可以直接进行访问. 但是不能改地址. 说白了. 不能赋值 print(lst) func() print(lst)
nonlocal 表示在局部作用域中, 调用父级命名空间中的变量. (不能调用全局命名空间中的变量)
a = 10 def func1(): a = 20 def func2(): nonlocal a a = 30 print(a) func2() print(a) func1() 结果: 加了nonlocal 30 30 不加nonlocal 30 20
再看, 如果嵌套了很多层, 会是一种什么效果:
a = 1 def fun_1(): a = 2 def fun_2(): nonlocal a a = 3 def fun_3(): a = 4 print(a) print(a) fun_3() print(a) print(a) fun_2() print(a) print(a) fun_1() print(a)
执行结果:

global
把全局中的变量引入到局部
a = 2 def wrapper(): global a a += 1 print(a) wrapper()
nonlocal
在局部...把离他最近的外层函数中的局部变量引入到当前.
def wrapper(): a = 1 def inner(): nonlocal a a += 1 print(a) inner() wrapper()

浙公网安备 33010602011771号