
🔥承渊政道:个人主页
❄️个人专栏: 《C语言基础语法知识》 《数据结构与算法》 《C++知识内容》 《Linux系统知识》 《算法刷题指南》 《测评文章活动推广》 《大模型语言路线学习》 《MySQL数据库学习》 《Python知识内容》
✨逆境不吐心中苦,顺境不忘来时路!✨
🎬 博主简介:

在学习 Python 的过程中,掌握基础语法只是第一步,真正决定代码是否清晰、高效、易维护的,是对函数、列表、元组、字典以及文件操作等核心知识的理解.函数可以帮助我们封装重复逻辑,让代码结构更加清晰;列表、元组和字典是 Python 中最常用的数据容器,分别适合处理不同类型的数据;文件操作则让程序能够读取、保存和管理外部数据,使代码从简单练习逐渐走向实际应用.本文将围绕函数、列表、元组、字典与文件操作展开,通过基础概念、语法结构和简单示例,梳理这些知识点之间的区别与使用场景.无论你是刚开始学习 Python,还是想重新巩固基础,都可以通过本文建立更加完整、清晰的知识框架.废话不多说,下面跟着小编的节奏🎵一起去疯狂的学习吧!

目录
- 1.函数
-
- 1.1函数是什么
- 1.2语法格式
- 1.3函数参数
- 1.4函数返回值
- 1.5变量作用域
- 1.6函数执行过程
- 1.7链式调用
- 1.8嵌套调用
- 1.9函数递归
- 1.10参数默认值
- 1.11关键字参数
- 2.列表和元组
-
- 2.1列表是什么,元组是什么
- 2.2创建列表
- 2.3访问下标
- 2.4切片操作
- 2.5遍历列表元素
- 2.6新增元素
- 2.7查找元素
- 2.8删除元素
- 2.9连接列表
- 2.10关于元组
- 3.字典
-
- 3.1字典是什么
- 3.2创建字典
- 3.3查找 key
- 3.4新增/修改元素
- 3.5删除元素
- 3.6遍历字典元素
- 3.7取出所有 key 和 value
- 3.8合法的 key 类型
- 4.文件
-
- 4.1文件是什么
- 4.2文件路径
- 4.3文件操作
-
- 4.3.1打开文件
- 4.3.2关闭文件
- 4.3.3写文件
- 4.3.4读文件
- 4.3.1打开文件
- 4.4关于中文的处理
- 4.5使用上下文管理器
1.函数
1.1函数是什么
编程中的函数和数学中的函数有一定的相似之处. 数学上的函数, 比如 y = sin x , x 取不同的值, y 就会得到不同的结果. 编程中的函数, 是一段 可以被重复使用的代码片段 .
代码示例: 求数列的和, 不使用函数
1# 1. 求 1 - 100 的和 2sum = 0 3for i in range(1, 101): 4sum += i 5print(sum) 6 7# 2. 求 300 - 400 的和 8sum = 0 9for i in range(300, 401): 10sum += i 11print(sum) 12 13# 3. 求 1 - 1000 的和 14sum = 0 15for i in range(1, 1001): 16sum += i 17print(sum) 18
可以发现, 这几组代码基本是相似的, 只有一点点差异. 可以把重复代码提取出来, 做成一个函数.实际开发中,复制粘贴是一种不太好的策略.实际开发的重复代码可能存在几十份甚至上百份.一旦这个重复代码需要被修改,那就得改几十次,非常不便于维护.
代码示例: 求数列的和,使用函数
1# 定义函数 2def calcSum(beg, end): 3sum = 0 4for i in range(beg, end + 1): 5sum += i 6print(sum) 7# 调用函数 8sum(1, 100) 9sum(300, 400) 10sum(1, 1000) 11
可以明显看到,重复的代码已经被消除了.
1.2语法格式
创建函数/定义函数
1def 函数名(形参列表): 2函数体 3return 返回值 4
调用函数/使用函数
1函数名(实参列表) // 不考虑返回值 2返回值 = 函数名(实参列表) // 考虑返回值 3
函数定义并不会执行函数体内容, 必须要调用才会执行. 调用几次就会执行几次
1def test1(): 2print('hello') 3# 如果光是定义函数, 而不调用, 则不会执行. 4
函数必须先定义, 再使用.
1test3() # 还没有执行到定义, 就先执行调用了, 此时就会报错. 2def test3(): 3print('hello') 4
1.3函数参数
在函数定义的时候,可以在( )中指定"形式参数"(简称形参),然后在调用的时候,由调用者把"实际参数"(简称实参)传递进去.这样就可以做到一份函数,针对不同的数据进行计算处理.
考虑前面的代码案例:
1def calcSum(beg, end): 2sum = 0 3for i in range(beg, end + 1): 4sum += i 5print(sum) 6calcSum(1, 100) 7calcSum(300, 400) 8calcSum(1, 1000) 9
上面的代码中,beg, end 就是函数的形参.1,100/300,400就是函数的实参.
(1)在执行sum(1,100) 的时候,就相当于beg=1,end=100,然后在函数内部就可以针对1-100进行运算.
(2)在执行sum(300, 400) 的时候,就相当于beg=300,end=400 ,然后在函数内部就可以针对300-400进行运算.
注意:
一个函数可以有一个形参,也可以有多个形参,也可以没有形参.
一个函数的形参有几个,那么传递实参的时候也得传几个.保证个数要匹配.
1def test(a, b, c): 2 print(a, b, c) 3test(10) 4

