【python基础】第12回 垃圾回收机制和字符编码
本章内容概要
1.垃圾回收机制(理论)
2.字符编码概述(理论)
3.字符编码相关操作
4.代码操作文件
本章内容详解
1.垃圾回收机制(理论)
1.1 什么是垃圾回收进制?
垃圾回收机制(简称GC)是Python 解释器自带一种机,专门用来回收不可用的变量值所占用的内存空间
1.2 为什么要有垃圾回收进制?
程序运行过程中会申请大量的内存空间,而对于一些无用的内存空间如果不及时清理的话会导致内存使用殆尽(内存溢出),导致程序崩溃,因此管理内存是一件重要且繁杂的事情,而python解释器自带的垃圾回收机制把程序员从繁杂的内存管理中解放出来。
1.3 垃圾回收机制原理分析
Python的GC模块主要运用了“引用计数”(reference counting)来跟踪和回收垃圾。在引用计数的基础上,还可以通过“标记-清除”(mark and sweep)解决容器对象可能产生的循环引用的问题,并且通过“分代回收”(generation collection)以空间换取时间的方式来进一步提高垃圾回收的效率。
1.4 引用计数
当数据值身上的引用计数不为0表示该数据值还有用 不会被删
当数据值身上的引用计数为0则会被垃圾回收机制回收
name = 'jason' # 数据值jason身上的引用计数就是1 name1 = name # 数据值jason身上的引用计数就是2 del name1 # 数据值jason身上的引用计数变为1
’引用计数存在一个坑>>>;循环引用
1.5 标记清除
专门用于解决循环引用的问题 将内存中程序产生的所有数据值全部检查一遍、
是否存在循环引用打上标记 之后一次性清楚
# 循环引用
l1 = ['jason',] l2 = ['kevin',] l1.append(l2) # 引用计数为2 l2.append(l1) # 引用计数为2
print(l1)
print(l2)
del l1 # 解除变量名l1与列表的绑定关系 列表引用计数减一 del l2 # 解除变量名l2与列表的绑定关系 列表引用计数减一
1.6 分代回收
标记清楚每隔一段时间就需要将所有的数据排查一遍 资源消耗过大
为了减轻垃圾回收机制的资源损耗 开发了三代管理
越往下检测的频率越低!!!
2.字符编码概述(理论)
2.1字符编码简介
1.只有文本文件才有字符编码的概念
2.计算机内内部存取数据的本质>>二进制,计算机其实只认识0和1
3.为什么我们在使用计算机的时候可以随意敲出各国文字,肯定存在一个人类字符与数字的装换关系
4.装换关系不能随便更改 应该有统一的标准 字符编码表>>>:记录了人类的字符与数字的对应关系
2.2字符编码发展史
1.一家独大
计算机是有美国人发明的 美国人需要让计算机识别英文字符
英文所有的字符加起来不超过127个(2的七次方)但是美国人考虑到后续可能出现的新的字符,所以加了一位以备不时之需(2的八次方)
ASCII码:内部只记录了英文字符与数字的对应关系(1bytes来存储字符)
A-Z 65-90 a-z 97-12
&&&&&&此时的就算机只能识别英文 不识别其他文字
2.群雄割据
中国
需要让计算机识别中文 需要开发 一套中文的编码表
GBK码 : 内部记录了中文字符,英文字符与数字的对应关系 2bytes起步存储中文(遇到生僻字使用更多字节),1bytes存储英文
韩国
需要让计算机识别韩文 需要开发一套韩文的编码表
Euc_kr码:内部记录了韩文字符,英文字符与数字的对应关系
日本
需要让计算机识别日文 需要开发一套日本的编码表
shift_JIS码:内部记录了日本字符,英文字符与数字的对应关系
&&&&&&此时的各国计算机文本文件无法直接交互 会出现乱码的情况
3.天下一统
万国码(unicode):兼容万国字符,所以的字符全部使用2bytes起步存储
utf家族(针对unicode的优化版本)>>>:utf8 英文还是采用1bytes 其他统一采用3bytes
内存使用unicode 硬盘使用utf8
3.字符编码相关操作
只有字符串可以参与编码解码 其他数据类型需要先转换成字符串才可以
1.解决乱码的措施
以什么编码存的就以什么编码解
2.编码与解码
编码:(人类的字符>>>计算机的字符)将人类的字符按照指定的编码装换成计算机可以识别的数字
解码:(计算机的字符>>>人类的字符)将计算机能够识别的数字按照指定的编码转成人类可以读懂的字符
s1 = 'jason说你们都是大宝贝' # 编码 res = s1.encode('gbk') print(res, type(res)) # b'jason\xcb\xb5\xc4\xe3\xc3\xc7\xb6\xbc\xca\xc7\xb4\xf3\xb1\xa6\xb1\xb4' <class 'bytes'> """ 在python中bytes类型的数据可以直接看成是二进制数据 """ # 解码 res1 = res.decode('gbk') print(res1) # jason说你们都是大宝贝
3.解释器层面
python2默认的编码是ASCII码
文件头 # coding:utf8
定义字符串:需要在字符串的前面加u
原因:因为没有办法 是补救措施
python3默认的编码是utf8码
4.代码操作文件
4.1.什么是文件操作?
通过编写代码自动操作文件读写
4.2.什么是文件?
双击文件图标是从硬盘加载数据到内存
写文件之后保存其实就是将内存中的数据刷到硬盘
文件其实是操作系统暴露给用户操作计算机硬盘的快捷方式之一!
4.3.如何代码操作文件?
open (文件路径,读写模式,字符模式)
方式1
f = open()
f.close()
方式2
with open() as 变量名代码运行结束之后自动调用close()方法
4.4.路径
针对文件路径需要注意 可能存在特殊含义(字母与撬棍的组合)
在字符串的前面加字母r即可取消特殊含义
作业
# 1.统计列表中每个数据值出现的次数并组织成字典战士
# eg: l1 = ['jason','jason','kevin','oscar']
# 结果:{'jason':2,'kevin':1,'oscar':1}
# 真实数据
# l1 = ['jason','jason','kevin','oscar','kevin','tony','kevin']
l1 = ['jason', 'jason', 'kevin', 'oscar', 'kevin', 'tony', 'kevin'] # 定义空字典 l2 = {} # 循环 for i in l1: if i not in l2: # 判断是否在l2中 l2[i] = 1 # 不在加一 else: l2[i] += 1 # 在的话在加一 print(l2)
# l2 = {}
# for i in l1:
# l2[i] = l1.count(i)
# print(l2)
# 2.编写员工管理系统
# 1.添加员工信息
# 2.修改员工薪资
# 3.查看指定员工
# 4.查看所有员工
# 5.删除员工数据
# 提示:用户数据有编号、姓名、年龄、岗位、薪资
# 数据格式采用字典:思考如何精准定位具体数据>>>:用户编号的作用
# 4.定义存储用户数据的字典 data_dict = {} # {'1':{}, '2':{}, '3':{} } # 1.先搭建功能框架 while True: print(""" 1.添加员工信息 2.修改员工薪资 3.查看指定员工 4.查看所有员工 5.删除员工数据 """) # 2.获取用户输入的功能编号 func_id = input('请输入功能的编号>>>:').strip() # 3.判断用户输入的功能编号 if func_id == '1': # 5.获取用户数据 emp_id = input('请输入员工编号>>>:').strip() # 9.针对员工编号应该做不重复校验 if emp_id in data_dict: print('该员工编号已经存在') continue emp_name = input('请输入员工姓名>>>:').strip() emp_age = input('请输入员工年龄>>>:').strip() emp_job = input('请输入员工岗位>>>:').strip() emp_salary = input('请输入员工薪资>>>:').strip() # 6.构造存储用户数据的小字典 temp_dict = {} # 7.将员工数据全部录入该小字典 temp_dict['emp_id'] = emp_id temp_dict['emp_name'] = emp_name temp_dict['emp_age'] = emp_age temp_dict['emp_job'] = emp_job temp_dict['emp_salary'] = emp_salary # 8.将员工数据小字典当做大字典的值添加 data_dict[emp_id] = temp_dict # {'1':{}} elif func_id == '2': # 1.获取员工编号 target_emp_id = input('请输入想要修改的员工编号>>>:').strip() # 2.判断当前员工编号是否存在 if target_emp_id not in data_dict: print('当前员工编号不存在 无法修改!!!') continue # 3.根据员工编号获取该员工的详细数据(小字典) emp_data = data_dict.get(target_emp_id) # {} # 4.获取新的员工薪资 new_salary = input('请输入该员工新的薪资>>>:').strip() # 5.修改员工小字典中薪资对应的值 emp_data['emp_salary'] = new_salary # 6.将修改之后的小字典重新赋值到大字典中 data_dict[target_emp_id] = emp_data # 7.人性化提示(也可以不写) print(f'员工编号:{target_emp_id} 员工姓名:{emp_data.get("emp_name")}薪资修改成功') elif func_id == '3': # 1.获取员工编号 target_emp_id = input('请输入想要查询的员工编号>>>:').strip() # 2.判断当前编号是否存在 if target_emp_id not in data_dict: print('当前员工编号不存在') continue # 3.根据员工编号获取员工数据字典 emp_data = data_dict.get(target_emp_id) # 4.格式化输出员工数据 print(f""" --------------------emp of info------------------ 编号:{emp_data.get('emp_id')} 姓名:{emp_data.get('emp_name')} 年龄:{emp_data.get('emp_age')} 岗位:{emp_data.get('emp_job')} 薪资:{emp_data.get('emp_salary')} ------------------------------------------------- """) elif func_id == '4': # 1.获取所有员工数据小字典 all_emp_data = data_dict.values() # [{},{},{}] # 2.循环获取每一个员工数据字典 for emp_data in all_emp_data: # {} # 4.格式化输出员工数据 print(f""" --------------------emp of info------------------ 编号:{emp_data.get('emp_id')} 姓名:{emp_data.get('emp_name')} 年龄:{emp_data.get('emp_age')} 岗位:{emp_data.get('emp_job')} 薪资:{emp_data.get('emp_salary')} ------------------------------------------------- """) elif func_id == '5': # 1.获取想要删除的员工编号 target_delete_id = input("请输入想要删除的员工编号>>>:").strip() # 2.判断员工编号是否存在 if target_delete_id not in data_dict: print('员工编号不存在') continue # 3.根据员工编号删除键值对 data_dict.pop(target_delete_id) # 4.小提示 print(f'员工编号{target_delete_id}数据删除成功') else: print('输入不合法!!!')