本周内容回顾
本周内容回顾
- 数据的内置方法
- 字符编码
- 文件操作
- 函数
数据的内置方法
数据的内置方法相当于是数据的一些独有的工具 可以很方便的操作数据
列表的内置方法
1.append()
就是在列表后面添加数据值
l1 = [1, 2, 3, 4, 5] l2 = [11, 22, 33] l1.append(66) print(l1) # [1, 2, 3, 4, 5, 66] l1.append(l2) print(l1) # [1, 2, 3, 4, 5, 66, [11, 22, 33]] l1.append(44) print(l1) # [1, 2, 3, 4, 5, 66, [11, 22, 33], 44] '''append括号内无论写什么数据类型都当做一个数据值添加'''
2.insert()
就是可以在列表的任意位置添加数据值
l1 = ['jason', 'tony', 11, 22, 'jerry'] l1.insert(0, 55) print(l1) # [55, 'jason', 'tony', 11, 22, 'jerry'] l1.insert(2, 'oscar') print(l1) # [55, 'jason', 'oscar', 'tony', 11, 22, 'jerry'] l1.insert(7, [1, 2, 3]) print(l1) # [55, 'jason', 'oscar', 'tony', 11, 22, 'jerry', [1, 2, 3]] ''' insert括号内第一个值是输入一个索引 第二个值是输入一个数据值 可以是任意数据类型 他会在索引位置添加你输入的数据值 原本的数据值就会往后 '''
3.extend()
就是扩展列表
1.for循环 l1 = ['jason', 'tony', 1, 2, 3] l2 = [4, 5, 6] for i in l2: l1.append(i) print(l1) # ['jason', 'tony', 1, 2, 3, 4, 5, 6] 2.+ 号 l1 = ['jason', 'tony', 1, 2, 3] l2 = [4, 5, 6] l3 = l1 + l2 print(l3) # ['jason', 'tony', 1, 2, 3, 4, 5, 6] 3.extend() l1 = ['jason', 'tony', 1, 2, 3] l2 = [4, 5, 6] l1.extend(l2) print(l1) # ['jason', 'tony', 1, 2, 3, 4, 5, 6] ''' 就是把两个列表拼接起来可以用for循环也可以用加号 但是加号会浪费内存资源 推荐使用extend extend()其实就是for循环加上append() ''' l1 = ['jason', 'tony', 1, 2, 3] l1.extend([4, 5, 6]) print(l1) # ['jason', 'tony', 1, 2, 3, 1, 2, 3] '''extend括号内要放可迭代对象 就是可以支持for循环'''
3.列表的删除操作
就是删除列表中的数据
# 1.通用的删除方法 关键字 del l1 = ['jason', 'tony', 11, 22, 'jerry'] del l1[0] # 通过输入索引就可以想要删除你想要删除数据 print(l1) # ['tony', 11, 22, 'jerry'] del l1 print(l1) # 报错 因为列表被删除了 l1就会被认为没有定义 '''如果删除了整个列表那么这个列表就会被完全删除''' # 2.指名道姓删除 关键字 remove l1 = ['jason', 'tony', 11, 22, 'jerry'] l1.remove('jason') # 直接输入数据值 print(l1) # ['tony', 11, 22, 'jerry'] '''直接删除你想要的删除的数据值''' # 3.弹出删除 关键字 pop l1 = ['jason', 'tony', 11, 22, 'jerry'] # res = l1.remove('jason') # print(l1, res) # ['tony', 11, 22, 'jerry'] None res = l1.pop() print(l1, res) # ['jason', 'tony', 11, 22] jerry '''pop随机弹出列表的末尾 然后在删除''' res = l1.pop(0) # 可以输入索引 print(l1, res) # ['tony', 11, 22, 'jerry'] jason
4.列表的改与查操作
# 1.改 l1 = ['jason', 'tony', 11, 22, 'jerry'] l1[0] = 12 # 输入索引就可以改变该列表的值 print(l1) # [12, 'tony', 11, 22, 'jerry'] l1[6] = 13 print(l1) # 会报错因为列表没有改索引 # 2.查 l1 = ['jason', 'tony', 11, 22, 'jerry'] print(l1) # ['jason', 'tony', 11, 22, 'jerry'] print(l1[0]) # jason print(l1[1:4]) # ['tony', 11, 22] ''' 可以查看列表所有的值 也可以靠索引查看数据值 也可以按切片方法查看 '''
5.index
# 1.意思 查看指定的数据对应的索引值 # 2.用法 l1 = ['jason', 'tony', 11, 22, 'jerry'] print(l1.index('tony')) # 1 """就是查看'tony'在列表l1中的索引是多少"""
6.sort
# 1.意思 排序 # 2.用法 l1 = [1, 2, 6, 5, 5, 6, 2, 56, 3, 5, 6] l1.sort() print(l1) # [1, 2, 2, 3, 5, 5, 5, 6, 6, 6, 56] l1.sort(reverse = True) print(l1) # [56, 6, 6, 6, 5, 5, 5, 3, 2, 2, 1] ''' sort括号内不写默认升序 sort括号内些了reverse = True 说明翻转为真 变为降序 '''
7.reverse
# 1.意思 翻转 # 2.用法 l1 = ['jason', 'kevin', 'oscar', 'jerry', 'tony', 'owen'] l1.reverse() print(l1) # ['owen', 'tony', 'jerry', 'oscar', 'kevin', 'jason'] '''就是把列表前后颠倒'''
8.count
# 1.意思 统计指定数据的个数 # 2.用法 l1 = ['jason', 'tony', 11, 22, 'jerry', 'jason', 'jason', 'jason'] print(l1.count('jason')) # 4 """就是查看'jason'在列表中有多少个"""
9.关系运算
l1 = [9, 8, 7] l2 = [1, 2, 3, 4, 5] print(l1 > l2) # True 是按位置顺序一一比较 l1 = ['a', 8, 7] l2 = [1, 2, 3, 4, 5] print(l1 > l2) # 报错 不同数据类型不能做比较 l1 = ['a', 8, 7] # a对应的是97 l2 = ['A', 2, 3, 4, 5] # A对应的是65 print(l1 > l2) # True 字母会有对应的ASCII码做比较 l1 = ['我', 8, 7] l2 = ['你', 2, 3, 4, 5] print(l1 > l2) # True 中文的也有对应的字符编码
字典的内置方法
1.字典的类型转换
# 类型转换 print(dict([('name', 'jason'), ('pwd', 123)])) # {'name': 'jason', 'pwd': 123} print(dict(name='jason', pwd=123)) # {'name': 'jason', 'pwd': 123} '''字典很少涉及到类型转换 都是直接定义使用'''
2.字典的取值操作
d = { 'name': 'tony', 'age': 18, 'hobby': 'run' } 1.直接按k取值 print(d['name']) # tony print(d['xxx']) # 报错 k不存在会直接报错 2.get print(d.get('name')) # tony print(d.get('xxx')) # None k不存在不会报错 会返回None print(d.get('name', '键不存在返回的值 默认返回None')) # tony print(d.get('xxx', '键不存在返回的值 默认返回None')) # 键不存在返回的值 默认返回None ''' get取值时如果只写k 那么就算k不存在也不会报错 如果get里后面写了k和另外一个参数 那么k存在就会取k对应的v k不存在就会返回后面那个参数 如果get只写了k默认返回None '''
3.len
len就是计算字典里有多少对键值对 d = { 'name': 'tony', 'age': 18, 'hobby': 'run' } print(len(d)) # 3
4.修改与新增
d = { 'name': 'tony', 'age': 18, 'hobby': 'run' } d['name'] = 'jason' # 键存在就是修改k对应的值 print(d) # {'name': 'jason', 'age': 18, 'hobby': 'run'} d['addr'] = '上海' # 键不存在就是新增一对键值对 print(d) # {'name': 'jason', 'age': 18, 'hobby': 'run', 'addr': '上海'}
5.删除键值对
d = { 'name': 'tony', 'age': 18, 'hobby': 'run' } # 1.直接删除 del d['name'] print(d) # {'age': 18, 'hobby': 'run'} 直接删除 # 2.弹出删除 res = d.pop('name') print(d, res) # {'age': 18, 'hobby': 'run'} tony 跟列表一样删除的时候还可以调用一下 然后在删除 # 3.随机删除 d.popitem() print(d) # {'name': 'tony', 'age': 18} 随机删除一对键值对 # pycharm优化了popitem让它删除末尾的数
6.快速获取k、 v 、kv键值对
1.快速获取键(k) d = { 'name': 'tony', 'age': 18, 'hobby': 'run' } print(d.keys()) # dict_keys(['name', 'age', 'hobby']) '''会单独提取出所有的键(k) 可以看作是元祖套列表''' print(d.values()) # dict_values(['tony', 18, 'run']) '''会单独提取出所有的值(v) 也可以看作是元祖套列表''' print(d.items()) # dict_items([('name', 'tony'), ('age', 18), ('hobby', 'run')]) '''会提取出所有的键值对 可以看作是列表套元祖'''
7.更新键值对
d = { 'name': 'tony', 'age': 18, 'hobby': 'run' } d.update({'name': 'jason'}) print(d) # {'name': 'jason', 'age': 18, 'hobby': 'run'} d.update({'gender': 'male'}) print(d) # {'name': 'jason', 'age': 18, 'hobby': 'run', 'gender': 'male'} '''键存在则修改值 键不存在则新增'''
8.快速构造字典
res = dict.fromkeys([1,2,3],None) print(res) # {1: None, 2: None, 3: None} ''' 它是让第一个参数中所有的值当字典的k 然后把后面的值绑定给前面的所有k所以所有k的值都是后面的参数 ''' new_dict = dict.fromkeys(['name', 'pwd', 'hobby'], []) new_dict['name'].append(123) new_dict['pwd'].append(123) new_dict['hobby'].append('read') print(new_dict) # {'name': [123, 123, 'read'], 'pwd': [123, 123, 'read'], 'hobby': [123, 123, 'read']} '''不管你是用哪个k来添加值 所有的v都会改变'''
9.setdefault
# 键存在则获取键对应的值 键不存在则设置 并返回设置的新值 d = { 'name': 'tony', 'age': 18, 'hobby': 'run' } res = d.setdefault('name', 'jasonNB') print(res, d) # tony {'name': 'tony', 'age': 18, 'hobby': 'run'} res1 = d.setdefault('xxx', 'jasonNB') print(res1, d) # jasonNB {'name': 'tony', 'age': 18, 'hobby': 'run', 'xxx': 'jasonNB'} '''就是如果键(k)存在就不会做改变 如果键不存在就会添加新的值'''
元祖的内置方法
1.元祖的类型转换
'''除了整数 浮点型 布尔值 其他的都可以转换为元祖 就是能支持for循环的都可以转换为元祖''' # 当元祖内只有一个数据值时 t = () i = (1) s = ('jason') l = ([1,2]) d = ({'name':'tony'}) print(type(t)) # tuple print(type(i)) # int print(type(s)) # str print(type(l)) # list print(type(d)) # dict ''' 当元祖内只有一个数据值时数据类型是不会变成元祖的 输入什么数据类型还是什么类型 必须要在数据值后面加一个逗号 ''' t = () i = (1,) s = ('jason',) l = ([1,2],) d = ({'name':'tony'},) print(type(t)) # tuple print(type(i)) # tuple print(type(s)) # tuple print(type(l)) # tuple print(type(d)) # tuple '''所以以后编写可以存放多个数据类型的时候里面只有一个数据时都要加上逗号'''
2.索引取值
t = (1, 2, 3, 4, 5, 6, 7) print(t[0]) # 1 print(t[-1]) # 7 '''元祖索引支持正向取值 也可以负向取值''' print(t[1:5]) # (2, 3, 4, 5) '''也支持切片操作(顾头不顾尾)''' print(t[0:5:2]) # (1, 3, 5) '''也支持分隔操作(顾头不顾尾)'''
3.增删改查操作
t = (1, 2, 3, 4, 5, 6, 7) print(t) # (1, 2, 3, 4, 5, 6, 7) print(t[0]) # 1 t[0] = 10 print(t) # 报错因为元祖不能修改 '''元祖不能修改绑定好的内存地址 元祖只能看 不能改''' t1 = (11, 22, 33, [11, 22]) t1[-1].append(1) print(t1) # (11, 22, 33, [11, 22, 1]) '''因为列表是可变类型修改列表内的值时不会改变列表的内存地址''' # 所以当定义好了一个元祖之后 就不能再修改删除添加元祖了 只能查看
集合的内置方法
1.集合的类型转换
1.类型的转换
支持for循环 并且数据类型是不可变类型
定义空集合必须是要用关键字set
集合内的数据必须是不可变类型(整型、浮点型、字符串、元祖、布尔值)
2.集合去重方法
# 去重 s1 = {1, 1, 2, 3, 2, 1, 4, 5, 4, 5, 6, 3, 2, 54, 1, 2, 6, 5, 4, 1, 25, 45, 122} print(s1) # {1, 2, 3, 4, 5, 6, 45, 54, 25, 122} '''可以把集合内的值去重把重复的值去掉只留下一个值''' l1 = ['jason', 'jason', 'tony', 'oscar', 'tony', 'oscar', 'jason'] s2 = set(l1) l1 = list(s2) print(l1) # ['tony', 'oscar', 'jason'] '''列表取值可以先把列表转换为集合 集合会自动去重 然后把去重的值在转换为列表赋值回原来列表的名字'''
2.集合的关系运算
# 模拟两个人的好友集合 f1 = {'jason', 'tony', 'oscar', 'jerry'} f2 = {'kevin', 'jerry', 'jason', 'lili'} # 1.求两个人的共同好友 print(f1 & f2) # {'jason', 'jerry'} # 2.求两个的所有好友 print(f1 | f2) # {'kevin', 'tony', 'lili', 'jason', 'jerry', 'oscar'} # 3.求f1独有的好友 print(f1 - f2) # {'oscar', 'tony'} 如果是求f2独有的好友: print(f2 - f1) # {'kevin', 'lili'} # 4.求两个不同的好友 print(f1 ^ f2) # {'lili', 'oscar', 'kevin', 'tony'} ''' & 求两个集合的共同值 | 求两个集合的所有值 - 求减号前面集合的独有的值 ^ 求两个集合不同的值 '''
可变于不可变类型
1.可变类型
# 值改变 内存地址可以不变 l1 = [11, 22, 33] print(id(l1)) # 1931283911552 l1.append(44) # [11, 22, 33, 44] print(id(l1)) # 1931283911552
2.不可变类型
# 值改变 内存地址肯定变 s1 = '$hello$' print(id(s1)) # 1624061428432 s1 = s1.strip('$') print(id(s1)) # 1624061428432 a = 666 print(id(ccc)) # 2888916433776 a = 990 print(id(ccc)) # 2888886496976
字符编码
1.字符编码的简介
首先要了解只有文本文件才有字符编码的概念
计算机在工作中只认识高低电平>>>1和0
可以把1和0组成许多的二进制数来表达不同的意思
计算机不认识我们人类的语言,所以我们人类定义了一个人类字符与数字的转换关系
而这些转换关系不能随便定义 所以就出现类字符编码表
2.字符编码的发展史
2.1一家独大
因为计算机是美国发明的,所以最初的字符编码只用于让计算机能够读懂英文即可 不能够支持中文和其他语言
美国发明的字符编码表叫ASCII表
一个英文字符用1bytes表示 1bytes等于8bit 8bit可以表示256个字符 而所有的英文字符只有127个 足够表示英文
2.2群雄割据
因为ASCII表只能表示英文不能够表示中文 所以我们中国的科学家们就发明了我们自己的字符编码 能够识别中文与英文 叫做GBK 内部存储中文用2bytes存储(生僻字用更多的字节)英文还是用1bytes表示
其他的国家也定义了他们国家的字符编码表比如韩国>>>euc_kr 日本>>>shift_jis
但是这个阶段会非常容易出现乱码
2.3天下一统
因为出现了很多字符编码,当我只用gbk编写一个文本文件然后用euc_kr打开时会识别不出来,就是会出现乱码
这时候就出现了万国码:能够兼容所有国家的字符
万国码内部统一用2bytes存储字符
这样它占用内存的空间就会变大,浪费空间,传输数据变慢
为了解决上述的问题就出现了utf家族
utf-8是现在比较流行的编码 它内部是按1bytes存储英文其他字符按3bytes存储
3.字符编码的应用
只有字符串能够参与编码与解码 其他数据类型只能先转换为字符串才能够参与编码解码
3.1 如何解决乱码
当初用什么编码就用什么解码
3.2 编码与解码
编码(人类的字符>>>计算机的字符)
编码其实就是把人类能够读懂的字符按指定编码装换成计算机能够读懂的字符
# encode # encode可以把人类能够读懂的字符按指定的编码转化为二进制数 s = 'jason 说我们是第一' res = s.encode('utf8') print(res) # b'jason \xe8\xaf\xb4\xe6\x88\x91\xe4\xbb\xac\xe6\x98\xaf\xe7\xac\xac\xe4\xb8\x80' '''在python中bytes的类型数据可以看成是二进制数'''
解码(计算机的字符>>>人类的字符)
解码其实就是把计算机能够读懂的字符按指定的编码解码成人类能够读懂的字符
s = 'jason 说我们是第一' # 编码 res = s.encode('utf8') print(res) # b'jason \xe8\xaf\xb4\xe6\x88\x91\xe4\xbb\xac\xe6\x98\xaf\xe7\xac\xac\xe4\xb8\x80' '''在python中bytes的类型数据可以看成是二进制数''' # 解码 # decode能够把计算机能欧读懂的字符按指定的字符解码成人类能够读懂的字符 res1 = res.decode('utf8') print(res1) # jason 说我们是第一 '''当你用某个字符编码时就要用同样的字符编码解码 要不然会报错'''
3.3 解释器层面
python2默认编码是ASCII码 python3默认utf8
而我们想要在python2中编写一些中文的文本信息的话我们需要在最上方写上文件头才行
1.文件头
# coding:utf8
2.定义字符串
需要在字符串的前面加u
垃圾回收机制
1.什么是垃圾回收机制
垃圾回收机制是python解释器自带的一种机制 它专门用来回收不用的变量值所占用的内存空间
2.为什么要有垃圾回收机制
程序运行过程中会想内存申请大量的内存空间来存储变量值 而有些变量值不用时不及时处理会超出内存溢出
导致程序崩盘 python自带了一种机制来管理这些不需要的变量值
3.垃圾回收机制的发展史
3.1引用计数
当我们定义一个变量时 数据值是会绑定到这个变量名 这个时候数据值就会有一个引用计数 数据值被绑定几次引用计数就是几个
当引用计数为零的时候 垃圾回收机制就会把这些引用计数为零的数据值回收
name = 'tony' # 'tony'引用计数就为1 name1 = name # 'tony'引用计数就会加一变为2 del name1 # 'tony'引用计数就会减1变为1
当一个数据值引用计数不为0时 就不会有影响
但是当引用计数为0时 该数据值就会被垃圾回收机制回收
就不会占用着内存
不过引用计数会出现一个bug>>>循环引用
循环引用会一直标记着这个数据值使这个数据一直有引用计数让垃圾回收机制回收不了
3.2标记清除
循环引用:
l1 = [1, 2, 3] # 引用计数加一 1
l2 = [7, 8, 9] # 引用计数加一 1
l1.append(l2) # 引用计数加一 2
l2.append(l1) # 引用计数加一 2
del l1 # 引用计数减一 1
del l2 # 引用计数减一 1
'''
现在l1和l2已被删除 我们已经不需要它们的数据值了
但是现在它们的数据值还在互相调用对方的数据值 使它们的引用计数一直还是1
使垃圾回收机制回收不了
'''
专门针对这个循环引用
内存会将程序中产生的所有数据值全部都检查一遍
然后将这些循环引用给标记上 然后一次性清除
3.3分代回收
标记清除每隔一段时间就会将所有数据检查一遍 这样就会太浪费资源了
为了减轻垃圾回收机制的资源损耗 开发了三个管理
越往下检测的频率越低
文件操作
1.一般我们操作文件都是通过鼠标来操作文件 但是我们可以通过代码的方式也可以操作文件
2.双击文件图标其实是从硬盘加载数据到内存
写文件之后保存其实就是将内存中的数据刷到硬盘
文件其实是操作系统暴露给用户操作计算机硬盘的快捷方式之一
3.代码操作文件
# 关键字 open # 语法结构 open(文件路径,读写模式,字符编码) # 当我们打开一个文件必然还需要关闭文件 所以我们还需要在open下面加上close() eg: f = open() f.close() # 其实close()写不写都行但是如果不写万一文件打开过多很容易把电脑变卡 # 所以有了另一个写法 with open(文件路径,读写模式,字符编码) as f: 子代码 # 子代码运行完之后会自动调用close() as是关键字 f是变量名
文件的读写模式
1.r模式
r模式 只读模式 是open默认的模式
在r模式的转态下打开文件下只能读 不能进行其他相关操作(写)
# 在有文件路径下打开文件 r模式不会报错 with open(r'b.txt', 'r', encoding='utf8') as f: print(f.read()) print(f.write()) # 会报错 因为r模式只能读不能写 # 在没有文件路径下打开文件 r模式会直接报错 with open(r'c.txt', 'r', encoding='utf8') as f: print(f.read()) # 如果你只写了文件目录没有写后面的参数open默认你写了r模式 with open(r'b.txt') as f1: print(f1.read())
2.w模式
w模式 只写模式
在w模式转态下打开文件下只能写 不能进行其他相关操作(读)
# 在有文件路径下打开文件 w模式不会报错 info = 'python ON.1' with open(r'b.txt', 'w', encoding='utf8') as f: print(f.write(info)) # 还能够计算文件中有多少个字符 print(f.read()) # 会报错 因为w模式只能写不能读 # 在没有文件路径下打开文件 w模式不会报错会直接在当前py文件下创建你文件的名字 with open(r'c.txt', 'w', encoding='utf8') as f: print(f.write(info)) ''' w写文件时它会先把文件内容里的所有数据清除然后在编写你写进去的程序 所以你不管运行多少次 文件里只有你程序最后运行的结果的数据 '''
3.a模式
a模式 只追加模式
在a模式下打开文件下默认在末尾追加内容 不能进行其他相关操作(读)
# 在有文件路径下打开文件 w模式不会报错 info = 'python ON.1\n' with open(r'b.txt', 'a', encoding='utf8') as f: print(f.write(info)) print(f.read()) # 会报错 因为a模式只能写不能读 # 在没有文件路径下打开文件 a模式也不会报错会直接在当前py文件下创建你文件的名字 with open(r'd.txt', 'a', encoding='utf8') as f: print(f.write(info)) ''' a模式写入文件时它不会清除文件里的内容 会直接在文件尾部添加数据 '''
4.+模式
+模式 就是可读可写
可以与上面三种联合用 r+、w+、a+、rb+、wb+、ab+
r+和rb+其实是跟r与rb的特性是一样的 只不过它可以既可以读也可以写
w+和wb+也跟w与wb的特性一样 只不过它也可以写也可以读
a+和ab+也跟a与ab的特性是一样 也是在文件末尾添加新值和读取文件
只不过如果不加b的模式只能操作文本文件 带b是操作二进制模式
with open(r'a.txt', 'a+', encoding='utf8') as f: res1 = f.write('tony|123\n') print(res1) res2 = f.read() print(res2) # +就是能在子代码中能够既读也可以写
文件的操作模式
文件的操作模式主要分为两种 t、b 默认t
1.t模式
t模式其实就是文本模式
只能够操作文本文件 文件操作的默认模式
t模式下有三种 rt、wt、at
如果是操作文本文件的话是要在t模式下操作的 可以简写为r、w、a
就是上面的三种文件读写模式 因为文件的操作默认的就是t模式所以可以简写
t模式:
1.只能操作文本文件 不能操作其他文件类型(视频文件、图片文件...)
2.必须要指定encoding参数
3.读写都是以字符串形式参与的
2.b模式
b模式其实就是二进制模式
文件内容都是以二进制进行操作的
b模式下有三种rb、wb、ab 这个不能简写
它能够操作所有类型文件
b模式:
1.能够操作所有类型的文件
2.不需要指定encoding参数
3.读写都是以bytes为单位(二进制数)
with open('111.jpeg', 'rb') as f1, open('222.jpeg', 'wb') as f2: f2.write(f1.read()) ''' 这个是个图片型文件 必须要用b模式因为t模式只能操作文本文件 这个意思就在先在打开111.jpeg文件然后读取 然后在打开222.jpeg文件 因为是w模式就会直接在当前.py文件下创建 然后在222.jpeg文件下写入从111.jpeg文件读取的内容 '''
文件的一些操作方式
read() # 可以一次性读取文件内的内容并且光标会停留在文件的末尾 如果继续读就会为空 '''当文件的数据过大时 不推荐使用 因为不管文件的大小read都是一次性读出来 有可能造成内存溢出''' for line in f: print(line) # for循环也是可以循环文件的可以把文件一行一行的循环出来 不会直接循环全部 write() # 写入内容 readline() # 一次只读取一行内容 readlines() # 按照行的方式读取所有内容然后组织成列表返回 readable() # 判断是否可读 writable() # 判断是否可写 writelines # 支持填写容器类型(内部可以存放多个数据值的数据类型)多个数据值 flush() # 将内存中的文件立刻刷到硬盘中(相当于按了Ctrl+s) '''这么多方法中只有前三个的方法是最重要的'''
文件内光标移动
1.read()的一些使用
read是可以在括号内存入参数的 意思是读取文件中几个字符或是字节
比如有个文件a.txt 里面就只写了 abc你好啊
with open(r'a.txt', 'r', encoding='utf8') as f: res = f.read(4) print(res) # abc你 # read()括号内是可以填写参数的 在文本模式下的单位是字符为单位 写几个就读出几个字 with open(r'a.txt', 'rb') as f: res = f.read(4) print(res) # b'abc\xe4' res1 = res.decode() # 因为读取二进制数的位数是4但是中文的字节为3个 # abc个有一个字节所以只有一个字节是读不出来中文的 # print(res1) # 报错 res = f.read(6) print(res) # b'abc\xe4\xbd\xa0' res1 = res.decode() print(res1) # abc你 # read()括号内是可以填写参数的 在二进制模式下的单位是bytes为单位 (英文是一个字节 中文是三个字节)
2.tell()关键字
还有一个可以获取光标移动了多少个字节
关键字时 tell() 获取光标移动的字节数
with open(r'a.txt', 'r',encoding='utf8')as f: res = f.read(4) print(res) # abc你 print(f.tell()) # 字节为单位 英文为一个字节中文为三个字节 所以为6 with open(r'a.txt', 'rb')as f: res = f.read(4) print(res) # b'abc\xe4' print(f.tell()) # 4 因为获取光标的单位本来就是二进制数 所以你输入啥就返回啥
3.seek()关键字
seek()可以控制光标的移动
# 关键字 seek() # seek(offset,whence) ''' offset : 控制光标移动的位移量(字节数) whence : 控制光标移动的模式 whence 有三种模式 0,1,2 0 基于文件的开头移动多少字节 1 基于光标当前所在的位置移动所少字节 2 基于文件的末尾移动多少字节 1和2只能在二进制模式使用 0在t和b中都可以使用 ''' with open(r'a.txt', 'r', encoding='utf8') as f: res = f.read(4) print(res) # abc你 # 现在光标在你这个字的后面 而如果还想读全部的话可以用关键字seek() f.seek(0, 0) print(f.read()) # abc你好啊 f.seek(6, 0) # 第一个数字就是控制光标往后几个字节开始读取内容 # 第二数字为模式0所以从文件的开头开始 # 是按字节来算的(英文一个字节 中文三个字节) print(f.read()) # 好啊 # f.seek(2,1) # 报错 print(f.read()) with open(r'a.txt', 'rb') as f: res = f.read(3) print(res) # b'abc' res1 = res.decode() print(res1) # abc # 现在光标在c字母后面 # f.seek(3, 1) # 1模式就是在光标当前位置开始移动 # 3的意思让光标往右移动3个字节在打印 # 因为3个字节刚好是一个中文刚好跳过你这个中文 # print(f.read().decode('utf8')) # 好啊 f.seek(-3, 1) # 控制看光标移动的还可以写负数控制方向 # -3的意思是让光标往左边移动3个字节在读取内容 print(f.read().decode('utf8')) # abc你好啊 f.seek(-3, 2) # 2模式是让光标跳到末尾开始移动光标 # -3的意思让光标往走移动三个字节然后在读取内容 print(f.read().decode('utf8')) # 啊
文件内修改数据的操作
机械硬盘存储数据的原理:
数据的修改其实就是在机械硬盘上原来的存储的去掉在原来的地方刻上修改后的内容
数据的删除其实就是在机械硬盘上把占有态把它改为自由态 自由态就可以重新存储数据
代码修改文件的方式
1.覆盖写
先读取文件内容到内存 在内存中完成修改 之后w模式打开该文件写入
2.重命名
先读取文件内容到内存 在内存中完成修改 之后保存到另外一个文件中
再将原文件删除 将新的文件重命名为原文件
# 覆盖写 with open(r'a.txt', 'r', encoding='utf8')as f: data = f.read() # 把内容提取出来 new_data = data.replace('abc','cbd') # 利用replace方法把想要换掉的字符给替换掉 with open(r'a.txt','w',encoding='utf8')as f: f.write(new_data) # 在重新写入进去 ''' 优点:硬盘只占用一块空间 缺点:数据量较大的时候会造成内存溢出 ''' # 重命名 import os with open('demo.txt', 'r', encoding='utf8') as read_f, \ open('.demo.txt.swap', 'w', encoding='utf8') as wrife_f: for line in read_f: wrife_f.write(line.replace('cbd', 'abc')) os.remove('demo.txt') # 删除文件 os.rename('.demo.txt.swap', 'demo.txt') # 重命名文件 ''' 优点:不会造成内存溢出 缺点:有那么一段时间需要占用硬盘两个地方的空间(可能) 也可能是在内存中创建没有刷到硬盘 '''
函数
函数的本质
可以把函数理解成一个工具 我们需要用它时在用它不是不用就放那 也不会影响代码的运行
定义好的函数 以后可以无限的使用它
就比如现在要编写一个功能
我们可以提前定义一个函数编写 也可以不用函数编写
如果一个py文件下要使用多次这个功能如果不用函数编写的话 我们就要反复的编写这个代码这样就会大大降低我们编写代码的效率
而如果我们是把编写好的代码通过函数封装起来时 这样我就可以通过这个函数来调用这个功能 这样不管你需要多少次这个功能只要调用即可 不需要重新编写
主意:函数必须先定义 才可以调用
函数的定义(制造工具)
需要使用关键字 def
def func():
pass
函数的调用(使用工具)
只需要函数名加括号
func()
函数的语法结构
def 函数名(参数1,参数2): '''注释(简绍这个函数的使用)''' 函数体代码 return 返回值
1.def
def是定义函数的时候必须使用的关键字
2.函数名
相当于变量名 尽量做到见名知意
3.()
括号后面必须跟上冒号 :
4.参数
定义函数阶段可以在括号内填写参数(个数不固定),也可以不写
用于接收外界传递给函数代码内部的数据
5.注释
相当于一个工具的说明书 用于简绍函数的主题功能和具体用法
6.函数体代码
是整个函数的核心
7.return
控制函数的返回值
函数的定义和调用
1.函数必须先定义后调用
定义函数的代码必须是在调用函数的代码的上面
2.定义函数必须使用关键字def 调用函数使用函数名加括号(可能还需要添加额外的参数)
3.函数在定义阶段只检测函数体代码语法 不会执行函数体代码 定义的时候只要语法没有错整体代码都可以执行
只有在调用阶段吹真正的执行函数体代码
4.函数名的意思
函数名相当于变量名 只不过变量名是绑定的数据值的内存地址 函数名绑定的也是内存地址 而里面放的是函数体代码
想要运行改代码 就需要调用函数>>>:函数名加括号
主意:函数名加括号的优先级是最高的(定义阶段除外)
函数的分类
1.内置函数
解释器提前帮你定义号的函数 用户可以直接调用 eg:len()
内置函数可以直接调用 数据类型的内置方法其实也是函数
但是数据类型的内置方法必须使用数据类型的方式才可以调用
相当于是数据类型独有的一些内置方法
2.自定义函数
自定义函数可以分为 空函数、无参函数、有参函数
2.1.空函数
空函数就是函数体代码没有实际意义的函数
函数体代码使用pass顶替
主要用于前期的项目的搭建 提示主要功能
def func(): pass # 没有实际意义
2.2无参函数
函数定义阶段括号内没有填写参数
调用函数时就可以不用填写参数
def func(): print('form func') # 无参函数直接使用函数名加括号即可调用
2.3有参函数
有参函数就是在函数定义阶段在括号内填写参数
调用阶段必须在括号内填写参数
def func(x, y): print('from func') # 有参函数调用函数需要函数名加括号并且填写数据值
函数的返回值
返回值就是调用函数之后产生的结果 可有可无
获取函数的返回值的方式是固定的
变量名 = 函数()
如果有返回值则直接赋值给变量名 没有则默认接收None
1.函数体代码内没有return关键字
def func(): print('from func') res = func() # 执行函数体代码 并把返回值赋值给res print(res) # None # 因为函数体代码没有编写所以默认返回None
2.函数体内有renturn 后面没写数据值
def func(): print('from func') return res = func() # 执行函数体代码 并把返回值赋值给res print(res) # 因为return后面没有写 所以也会是返回None # renturn后面没有写的话默认返回None
3.函数体代码内有return 后面写了数据值
def func(): print('from func') return 123 res = func() # 执行函数体代码并且把返回值赋值给res print(res) # 因为return后面写了数据 就会打印123 # 如果return后面写了变量名 def func(): print('from func') name = 'tony' return name res = func() # 执行函数体代码并且把返回值赋值给res print(res) # 因为return后面写了数据 就会打印'tony' ''' return 后面如果写了数据那么些什么就会返回什么 如果是返回了变量名那就回找到变量名绑定的值并返回 '''
4.return后面写了多个数据值
# 第一种情况 def func(); print('from func') return 1, 2, 3, 4 # 多个数据值使用逗号隔开 res = func() # 执行函数体代码并且把返回值赋值给res print(res) # 如果是多个数据值那么就会组织成元祖并返回 (1, 2, 3, 4) # 如果return后面是多个数据值 默认情况下会组织成元祖返回 # 第二种情况 def func(); print('from func') return [1, 2, 3, 4] res = func() # 执行函数体代码并且把返回值赋值给res print(res) # 如果是列表那么就会返回列表 [1, 2, 3, 4] # 列表、字典、元祖、集合都是一样的 # 第三种情况 def func(): print('from func') return [1, 2, 3, 4], {'a' : 1, 'b' : 2}, 12 res = func() # 执行函数体代码并且把返回值赋值给res print(res) # 如果是混合写人也会是返回元祖 ([1, 2, 3, 4], {'a': 1, 'b': 2}, 12) # 不管return后面写多少个值只要是逗号隔开 那么就会组织成元祖返回 数据值按逗号隔开
5.函数体代码遇到return会直接结束函数运行
def func(): print('我在return上面') # 会执行这行代码 return 123 print('我在return下面') # 因为这行代码的上方就是return关键字不会执行这行代码 func() # 函数体代码只要遇到return关键字就会直接结束运行 不管你下方有多少行代码都不会运行
函数的参数
参数有两大类>>>:形式参数 实际参数
1.形式参数
函数在定义阶段括号内填写的参数 简称为'形参'
2.实际参数
函数在调用阶段括号内填写的参数 简称为'实参'
形参与实参的关系
形参相当于变量名
实参相当于数据值
在函数调用阶段形参会临时与实参进行绑定 函数运行结束就会立刻解除绑定>>>动态绑定 动态解除
def func(x, y): print(x, y) func(1, 2) ''' 1.首先定义一个func()函数括号内有两个形参 2.然后调用函数 这个时候x就会临时与1绑定 y也会临时与2绑定 3.执行函数体代码 这样就会打印 1,2 4.执行完函数后x,y就会与1和2解除绑定 '''
1.位置形参
位置参数有两种 位置形参与位置实参
1.位置形参
在函数定义阶段括号内从左往右依次填写的变量名称之为位置形参
2.位置实参
在函数调用阶段括号内从左往右依次填写的数据值称之为位置实参
def func(x, y): # x和y就是位置形参 print(x, y) name1 = 'tony' name2 = 'jason' func(name1, name2) # tony jason 实参可以是绑定了数据值的变量名 func(1, 2) # 1,2就是位置实参 # func(1) # 报错 # func(1, 2, 3) # 报错 ''' 当你位置形参只有两个时 那么你实参就必须传两个即可 传多传少多会报错 两者必须匹配 '''
2.关键字参数
关键字参数只有关键字实参
关键字参数就是在调用阶段括号内以什么等于什么的形式传值 称之为关键字实参
关键字实参
1.指名道姓的给形参传值(打破了位置的限制)
2.位置实参必须才关键字实参的前面
小诀窍:无论是形参还是实参 都遵守短的在前面 长的在后面
3.通过一个形参在一次调用中只能传一次值
def func(x, y): # x和y就是位置形参 print(x, y) func(1, 2) # 1,2 func(y=3, x=4) # 4 3 # 可以先写y的值 再写x的值 # func(y=1, 2) # 报错 # func(x=1, 2) # 报错 # func(99999, x=1) # 报错 x只能赋值一次 func(2, y=1) # 2,1 # func(x=1,y=3,z=3) # 报错 ''' 1.首先你的位置实参必须在关键字实参前面 2.关键字实参可以改变位置 3.每个形参调用是只能赋值一次 4.可以先写位置实参 但是后面的关键字实参只能赋值给后面那个形参 5.形参的数量决定了关键字的数量这是不变的 '''
3.默认值参数
默认值参数只有默认值形参
默认值形参就是在定义阶段括号内以什么等于什么的形式填写的形参称之为默认值形参
调用的时候可以改也可以不用改
def register(name, age, gender='male'): print(name) print(age) print(gender) register('jason', 18) # jason 18 male register('oscar', 28) # oscar 28 male register('jerry', 38) # jerry 38 ,ale register('lili', 18, 'female') # lili 18 female ''' 默认形参就是提前赋值后了参数 后续如果调用该函数时可以不用写改形参对应的实参 不过也可以自己定义该位置的实参 该位置形参就会临时绑定该位置的实参 不过还是要遵循前面总结的规律(简单的左边 复杂的在右边) '''
4.可变长参数
可变长参数只有可变长形参
可以打破形参与实参的个数限制 随意传值
# 第一种 * def func1(*x): print(x) func1() # () 因为函数中没有形参所以不会报错 func1(1, 2, 3) # (1, 2, 3) func(x=1, y=2) # 报错 因为它只能接收位置实参 func(1,y=1) # 报错 ''' *在形参中的作用 接收多余的位置参数然后组织成元祖形式赋值给*号后面的变量名 ''' def func2(a,*x): print(a,x) func2() # 报错 因为函数中有一个位置形参 所以必须传入一个实参才可以 func2(1) # 1 () func2(1,2) # 1 (2,) func2(1,2,3,4) # 1 (2, 3, 4) # 因为位置形参就一个所以是需要一个位置实参足以 其他的位置实参就会组织成元祖赋值给x # 第二种情况 ** def func1(**x): print(x) func1(1) # 报错 因为这个只能接收位置实参func1(1,2,3) # 报错 func1() # {} func1(name=1,name2=2) # {'name': 1, 'name2': 2} func1(name1=1,name2=2,name=3) # {'name1': 1, 'name2': 2, 'name': 3} ''' **在形参中的作用 接收多余的关键字参数然后组织成字典赋值给**号后面的变量名 ''' def func2(a, **b): print(a, b) func2() # 报错 func2(1) # 1 {} func2(name=1,name2=2) # 报错 因为函数内有一个形参必须先填写一个实参才行 func2(a=1,1,2,3) # 报错 因为位置实参必须在关键字实参前面 func2(1, name1=2, name2=3) # 1 {'name1': 2, 'name2': 3} func2(a=1, name1=2, name2=3) # 1 {'name1': 2, 'name2': 3}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现