和C++/Java不同,Python是动态类型的编程语言,函数的形参不必指定参数类型.换句话说,一个
函数可以支持多种不同类型的参数.
1def test(a): 2 print(a) 3test(10) 4test('hello') 5test(True) 6

1.4函数返回值
函数的参数可以视为是函数的"输入",则函数的返回值,就可以视为是函数的"输出".
此处的"输入","输出"是更广义的输入输出,不是单纯指通过控制台输入输出.
我们可以把函数想象成一个 “工厂”.工厂需要买入原材料,进行加工,并生产出产品.
函数的参数就是原材料, 函数的返回值就是生产出的产品
1def calcSum(beg, end): 2 sum = 0 3 for i in range(beg, end + 1): 4 sum += i 5 print(sum) 6calcSum(1, 100) 7
可以转换成
1def calcSum(beg, end): 2sum = 0 3for i in range(beg, end + 1): 4sum += i 5return sum 6result = calcSum(1, 100) 7print(result) 8
这两个代码的区别就在于,前者直接在函数内部进行了打印,后者则使用 return 语句把结果返回给函数调用者,再由调用者负责打印.我们一般倾向于第二种写法.实际开发中我们的一个通常的编程原则, 是"逻辑和用户交互分离".而第一种写法的函数中,既包含了计算逻辑,又包含了和用户交互(打印到控制台上).这种写法是不太好的,如果后续我们需要的是把计算结果保存到文件中,或者通过网络发送,或者展示到图形化界面里,那么第一种写法的函数,就难以胜任了.而第二种写法则专注于做计算逻辑,不负责和用户交互.那么就很容易把这个逻辑搭配不同的用户交
互代码,来实现不同的效果.
一个函数中可以有多个 return 语句
1# 判定是否是奇数 2def isOdd(num): 3if num % 2 == 0: 4return False 5else: 6return True 7result = isOdd(10) 8print(result) 9
执行到return语句,函数就会立即执行结束,回到调用位置.
1# 判定是否是奇数 2def isOdd(num): 3if num % 2 == 0: 4return False 5return True 6result = isOdd(10) 7print(result) 8
如果num是偶数,则进入if之后,就会触发return False ,也就不会继续执行 return True
一个函数是可以一次返回多个返回值的.使用,来分割多个返回值.
1def getPoint(): 2 x = 10 3 y = 20 4return x, y 5a, b = getPoint() 6
如果只想关注其中的部分返回值,可以使用 _ 来忽略不想要的返回值.
1def getPoint(): 2 x = 10 3 y = 20 4 return x, y 5_, b = getPoint() 6
1.5变量作用域
1def getPoint(): 2 x = 10 3 y = 20 4 return x, y 5x, y = getPoint() 6
在这个代码中,函数内部存在x, y,函数外部也有 x, y.
但是这两组x, y不是相同的变量,而只是恰好有一样的名字.
变量只能在所在的函数内部生效.
在函数getPoint() 内部定义的 x, y 只是在函数内部生效.一旦出了函数的范围,这两个变量就不再生效了.
1def getPoint(): 2 x = 10 3 y = 20 4 return x, y 5getPoint() 6print(x, y) 7

