【周报】初用函数
上周回顾
基本数据类型
整型 int
浮点型 float
字符串 str
布尔值 bool
列表 list
字典 dict
元组 tuple
集合 set
与用户交互
输入 input()
输出 print()
格式化输出
占位符
format()
运算符
逻辑运算符
成员运算符
身份运算符
流程控制
流程控制理论
if
while
for
数据类型内置方法·上
整型
浮点型
字符串
# 索引取值相关
s1 = 'hello'
print(s1[2]) # l
print(s1[0:3]) # hel
print(s1[3:0:-1]) # lle
print(s1[-3:0:-1]) # le
print(s1[::2]) # hlo
# 替换 replace()
s1 = 'hello'
print(s1.replace('l', o)) # heooo
# 去除首尾指定字符 strip()
s1 = '$hello$$'
print(s1.strip('$')) # hello
print(s1.rstrip('$')) # $hello 右清除
print(s1.lstrip('$')) # hello$$ 左清除
s2 = ' h ello '
print(s1.strip()) # h ello 默认去除首尾空格
# 按指定字符切割 split()
s1 = 'jason|123'
print(s1.split('|')) # ['jason', '123']
# 大小写 upper() lower()
s1 = 'JaSon'
print(s1.upper(), s1.lower()) # JASON jason
# 判断大小写 isupper() islower()
s1 = 'JaSON'
s2 = 'jason'
S3 = 'JASON'
print(s1.isupper(), s1.islower()) # False False
print(s2.islower(), s3.isupper()) # True True
# 判断是否以指定字符为开头/结尾 startswith() endswith()
s1 = 'hello'
print(s1.startswith('h'), s1.endswith('lo')) # True True
# 计算字符出现次数 count()
s1 = 'hello'
print(s1.count('e'), s1.count('l')) # 1 2
# 计算字符长度 len()
s1 = 'hello'
s2 = 'hello world'
print(len(s1)) # 5
print(len(s2)) # 11
# 字符串拼接 join() +
s1 = 'heelo'
s2 = 'world'
print(s1 + ',' + s2) # hello,world
print(','.join((s1, s2))) # hello,world
布尔值
本周回顾
概要
数据类型内置方法·下
垃圾回收机制
字符编码
文件操控
函数
数据类型内置方法·下
列表
# 索引取值相关
# 统计数据值个数 len()
l1 = [1, 2, 3, 4, 5]
print(len(l1)) # 5
# 添加数据 append() insert() extent()
# 尾部追加数据 appen()
l1 = [1, 2, 3, 4, 5]
l1.append(4)
print(l1, l1.append(4)) # [1, 2, 3, 4, 5, 4] None
# 列表属于可变类型 调用内置方法时修改的是本身而不会产生新的值
# 任意位置插入 insert()
l1 = [1, 2, 3, 4, 5]
l1.insert(4, 2)
print(l1) # 1, 2, 3, 4, 2, 5
# 尾部追加列表 extent()
l1 = [1, 2, 3, 4]
l2 = [2, 3, 4, 5]
l1.extend(l2)
print(l1) # [1, 2, 3, 4, 2, 3, 4, 5]
# 删除数据 del remove() pop()
# del 通用删除方法
l1 = [1, 2, 3, 4]
l2 = ['jason', 2, 3]
del l1[2]
del l2[0]
print(l1) # [1, 2, 4]
print(l2) # [2, 3]
# remove() 指定删除
l1 = [1, 2, 3, 4]
l2 = ['jason', 2, 3]
l1.remove(2)
l2.remove('jason')
print(l1) # [1, 3 4]
print(l2) # [2, 3]
# pop() 指定删除 但有返回值
l1 = [1, 2, 3, 4]
res = l1.pop(2)
print(l1, res) # [1, 3, 4] 2
# 查询数据值对应的索引值 index()
l1 = ['jason', 'tony', 'tom', 'jason']
print(l1.index('jason')) # 0 当有重复的值时 从左到右遇到第一个则停止
# 统计数据值出现的次数 count()
l1 = ['jason', 'jason', 'jason', 'tony']
print(l1.count('jason')) # 3
# 排序 sort() 默认为升序
l1 = [2, 1, 4, 5, 6, 9, 3, 7, 8]
l2 = l1
l3 = [2, 1, 4, 5, 6, 9, 3, 7, 8]
l1.sort()
print(l1) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(l2) # [1, 2, 3, 4, 5, 6, 7, 8, 9] l1 和 l2 指向同一个地址上的列表 所以修改一个 两个同时变化
l3.sort(reverse=True)
print(l3) # [9, 8, 7, 6, 5, 4, 3, 2, 1]
# 反转 reverse()
l1 = [1, 3, 5, 2, 4, 6]
l1.reverse()
print(l1) # [6, 4, 2, 5, 3, 1]
字典
# 增加数据
d1 = {'username': 'jason'}
d1['age'] = 18 # 键存在则修改值,键不存在则添加键值对
print(d1) # {'username': 'jason', 'age': 18}
# 删除数据 del pop() popitem()
# del 通用删除方法
d1 = {'username': 'jason', 'age': 18}
del d1['username']
print(d1) # {'age': 18}
# pop() 有返回值
d1 = {'username': 'jason', 'age':18}
res = d1.pop('username')
print(d1, res) # {'age': 18} jason pop()删除键值对会获取对应的值v
# popitem() 随机删除
# 修改数据 update()
d1 = {'username': 'jason', 'age': 18}
d1['username'] = 'tony' # 键存在则修改值,键不存在则添加键值对
print(d1) # {'username': 'tony', 'age': 18}
d1.update({'username': 'tony', 'hobby': 'read'})
print(d1) # {'username': 'tony', 'age': 18, 'hobby': 'read'} # 键存在则修改值,键不存在则添加键值对
# 快速获取键 值 键值对
d1 = {'username': 'jason', 'age': 18}
print(d1.values()) # dict_values(['jason', 18])
print(d1.keys()) # dict_keys(['username', 'age'])
print(d1.items()) # dict_items([('username', 'jason'), ('age', 18)])
# 返回值可用for循环取出
for i in d1.values():
print(i)
# 运行结果
# jason
# 18
# settledefault()
dict = {'username': 'jason', 'age': 18}
res = dict.setdefault('username', 'jasonNB')
print(dict, res) # {'username': 'jason', 'age': 18} jason
res = dict.setdefault('hobby', 'read')
print(dict, res) # {'username': 'jason', 'age': 18, 'hobby': 'read'} read
# 键存在则获取键对应的值 键不存在则设置 并返回设置的新值
元组
# 面试题
t1 = (1, 2, 3, 4, [1, 2])
t1[4].append(3) # 是可以执行的
print(t1) # (1, 2, 3, 4, [1, 2, 3]) 并且数值也修改了
# 这是因为列表是可变类型
# 元组每个数据都是绑定的地址值,当绑定的地址保存的是可变类型数据,通过内置方法修改该数据,元组内的数据就得到了修改
集合
# 去重
s1 = {1, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}
print(s1) # {1, 2, 3}
# 相关运算
s1 = {1, 2, 4, 6}
s2 = {1, 4, 5, 7}
print(s1 & s2) # {1, 4} # 取相同
print(s1 - s2) # {2, 6} # 取相异
print(s1 | s2) # {1, 2, 4, 5, 6, 7} # 取所有
print(s1 ^ s2) # {2, 5, 6, 7} # 取所有不相同
垃圾回收机制
python会自动清除和申请内存空间
引用计数
每次数据被引用就会计数一次
当数据值身上的引用次数不为0时 说明有运用 不会被删除
当数据值身上的引用次数为0时 则会被python垃圾回收机制回收
标记清除
专门用于解决循环引用的问题 将内存中程序产生的所有数据值全部检查一遍
是否存在循环引用打上标记 之后一次性清除
分代回收
标记清除每隔一段时间就需要将所有的数据排查一遍 资源消费过大
为了减轻垃圾回收机制的资源损耗 开发了三代管理,python将所有对象分为0,1,2三代。
所有新建对象都是0代,会根据数据的使用频率,使用次数来划分,越往上检测的概率越低
字符编码
字符编码简介
只有文本文件才有字符编码的概念
计算机内部读取数据的本质>>>:二进制数,计算机只认识 0 和 1
计算机并不能识别人类语言 而是人类通过制定了一套方法,让计算机能够通过这种方法来实现机器语言和人类语言的转换
而这套方法就是编码,转换关系不能随便更改 应该有统一的标准,字符编码表>>>:记录了人类的字符与数字的对应关系
字符编码发展史
一家独大(ASCII)>>> 群雄割据(GBK、Eur_kr、shift_JISK) >>> 天下一统 (unicode、utf)
字符编码实操
# 编码 encode()
s1 = '你好'
res = s1.encode('utf8')
print(res) # b'\xe4\xbd\xa0\xe5\xa5\xbd' 二进制数开头前有b 且utf8中一个中文占三个字节
# 解码 decode()
print(res.decode('utf8')) # 你好
# 注:用什么编码处理的数据,就用什么编码进行解码,否则极有可能出现乱码
文件操作
本质
用代码进行文件的自动操作
语法
# 方式一 open(文件名, 读写+操作模式, 字符编码)
f = open('a.txt', 'r', encoding='utf8')
print(f.read())
f.close() # 在这种方法下一定要执行 否则随着程序的进行 资源会占用的越来越多
# 方式二 推荐方法
with open('a.txt', 'r', encoding='utf8') as f:
print(f.read())
# 这种方法会自动执行.close()
补充内容
with可同时打开多个文件
with open('a.txt', 'r', encoding='utf8') as f1, open('b.txt', 'w', encoding='utf8') as f2:
f2.write(f1.read()) # 这种方法可以将f1中的内容写入f2中 但有缺陷 后面会讲解
python补全语法 pass ...
# 可以通过pass来补全语法 用于初始化程序时将功能框架框出来 再进行添加
if 1 >= 2:
pass
for i in range(8):
pass
读写模式·只读模式(r)
默认模式
在只读模式下,若文件路径不存在,则报错
若文件路径存在,可以通过read()来获取文件内的内容
# 文件a.txt内容如下
# 你好a你好a你a好a啊
with open('a.txt', 'r', encoding='utf8') as f:
print(f.read()) # 你好a你好a你a好a啊
读写模式·只写模式(w)
在只写模式下,若文件路径不存在,则会创建一个该路径的文件
若文件路径存在,可以通过write()来为文件注入内容
注:每次用w模式打开文件前会清空所有内容
# 文件a.txt内容如下
# 你好a你好a你a好a啊
with open('a.txt', 'w', encoding='utf8') as f:
f.write('你好')
# 运行后a.txt内容如下
# 你好
# 文件b.txt不存在
with open('b.txt', 'w', encoding='utf8') as f:
f.write('你好a')
# 运行后产生一个b.txt文件 文件内容如下
# 你好a
读写模式·只追加模式(a)
在只追加模式下,若文件路径不存在,则会创建一个该路径的文件
若文件路径存在,可以通过write()来为文件注入内容,默认在内容末尾注入
注:每次使用a方式打开文件 不会清空原有内容
# 文件a.txt内容如下
# 你好a你好a你a好a啊
with open('a.txt', 'a', encoding='utf8') as f:
f.write('你好')
# 运行后a.txt内容如下
# 你好a你好a你a好a啊你好
操作模式·文本模式(t)
默认模式
其实平时写的 r w a 可以看为 rt wt at
此操作模式下只能操作文本文件
必须指定encoding参数
读写都以字符为单位
操作模式·二进制模式(b)
在平时写的 r w a 后面加b rb wb at
此操作模式下可以操作任意类型文件
不用指定encoding参数
读写都以字节bytes为单位
文件多钟操作方法
read() 一次性读取全部内容 之后光标处于内容末尾 继续读则为空
readline() 只读一行 读完后光标处于下一行开头
readlines() 读取全部内容 将读取的内容以列表的形式返回
readable 判断可读性
write() 填写文本内容
writelines() 支持填写容器类型(如列表,字典等)数据
writable() 判断可写性
flush() 如同ctrl + s 手动保存文件
文件内光标的移动
read()内可以填写数字,rt模式下表示光标移动数字个字符,rb模式下表示光标移动数字个字节
# 文件a.txt的内容如下
# 你好a你好a你a好a
with open('a.txt', 'r', encoding='utf8') as f:
print(f.read(3)) # 你好a
print(f.read(4)) # 你好a你
"""
原先调用read()都认为就读取不到了
原来read()使从当前光标开始读取
读到目标位置 默认为读到底
而光标到内容末尾 当然没内容了
"""
with open('a.txt', 'rb') as f:
print(f.read(3)) # 你
print(f.read(4)) # 好a
# 在二进制模式中 文件操作是以字节为单位的
tell()可以计算当前光标与内容开始之间的距离
# 文件a.txt的内容如下
# 你好a你好a你a好a
with open('a.txt', 'r', encoding='utf8') as f:
f.read(3)
print(f.tell()) # 7 ??!!! 诶诶诶 为什么是7呢? 不是写了3吗 别着急
with open('a.txt', 'rb') as f:
f.read(3)
print(f.tell()) # 3 欸~这不就正常了 还记得b模式下是以什么为单位进行操作吗 啊对 字节
# 得出结论 tell()无论在t模式还是b模式下,都是计算光标距离开头间隔*字节*的个数
seek()可以指定光标位置
# seek(offset, whence) seek括号内可以传入两个值
# 第一个值表示位移量
# 第二个值表示移动初始位置 默认值为0 还有1 2
# 0表示从内容开头进行移动
# 1表示从当前光标进行移动
# 2表示从内容末尾开始移动
# 其中1和2只能在二进制模式下使用 0随意
# 文件a.txt的内容如下
# 你好a你好a你a好a
with open('a.txt', 'r', encoding='utf8') as f:
f.read(4)
print(f.tell()) # 10
f.seek(0) # 将光标指向0,第二个数值不写为0
print(f.tell()) # 0
f.seek(6)
print(f.tell()) # 6
print(f.read()) # a你好a你a好a啊 seek移动的位移量也以字节为单位
with open('a.txt', 'rb') as f:
f.seek(-3, 2)
print(f.tell()) # 22
f.seek(-3, 1)
print(f.tell()) # 19
f.seek(10, 1)
print(f.tell()) # 29
print(f.read()) # b'' 超出内容长度 无法读取内容
f.seek(-3, 0) # 报错 因为开头不能再往前了
文件修改
# 覆盖写
with open('a.txt', 'rb') as f:
data = f.read()
with open('a.txt'm 'wb') as f:
f.write(data)
"""
这种方法只占用一个磁盘空间,但操作大文件时会造成内存溢出
"""
# 重命名
with open('a.txt', 'rb') as f1, open('b.txt', 'wb') as f2:
for line in f1: # 通过for循环一次获取每一行的数据
f2.write(line)
# 然后删除a.txt 给b.txt重命名为a.txt
# 这种方法同一时间可能占用两个磁盘空间,但大幅度减少了内存溢出的概率
函数
简介
函数用于减少重复代码的编译量
函数与循环的关系
循环就是在相同的地方执行相同的代码
而函数时在不同的地方执行相同的代码
本质
函数可以看成是工具,提前制造(定义)好,然后反复使用(调用)
没有函数,那么做重复的工作时,就要当场手搓工具,而有了函数,就像备好了工具箱,需要时直接拿取
函数在调用前,一定要先定义,就像工具在使用前,一定要先造出来
# 函数的定义(提前准备工具的过程)
def func():
pass
# 函数的调用(使用工具的过程)
func()
函数的语法结构
结构代码
def 函数名(参数1, 参数2):
"""函数的注释"""
函数体代码块
return 返回值
结构分析
def:定义函数的关键字
函数名:与变量名的命名一致 尽量做到见名知意
def selecet_student(): # 得知是选择学生相关的函数
pass
括号:在定义函数时函数名后面必须跟括号
参数:定义函数可以在括号内写参数,也可以不写,参数用于接收外界传递给函数内部的数据
注释:类似说明书,用于接收函数的主体功能和具体用法
函数代码块:整个函数最核心的部位
return:控制函数的返回值,不写默认为 None
返回值:可以将指定的数据传出函数 不写默认为 None
函数的定义与调用
定义与调用的关系
函数必须先定义再调用,既定义的代码一定要在调用代码的上面
定义与调用的方法
通过def关键字进行定义,使用函数名加括号的方式进行调用
定义与调用逻辑
函数在定义阶段不会执行代码块代码,在调用时才会执行,在定义阶段只检测函数体代码语法
函数名解释
函数名绑定的是一块内存地址,里面存放了函数体代码
要想运行该代码 就需要调用函数>>>:函数名加括号
函数名加括号执行优先级最高(定义阶段除外)
函数的分类
内置函数
解释器提前定义好的函数,用户可以直接调用,如len()
内置函数可以直接调用,但数据类型的内置方法必须以数据类型.内置方法的方式才可以使用
既数据类型的独有方法
s1 = 'hello'
print(len(s1)) # 5 可以直接调用
print(s1.replace('l', 'o')) # heooo 需要数据类型.的形式
自定义函数
用户自己编写的函数,有可分为空函数、无参函数、有参函数三种
空函数
函数体代码用pass代替,暂时没有任何功能,主要用于前期的项目搭建,提示主要功能
# 钢铁侠项目
# 钢铁侠需要跑步这个功能
def run():
pass # 先不写 诶 就是玩(bushi 等搭建好框架后再逐步添加
# 钢铁侠需要飞行这个功能
def fly():
pass
# 钢铁侠需要贾维斯这个功能
def ai():
pass
无参函数
函数定义阶段括号内没有填写参数
def func(): # 括号内没有任何东西!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
'括号内没有东西???!!!哦原来是无参函数'
func() # 函数名() 调用 也同样括号内没有任何东西!
# 运行结果
# 括号内没有东西???!!!哦原来是无参函数
有参函数
函数定义阶段括号内有填写参数
def func(a, b): # 括号内有东西!
print(a, b)
func('啊啊啊啊啊啊啊这是参数一', '啊啊啊啊啊安安这是参数二') # 有参函数需要 调用函数时 输入 与定义函数括号内参数 相同数量 的参数
# 运行结果
# 啊啊啊啊啊啊啊这是参数一 啊啊啊啊啊安安这是参数二
函数的返回值
返回值的性质
返回值就是调用函数之后产生的结果,可有可无
通过以下方法获取函数返回值
变量名 = 函数名()
上述方法有返回值则返回返回值,没有则默认返回 None
情况1:无return关键字
函数体代码没有return关键字,默认返回None
def func():
pass
res = func()
print(res) # None
情况2:有return关键字但关键字后面没有数据值或表达式
函数体代码有return关键字,后面不写也返回None
def func():
return
res = func()
print(res) # None
情况3:有return关键字且关键字后面有单个数据值或变量名
return后面写什么返回值就返回什么
如果是数据值则直接返回,如果是变量则需要找到对应的数据值返回
def func(): # 数据值
return 123
res = func()
print(res) # 123
def func(): # 变量名
name = 'jason'
return name
res = func()
print(res) # jason
情况4:有return关键字且关键字后面有多个数据值或变量名
函数体代码有return关键字并且后面有多个数据值(名字)逗号隔开,默认情况下会自动组织称元组返回
def func():
return 1, 2, 3, 4, 5
res = func()
print(res) # (1, 2, 3, 4, 5) 默认以元组方式返回
return在函数体中的作用
函数体中只要执行return,直接结束函数体代码块的运行,类似循环中的break
def func():
print('我在return前面')
return
print('我在return后面')
func()
# 运行结果
# 我在return前面
函数的参数
参数的分类
函数的参数可分为形参和实参
形参是在函数定义阶段括号内的参数
实参是在函数调用阶段括号内的参数
def (形参1, 形参2, ...):
pass
func(实参1, 实参2, ...)
形参与实参的关系
形参相当于变量名 而实参就是数据值
在调用函数时 实参和形参临时绑定,函数结束时,立即解绑
位置参数
位置形参与位置实参定义
在函数定义阶段括号内从左往右依次填写的变量名,称之为位置形参
在函数调用阶段括号内从左往右依次填写的数据值,称之为位置实参
关键字参数
关键字传参定义
在函数调用阶段括号内以什么等于什么的形式传值称之为关键字传参
def func(a, b):
print(a, b)
func(b=1, a=2) # 关键字传参时 可以打破关键字之间的顺序
# 运行结果
# 2 1
"""
1.指名道姓的给形参传值(打破了位置的限制)
2.位置实参必须在关键字实参的前面
小诀窍:无论是形参还是实参 都遵循短(简单)的在前面 长(复杂的)的在后面
3.同一个形参在一次调用中 只能传一次值
"""
默认值形参
默认值形参定义
在函数定义阶段在括号内给参数设置默认值 通过什么=什么的形式
def func(a=2, b=1): # 其中a和b都设置了默认值
print(a, b)
func() # 因为都设置了默认值 所以可以不传参 使用函数内参数的默认值
# 运行结果
# 2 1
可变长参数
可变长参数的定义
可以打破形参与实参的个数限制,随意传值
def func(*args, **kwargs):
print('我可以接收所有数据')
"""其中*args表示接受所有多余的位置实参,**kwargs表示接收所有多余的关键字实参,args和kwargs才是变量名"""
func(1, 2, 3, a=123, b=1235, z=9)
# 运行结果
# 我可以接收所有数据
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!