垃圾回收机制与流程控制
今日内容详细
垃圾回收机制
什么是垃圾回收机制
垃圾回收机制(简称GC)是Python解释器自带一种机,专门用来回收不可用的变量值所占用的内存空间
为什么要用垃圾回收机制?
程序运行过程中会申请大量的内存空间,而对于一些无用的内存空间如果不及时清理的话会导致内存使用殆尽(内存溢出),导致程序崩溃,因此管理内存是一件重要且繁杂的事情,而python解释器自带的垃圾回收机制把程序员从繁杂的内存管理中解放出来。
"""
有一些语言 内存空间的申请和释放都需要程序员自己写代码才可以完成
但是python却不需要 通过垃圾回收机制自动管理
"""
垃圾回收机制原理分析
Python的GC模块主要运用了“引用计数”(reference counting)来跟踪和回收垃圾。在引用计数的基础上,还可以通过“标记-清除”(mark and sweep)解决容器对象可能产生的循环引用的问题,并且通过“分代回收”(generation collection)以空间换取时间的方式来进一步提高垃圾回收的效率。
1.引用计数
1.1引用计数算法原理
引用计数原理比较简单:
- 每个对象有一个整型的引用计数属性。用于记录对象被引用的次数。
- 例如对象A,如果有一个对象引用了A,则A的引用计数+1。
- 当引用删除时,A的引用计数-1。
- 当A的引用计数为0时,即表示对象A不可能再被使用,直接回收。
name = 'qyf' 数据值qyf身上的引用计数为1
name1 = name 数据值qyf身上的引用计数加1 为2
del name1 数据值qyf身上的引用计数减1 为1
当数据值身上的引用计数为0的时候 就会被垃圾回收机制当做垃圾回收掉
当数据值身上的引用计数不为0的时候 永远不会被垃圾回收机制回收
1.2 计数器增减条件
上面我们看到,创建一个A对象,并将对象赋值给a变量后,对象的引用计数器值为2。那么什么时候计数器会+1,什么时候计数器会-1呢?
1.2.1 引用计数+1的条件
- 对象被创建,如A()。
- 对象被引用,如a=A()。
- 对象作为函数的参数,如func(a)。
- 对象作为容器的元素,如arr=[a,a]。
1.2.2 引用计数-1的条件
- 对象被显式销毁,如del a。
- 变量重新赋予新的对象,例如a=0。
- 对象离开它的作用域,如func函数执行完毕时,func函数中的局部变量(全局变量不会)。
- 对象所在的容器被销毁,或从容器中删除对象。
2.标记清除
容器对象(比如:list,set,dict,class,instance)都可以包含对其他对象的引用,所以都可能产生循环引用。而“标记清除”计数就是为了解决循环引用的问题。
主要针对循环引用问题
l1 = [11, 22] # 引用计数为1
l2 = [33, 44] # 引用计数为1
l1.append(l2) # l1 = [11, 22, l2列表] 引用计数为2
l2.append(l1) # l2 = [33, 44, l1列表] 引用计数为2
del l1 # 断开变量名l1与列表的绑定关系 引用计数为1
del l2 # 断开变量名l2与列表的绑定关系 引用计数为1
当内存占用达到临界值的时候 程序会自动停止 然后扫描程序中所有的数据
并给只产生循环引用的数据打上标记 之后一次性清除
3.分代回收
分代回收的核心思想是:在历经多次扫描的情况下,都没有被回收的变量,gc机制就会认为,该变量是常用变量,gc对其扫描的频率会降低,具体实现原理如下:
分代指的是根据存活时间来为变量划分不同等级(也就是不同的代)
新定义的变量,放到新生代这个等级中,假设每隔1分钟扫描新生代一次,如果发现变量依然被引用,那么该对象的权重(权重本质就是个整数)加一,当变量的权重大于某个设定得值(假设为3),会将它移动到更高一级的青春代,青春代的gc扫描的频率低于新生代(扫描时间间隔更长),假设5分钟扫描青春代一次,这样每次gc需要扫描的变量的总个数就变少了,节省了扫描的总时间,接下来,青春代中的对象,也会以同样的方式被移动到老年代中。也就是等级(代)越高,被垃圾回收机制扫描的频率越低
流程控制
流程控制理论
流程控制>>>:控制事物的执行流程
事物执行流程总共可以分为三种
1.顺序结构
从上往下依次执行 我们之前所编写的代码都属于该结构
2.分支结构
事物的执行会根据条件的不同做出不同的执行策略
3.循环结构
事物的执行会根据某个条件出现重复
ps:在代码的世界里 很多时候可能会出现三者混合
流程控制必备知识
1.python中使用代码的缩进来表示代码的从属关系
从属关系:缩进的代码(子代码)是否执行取决于上面没有缩进的
2.并不是所有的代码都可以拥有缩进的代码(子代码)
if关键字
3.如果有多行子代码属于同一个父代码 那么这些子代码需要保证相同的缩进量
4.python中针对缩进量没有具体的要求 但是推荐使用四个空格(windows中tab键)
5.当某一行代码需要编写子代码的时候 那么这一行代码的结尾肯定需要冒号
6.相同缩进量的代码彼此之间平起平坐 按照顺序结构依次执行
流程控制之分支结构
1.单if分支结构
if 条件:
条件成立之后才会执行的代码块
ps:单if可以借助于流程图理解
username = input('username>>>:')
if username == 'jason':
print('老师好')
2.if...else...分支结构
if 条件:
条件成立之后执行的子代码
else:
条件不成立执行的子代码
username = input('username>>>:')
if username == 'jason':
print('老师好')
else:
print('去你妹的')
3.if...elif...else分支结构
if 条件1:
条件1成立之后执行的子代码
elif 条件2:
条件1不成立 条件2成立执行的子代码
elif 条件3:
条件1和2都不成立 条件3成立执行的子代码
else:
上述条件都不成立 执行的子代码
ps:中间的elif可以写多个、上述子代码永远只会走一个
score = input('请输入学生成绩>>>:')
score = int(score) # 将字符串的整数转换成整型的整数
if score >= 90:
print('优秀')
elif score >= 80:
print('良好')
elif score >= 70:
print('一般')
elif score >= 60:
print('及格')
else:
print('挂科 交钱重修')
4.if的嵌套使用
age = 28
height = 170
weight = 110
is_beautiful = True
is_success = False
username = 'tony'
if username == 'tony':
print('tony发现目标')
if age < 30 and height > 160 and weight < 150 and is_beautiful:
print('大妹纸 手机掏出来 让我加微信')
if is_success:
print('吃饭 看电影 天黑了...')
else:
print('去你妹的 流氓!!!')
else:
print('不好意思 认错人了')
else:
print('不是tony做不出来这件事')
流程控制之循环结构
就是想让一些代码反复的执行
while 条件:
条件成立之后执行的子代码(循环体代码)
1.先判断条件是否成立
2.如果成立则执行循环体代码
3.循环体代码执行完毕后再次回到条件判断处 判断条件是否成立
4.如果成立 则继续执行循环体代码
5.按照上述规律依次执行 直到条件不成立才会结束循环体代码的执行
count = 1 #计数为1
while count < 5: # 判断计数是否小于5 成立则执行循环体代码
print('hello world') # 打印出hello world
count += 1 # count = count + 1 # 计数加1后返回条件判断处 判断条件是否成立 直至条件不成立才结束循环体代码
print('想不想干饭?') # 当循环体代码结束后才打印出想不想干饭
break # 强行结束循环体
while循环体代码一旦执行到break会直接结束循环
continue # 直接跳到条件判断处
while循环体代码一旦执行到continue会结束本次循环 开始下一次循环
while 条件:
循环体代码
else:
循环体代码没有被强制结束的情况下 执行完毕就会执行else子代码
作业练习
1.根据用户输入内容打印其权限
'''
jason --> 超级管理员
tom --> 普通管理员
jack,rain --> 业务主管
其他 --> 普通用户
'''
# 1.获取用户输入的用户名
username = input('请输入您的用户名>>>:')
# 2.判断用户名 打印不同的提示>>>:不同的条件执行不同的代码 那么需要使用分支结构
if username == 'jason':
print('超级管理员')
elif username == 'tom':
print('普通管理员')
# elif username == 'jack' or 'rain': # 错误写法
# elif username == 'jack' or username == 'rain': # 正确写法
elif username in ['jack', 'rain']: # 正确写法
print('业务主管')
else:
print('普通用户')
2.编写用户登录程序
要求:有用户黑名单 如果用户名在黑名单内 则拒绝登录
eg:black_user_list = ['jason','kevin','tony']
如果用户名是黑名单以外的用户则允许登录(判断用户名和密码>>>:自定义)
eg: oscar 123
# 提前定义好黑名单用户
black_user_list = ['jerry', 'kevin', 'tony']
# 1.先获取用户输入的用户名和密码
username = input('请输入您的用户名>>>:')
# 3.先判断用户名是否是黑名单用户
if username in black_user_list:
print('您已经被拉黑了 无法消费')
else:
password = input('请输入您的密码>>>:')
# 2.判断用户名和密码是否正确
if username == 'jason' and password == '123':
print('登录成功 来宾一位')
else:
print('用户名或密码错误')
3.编写用户登录程序
用户如果登录失败 则只能尝试三次
用户如果登录成功 则直接结束程序
# 4.定义一个计数器
count_num = 1
while True:
# 6.先判断当前尝试了几次
if count_num == 4:
print('很抱歉 您已经尝试了三次')
break
# 1.获取用户数据
username = input('username>>>:')
password = input('password>>>:')
# 2.校验数据是否正确
if username == 'jason' and password == '123':
print('登录成功')
break # 3.结束循环体代码
else:
print('用户名或密码错误')
# 5.每错误一次就让计数器自增1
count_num += 1
# 4.猜年龄的游戏
# 假设用户的真实年龄是18 编写一个猜年龄的游戏 获取用户猜测的年龄
# 基本要求:可以无限制猜测 每次猜错给出提示(猜大了 猜小了) 猜对则结束程序
# 拔高练习:每次猜测只有三次机会 一旦用完则提示用户是否继续尝试 用户通过输入n或者y来表示是否继续尝试 如果是y则继续给用户三次猜测机会 否则结束程序
# 1.先定义用户的真实年龄
real_age = 18
# 8.定义计数器
count_num = 1
# 6.添加循环结构
while True:
# 10.判断当前尝试的次数
if count_num == 4:
choice = input('您已经尝试了三次 是否继续尝试(n/y)>>>:')
# 11.判断用户输入的选择
if choice == 'y':
# 12.重置计数器
count_num = 1
else:
print('下次再来玩哟')
break
# 2.获取用户猜测的年龄
guess_age = input('你猜一猜我的年龄 好不好呀>>>:')
# 3.由于一会儿需要比较大小 所以要将用户输入的字符串年龄转成整型的年龄
guess_age = int(guess_age) # 有小bug 暂时不考虑
# 4.判断年龄是否猜测正确
if guess_age > real_age:
print('你这小伙子 真讨厌 人家有那么大吗')
# 猜测错了 计时器加一
count_num += 1
elif guess_age < real_age:
print('哎呀 你真讨厌 人家也没那么小啦')
# 猜测错了 计时器加一
count_num += 1
else:
print('你真棒 猜对了 嘿嘿嘿')
# 7.猜对了 直接结束循环
break
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性