在不同的作用域中,允许存在同名的变量
虽然名字相同,实际上是不同的变量.
1x = 20 2def test(): 3 x = 10 4 print(f'函数内部 x = {x}') 5test() 6print(f'函数外部 x = {x}') 7

注意:
在函数内部的变量,也称为 “局部变量”
不在任何函数内部的变量,也称为 “全局变量”
如果函数内部尝试访问的变量在局部不存在,就会尝试去全局作用域中查找
1x = 20 2def test(): 3 print(f'x = {x}') 4test() 5

如果是想在函数内部,修改全局变量的值,需要使用global关键字声明
1x = 20 2def test(): 3 global x 4 x = 10 5 print(f'函数内部 x = {x}') 6test() 7print(f'函数外部 x = {x}') 8

如果此处没有global,则函数内部的x =10就会被视为是创建一个局部变量x,这样就和全局变量 x 不相关了.
if / while / for 等语句块不会影响到变量作用域
换而言之,在 if / while / for 中定义的变量,在语句外面也可以正常使用.
1for i in range(1, 10): 2 print(f'函数内部 i = {i}') 3print(f'函数外部 i = {i}') 4
1.6函数执行过程
调用函数才会执行函数体代码. 不调用则不会执行.
函数体执行结束(或者遇到return语句),则回到函数调用位置,继续往下执行.
1def test(): 2 print("执行函数内部代码") 3 print("执行函数内部代码") 4 print("执行函数内部代码") 5print("1111") 6test() 7print("2222") 8test() 9print("3333") 10

1.7链式调用
1# 判定是否是奇数 2def isOdd(num): 3 if num % 2 == 0: 4 return False 5 else: 6 return True 7result = isOdd(10) 8print(result) 9
实际上也可以简化写作
1print(isOdd(10)) 2
把一个函数的返回值, 作为另一个函数的参数, 这种操作称为 链式调用.
1.8嵌套调用
函数内部还可以调用其他的函数, 这个动作称为 “嵌套调用” .
1def test(): 2 print("执行函数内部代码") 3 print("执行函数内部代码") 4 print("执行函数内部代码") 5
test 函数内部调用了print函数,这里就属于嵌套调用.
==一个函数里面可以嵌套调用任意多个函数. ==
函数嵌套的过程是非常灵活的.
1def a(): 2 print("函数 a") 3def b(): 4 print("函数 b") 5 a() 6def c(): 7 print("函数 c") 8 b() 9def d(): 10 print("函数 d") 11 c() 12d() 13

如果把代码稍微调整, 打印结果则可能发生很大变化.
1def a(): 2 print("函数 a") 3def b(): 4 a() 5 print("函数 b") 6def c(): 7 b() 8 print("函数 c") 9def d(): 10 c() 11 print("函数 d") 12d() 13

函数之间的调用关系,在Python中会使用一个特定的数据结构来表示,称为函数调用栈.每次函数调用,都会在调用栈里新增一个元素,称为 栈帧.
每个函数的局部变量,都包含在自己的栈帧中
1def a(): 2 num1 = 10 3 print("函数 a") 4def b(): 5 num2 = 20 6 a() 7 print("函数 b") 8def c(): 9 num3 = 30 10 b() 11 print("函数 c") 12def d(): 13 num4 = 40 14 c() 15 print("函数 d") 16d() 17
1.9函数递归
递归是嵌套调用中的一种特殊情况,即一个函数嵌套调用自己.
代码示例: 递归计算 5!
1def factor(n): 2 if n == 1: 3 return 1 4 return n * factor(n - 1) 5result = factor(5) 6print(result) 7
上述代码中,就属于典型的递归操作.在 factor函数内部,又调用了factor自身.
注意: 递归代码务必要保证
- 存在递归结束条件. 比如 if n == 1 就是结束条件. 当 n 为 1 的时候, 递归就结束了.
- 每次递归的时候, 要保证函数的实参是逐渐逼近结束条件的.
如果上述条件不能满足, 就会出现 “无限递归” . 这是一种典型的代码错误.
1def factor(n): 2 return n * factor(n - 1) 3result = factor(5) 4print(result) 5

如前面所描述,函数调用时会在函数调用栈中记录每一层函数调用的信息.
但是函数调用栈的空间不是无限大的.如果调用层数太多,就会超出栈的最大范围,导致出现问题.
递归的优点
- 递归类似于 “数学归纳法” ,明确初始条件,和递推公式,就可以解决一系列的问题.
- 递归代码往往代码量非常少.
递归的缺点
- 递归代码往往难以理解, 很容易超出掌控范围
- 递归代码容易出现栈溢出的情况
- 递归代码往往可以转换成等价的循环代码.并且通常来说循环版本的代码执行效率要略高于递归版本.
1.10参数默认值
Python 中的函数, 可以给形参指定默认值.
带有默认值的参数, 可以在调用的时候不传参.
代码示例: 计算两个数字的和
1def add(x, y, debug=False): 2 if debug: 3 print(f'调试信息: x={x}, y={y}') 4 return x + y 5print(add(10, 20)) 6print(add(10, 20, True)) 7
此处debug=False 即为参数默认值.当我们不指定第三个参数的时候, 默认 debug 的取值即为 False. 带有默认值的参数需要放到没有默认值的参数的后面.
1def add(x, debug=False, y): 2 if debug: 3 print(f'调试信息: x={x}, y={y}') 4 return x + y 5print(add(10, 20)) 6

1.11关键字参数
在调用函数的时候,需要给函数指定实参.一般默认情况下是按照形参的顺序,来依次传递实参的.但是我们也可以通过 关键字参数,来调整这里的传参顺序,显式指定当前实参传递给哪个形参.
1def test(x, y): 2 print(f'x = {x}') 3 print(f'y = {y}') 4test(x=10, y=20) 5test(y=100, x=200) 6

形如上述 test(x=10, y=20) 这样的操作,即为关键字参数.
2.列表和元组
2.1列表是什么,元组是什么
列表和元组都可以用来保存多个数据。核心区别是:
列表 list:可以修改
元组 tuple:创建后不能修改
列表是一种让程序猿在代码中批量表示/保存数据的方式.
元组和列表相比,是非常相似的,只是列表中放哪些元素可以修改调整,元组中放的元素是创建元组的时候就设定好的,不能修改调整.
2.2创建列表
创建列表主要有两种方式. [ ] 表示一个空的列表.
1alist = [ ] 2alist = list() 3print(type(alist)) 4
如果需要往里面设置初始值, 可以直接写在 [ ] 当中.
可以直接使用 print 来打印 list 中的元素内容.
1alist = [1, 2, 3, 4] 2print(alist) 3
列表中存放的元素允许是不同的类型. (这一点和 C++ Java 差别较大).
1alist = [1, 'hello', True] 2print(alist) 3
因为 list 本身是 Python 中的内建函数, 不宜再使用 list 作为变量名, 因此命名为 alist
2.3访问下标
可以通过下标访问操作符 [ ] 来获取到列表中的任意元素.
我们把 [ ] 中填写的数字, 称为 下标 或者 索引 .
1alist = [1, 2, 3, 4] 2print(alist[2]) 3
注意: 下标是从0开始计数的,因此下标为2,则对应着3这个元素.
通过下标不光能读取元素内容,还能修改元素的值.
1alist = [1, 2, 3, 4] 2alist[2] = 100 3print(alist) 4
如果下标超出列表的有效范围, 会抛出异常.
1alist = [1, 2, 3, 4] 2print(alist[100]) 3

因为下标是从0开始的, 因此下标的有效范围是 [0, 列表长度 - 1]. 使用 len 函数可以获取到列表的元素个数.
1alist = [1, 2, 3, 4] 2print(len(alist)) 3
下标可以取负数. 表示"倒数第几个元素"

1alist = [1, 2, 3, 4] 2print(alist[3]) 3print(alist[-1]) 4
alist[-1] 相当于 alist[len(alist) - 1]
2.4切片操作
通过下标操作是一次取出里面第一个元素.
通过切片, 则是一次取出一组连续的元素, 相当于得到一个 子列表
使用 [ : ] 的方式进行切片操作.
1alist = [1, 2, 3, 4] 2print(alist[1:3]) 3

切片操作中可以省略前后边界
1alist = [1, 2, 3, 4] 2print(alist[1:]) # 省略后边界, 表示获取到列表末尾 3print(alist[:-1]) # 省略前边界, 表示从列表开头获取 4print(alist[:]) # 省略两个边界, 表示获取到整个列表. 5

切片操作还可以指定"步长",也就是"每访问一个元素后,下标自增几步"
1alist = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 2print(alist[::1]) 3print(alist[::2]) 4print(alist[::3]) 5print(alist[::5]) 6

切片操作指定的步长还可以是负数, 此时是从后往前进行取元素. 表示 “每访问一个元素之后, 下标自减几步”
1alist = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 2print(alist[::-1]) 3print(alist[::-2]) 4print(alist[::-3]) 5print(alist[::-5]) 6

如果切片中填写的数字越界了, 不会有负面效果. 只会尽可能的把满足条件的元素过去到.
1alist = [1, 2, 3, 4] 2print(alist[100:200]) 3

2.5遍历列表元素
“遍历” 指的是把元素一个一个的取出来, 再分别进行处理.
最简单的办法就是使用 for 循环
1alist = [1, 2, 3, 4] 2for elem in alist: 3 print(elem) 4
也可以使用 for 按照范围生成下标, 按下标访问
1alist = [1, 2, 3, 4] 2for i in range(0, len(alist)): 3 print(alist[i]) 4
还可以使用while循环.手动控制下标的变化
1alist = [1, 2, 3, 4] 2i = 0 3while i < len(alist): 4 print(alist[i]) 5 i += 1 6
2.6新增元素
使用 append 方法, 向列表末尾插入一个元素(尾插).
1alist = [1, 2, 3, 4] 2alist.append('hello') 3print(alist) 4

使用 insert 方法, 向任意位置插入一个元素
1alist = [1, 2, 3, 4] 2alist.insert(1, 'hello') 3print(alist) 4

2.7查找元素
使用 in 操作符, 判定元素是否在列表中存在. 返回值是布尔类型.
1alist = [1, 2, 3, 4] 2print(2 in alist) 3print(10 in alist) 4

使用index方法,查找元素在列表中的下标.返回值是一个整数.如果元素不存在,则会抛出异常.
1alist = [1, 2, 3, 4] 2print(alist.index(2)) 3print(alist.index(10)) 4
2.8删除元素
使用 pop 方法删除最末尾元素
1alist = [1, 2, 3, 4] 2alist.pop() 3print(alist) 4

pop 也能按照下标来删除元素
1alist = [1, 2, 3, 4] 2alist.pop(2) 3print(alist) 4

使用 remove 方法, 按照值删除元素.
1alist = [1, 2, 3, 4] 2alist.remove(2) 3print(alist) 4

2.9连接列表
使用 + 能够把两个列表拼接在一起.
1alist = [1, 2, 3, 4] 2blist = [5, 6, 7] 3print(alist + blist) 4

使用extend方法,相当于把一个列表拼接到另一个列表的后面.
1alist = [1, 2, 3, 4] 2blist = [5, 6, 7] 3alist.extend(blist) 4print(alist) 5print(blist) 6

2.10关于元组
元组的功能和列表相比, 基本是一致的.
元组使用 ( ) 来表示.
1atuple = ( ) 2atuple = tuple() 3
元组不能修改里面的元素, 列表则可以修改里面的元素
另外, 元组在 Python 中很多时候是默认的集合类型. 例如, 当一个函数返回多个值的时候.
1def getPoint(): 2 return 10, 20 3result = getPoint() 4print(type(result)) 5

此处的 result 的类型, 其实是元组.
问题来了, 既然已经有了列表, 为啥还需要有元组?
元组相比于列表来说, 优势有两方面:
你有一个列表, 现在需要调用一个函数进行一些处理.但是你有不是特别确认这个函数是否会
把你的列表数据弄乱. 那么这时候传一个元组就安全很多.我们下面要讲的字典,是一个键值对结构. 要求字典的键必须是 “可hash对象” (字典本质上也是一个hash表). 而一个可hash对象的前提就是不可变. 因此元组可以作为字典的键, 但是列表不行.
3.字典
3.1字典是什么
字典是一种存储 键值对 的结构.
啥是键值对? 这是计算机/生活中一个非常广泛使用的概念.
把 键(key) 和 值(value) 进行一个一对一的映射, 然后就可以根据键, 快速找到值.
可以理解为现实中的通讯录:
姓名是“键”
电话号码是“值”
3.2创建字典
创建一个空的字典. 使用 { } 表示字典.
1a = { } 2b = dict() 3print(type(a)) 4print(type(b)) 5
也可以在创建的同时指定初始值
键值对之间使用 , 分割, 键和值之间使用 : 分割. (冒号后面推荐加一个空格).
使用 print 来打印字典内容
1student = { 'id': 1, 'name': 'zhangsan' } 2print(student) 3
为了代码更规范美观, 在创建字典的时候往往会把多个键值对, 分成多行来书写.
1student = { 2'id': 1, 3'name': 'zhangsan' 4} 5
最后一个键值对,后面可以写,也可以不写.
1student = { 2'id': 1, 3'name': 'zhangsan', 4} 5
3.3查找 key
使用in可以判定key是否在字典中存在.返回布尔值.
1student = { 2'id': 1, 3'name': 'zhangsan', 4} 5print('id' in student) 6print('score' in student) 7
使用 [ ] 通过类似于取下标的方式, 获取到元素的值. 只不过此处的"下标"是 key. (可能是整数, 也可能是字符串等其他类型).
1student = { 2'id': 1, 3'name': 'zhangsan', 4} 5print(student['id']) 6print(student['name']) 7
如果 key 在字典中不存在, 则会抛出异常.
1student = { 2'id': 1, 3'name': 'zhangsan', 4} 5print(student['score']) 6
3.4新增/修改元素
使用 [ ] 可以根据 key 来新增/修改 value.
如果 key 不存在, 对取下标操作赋值, 即为新增键值对
1student = { 2'id': 1, 3'name': 'zhangsan', 4} 5student['score'] = 90 6print(student) 7
如果 key 已经存在, 对取下标操作赋值, 即为修改键值对的值.
1student = { 2'id': 1, 3'name': 'zhangsan', 4'score': 80 5} 6student['score'] = 90 7print(student) 8
3.5删除元素
使用 pop 方法根据 key 删除对应的键值对.
1student = { 2'id': 1, 3'name': 'zhangsan', 4'score': 80 5} 6student.pop('score') 7print(student) 8
3.6遍历字典元素
直接使用 for 循环能够获取到字典中的所有的 key, 进一步的就可以取出每个值了.
1student = { 2'id': 1, 3'name': 'zhangsan', 4'score': 80 5} 6for key in student: 7print(key, student[key]) 8
3.7取出所有 key 和 value
使用 keys 方法可以获取到字典中的所有的 key
1student = { 2'id': 1, 3'name': 'zhangsan', 4'score': 80 5} 6print(student.keys()) 7
此处 dict_keys 是一个特殊的类型, 专门用来表示字典的所有 key. 大部分元组支持的操作对于
dict_keys 同样适用.使用 values 方法可以获取到字典中的所有 value
1student = { 2'id': 1, 3'name': 'zhangsan', 4'score': 80 5} 6print(student.values()) 7
此处 dict_values 也是一个特殊的类型, 和 dict_keys 类似.使用 items 方法可以获取到字典中所有的键值对.
1student = { 2'id': 1, 3'name': 'zhangsan', 4'score': 80 5} 6print(student.items()) 7
3.8合法的 key 类型
不是所有的类型都可以作为字典的 key.
字典本质上是一个 哈希表, 哈希表的 key 要求是 “可哈希的”, 也就是可以计算出一个哈希值.
可以使用 hash 函数计算某个对象的哈希值.
但凡能够计算出哈希值的类型, 都可以作为字典的 key.
1print(hash(0)) 2print(hash(3.14)) 3print(hash('hello')) 4print(hash(True)) 5print(hash(())) # ( ) 是一个空的元组 6
列表无法计算哈希值.
1print(hash([1, 2, 3])) 2
字典也无法计算哈希值
1print(hash({ 'id': 1 })) 2
4.文件
4.1文件是什么
变量是把数据保存到内存中. 如果程序重启/主机重启, 内存中的数据就会丢失.
要想能让数据被持久化存储, 就可以把数据存储到硬盘中. 也就是在 文件 中保存.
在 Windows “此电脑” 中,看到的内容都是文件.
通过文件的后缀名, 可以看到文件的类型. 常见的文件的类型如下:
文本文件 (txt)
可执行文件 (exe, dll)
图片文件 (jpg, gif)
视频文件 (mp4, mov)
office 文件 (.ppt, docx)
4.2文件路径
一个机器上, 会存在很多文件, 为了让这些文件更方面的被组织, 往往会使用很多的 “文件夹”(也叫做目录)来整理文件.实际一个文件往往是放在一系列的目录结构之中的. 为了方便确定一个文件所在的位置, 使用 文件路径 来进行描述. 目录之间的分隔符, 可以使用 \ 也可以使用 / . 一般在编写代码的时候使用 / 更方便. 上述以盘符开头的路径, 我们也称为 绝对路径.除了绝对路径之外,还有一种常见的表示方式是相对路径.相对路径需要先指定一个基准目录,然后以基准目录为参照点, 间接的找到目标文件.描述一个文件的位置,使用绝对路径和相对路径都是可以的.对于新手来说,使用绝对路径更简单更好理解,也不容易出错.
4.3文件操作
要使用文件, 主要是通过文件来保存数据, 并且在后续把保存的数据读取出来.
但是要想读写文件, 需要先 “打开文件”, 读写完毕之后还要 “关闭文件”.
4.3.1打开文件
使用内建函数 open 打开一个文件.
1f = open('d:/test.txt', 'r') 2
第一个参数是一个字符串, 表示要打开的文件路径
第二个参数是一个字符串, 表示打开方式. 其中 r 表示按照读方式打开. w 表示按照写方式打开. a表示追加写方式打开.
如果打开文件成功, 返回一个文件对象. 后续的读写文件操作都是围绕这个文件对象展开.
如果打开文件失败(比如路径指定的文件不存在), 就会抛出异常.
4.3.2关闭文件
使用 close 方法关闭已经打开的文件.
1f.close() 2
使用完毕的文件要记得及时关闭!
一个程序能同时打开的文件个数, 是存在上限的.
1flist = [] 2count = 0 3while True: 4 f = open('d:/test.txt', 'r') 5 flist.append(f) 6 count += 1 7 print(f'count = {count}') 8
4.3.3写文件
文件打开之后, 就可以写文件了.
写文件, 要使用写方式打开, open 第二个参数设为 ‘w’
使用 write 方法写入文件.
1f = open('d:/test.txt', 'w') 2f.write('hello') 3f.close() 4
如果是使用 ‘r’ 方式打开文件, 则写入时会抛出异常.
1f = open('d:/test.txt', 'r') 2f.write('hello') 3f.close() 4
使用 ‘w’ 一旦打开文件成功, 就会清空文件原有的数据.
使用 ‘a’ 实现 “追加写”, 此时原有内容不变, 写入的内容会存在于之前文件内容的末尾.
1f = open('d:/test.txt', 'w') 2f.write('hello') 3f.close() 4f = open('d:/test.txt', 'a') 5f.write('world') 6f.close() 7
针对已经关闭的文件对象进行写操作, 也会抛出异常.
1f = open('d:/test.txt', 'w') 2f.write('hello') 3f.close() 4f.write('world') 5
4.3.4读文件
读文件内容需要使用 ‘r’ 的方式打开文件
使用 read 方法完成读操作. 参数表示 “读取几个字符”
1f = open('d:/test.txt', 'r') 2result = f.read(2) 3print(result) 4f.close() 5
如果文件是多行文本, 可以使用 for 循环一次读取一行.
1f = open('d:/test.txt', 'r') 2for line in f: 3 print(f'line = {line}') 4f.close() 5
使用 readlines 直接把文件整个内容读取出来, 返回一个列表. 每个元素即为一行.
1f = open('d:/test.txt', 'r') 2lines = f.readlines() 3print(lines) 4f.close() 5
4.4关于中文的处理
当文件内容存在中文的时候, 读取文件内容不一定就顺利.
计算机表示中文的时候, 会采取一定的编码方式, 我们称为 “字符集”
所谓 “编码方式” , 本质上就是使用数字表示汉字.我们知道,计算机只能表示二进制数据.要想表示英文字母, 或者汉字, 或者其他文字符号, 就都要通过编码.最简单的字符编码就是ascii.使用一个简单的整数就可以表示英文字母和阿拉伯数字.但是要想表示汉字,就需要一个更大的码表.
一般常用的汉字编码方式,主要是 GBK 和 UTF-8必须要保证文件本身的编码方式,和 Python 代码中读取文件使用的编码方式匹配,才能避免出现上述问题.Python3 中默认打开文件的字符集跟随系统, 而简体中文版的字符集采用了 GBK, 所以如果文件本身是 GBK 的编码, 直接就能正确处理. 如果文件本身是其他编码(比如 UTF-8), 那么直接打开就可能出现上述问题.
如果此处的编码为ANSI,则表示 GBK 编码. 如果此处为UTF-8,则表示UTF-8编码.此时修改打开文件的代码,给 open 方法加上 encoding 参数, 显式的指定为和文本相同的字符集, 问题
即可解决.
1f = open('d:/test.txt', 'r', encoding='utf8') 2
4.5使用上下文管理器
打开文件之后, 是容易忘记关闭的. Python 提供了 上下文管理器 , 来帮助程序猿自动关闭文件.
使用 with 语句打开文件.
当 with 内部的代码块执行完毕后, 就会自动调用关闭方法.
1with open('d:/test.txt', 'r', encoding='utf8') as f: 2lines = f.readlines() 3print(lines) 4

🚀真正的勇者不是流泪的人,而是含泪奔跑的人!
敬请期待下一篇文章内容
每日心灵鸡汤: 真正拉开差距的,是一个人的底层决策逻辑!
一个人开始变富,往往不是因为赚到了钱,而是因为底层决策逻辑发生了改变:他开始把时间视为最稀缺的资产,拒绝无效消耗;不再向外证明自己,而是向内积累资产;学习不再为了竞争,而是为了理解世界运行的规律;接受长期主义,能够忍受延迟回报;收入增长后,不升级欲望,而是升级资本积累能力.真正拉开人与人差距的,从来不是收入,而是一个人如何看待时间、认知、欲望和未来.

《【Python学习】(认识函数、列表、元组、字典与文件核心知识要点)》 是转载文章,点击查看原文。
