垃圾回收机制

1.概念

  • 垃圾回收机制(GC):是Python解释器自带一种机制,专门用来回收不可用的变量值所占用的内存空间

2.原理

  • Python的垃圾回收机制(GC)主要使用引用计数(reference counting)来跟踪和回收垃圾。在引用计数的基础上,通过“标记-清除”(mark and sweep)解决容器对象可能产生的循环引用问题,通过“分代回收”(generation collection)以空间换时间的方法提高垃圾回收效率。
  • python采用的是引用计数机制为主,标记-清除和分代收集两种机制为辅的策略。

3.引用计数

  • 引用计数:变量值被变量名关联的次数
  • 引用计数存在一个致命缺陷:循环引用导致内存泄漏
    • 解决办法:标记清楚、分代回收、手动GC
name = 'NianBai' # 'NianBai'被关联了一个变量名name,称之为引用计数为1
name1 = name # 把name的内存地址给了name1,而name、name1都关联了'NianBai',所以'NianBai'的引用计数为2
del name1 # 解除'NianBai'和name1的关联,'NianBai'身上的引用计数变为1

4.标记清除

  • 专门用于解决循环引用的问题,将内存中程序产生的所有数据值全部检查一遍,查看是否存在循环引用,存在则打上标记 ,之后一次性清除
  • 标记:遍历所有的GC Roots对象(栈区中的所有内容或者线程都可以作为GC Roots对象),然后将所有GC Roots的对象可以直接或间接访问到的对象标记为存活的对象,其余的均为非存活对象,应该被清除。
  • 清除:清除过程中遍历堆中所有的对象,将没有标记的对象全部清除
  • 标记清除算法时,发现栈区内不再有l1与l2(只剩下堆区内二者的相互引用),于是列表1与列表2都没有被标记为存活,二者会被清理掉,这样就解决了循环引用带来的内存泄漏问题。
l1 = ['jason', ]
l2 = ['kevin', ]
l1.append(l2)  # 引用计数为2
l2.append(l1)  # 引用计数为2
del l1  # 解除变量名l1与列表的绑定关系,列表引用计数减一
del l2  # 解除变量名l1与列表的绑定关系,列表引用计数减一

5.分代回收

  • 因为标记清除每隔一段时间就需要将所有的数据排查一遍,资源消耗过大,所以为了减轻资源损耗,开发了分代管理。
  • 分代回收:是一种以空间换时间的操作方式,Python将内存根据对象的存活时间划分为不同的集合,每个集合称为一个代。
  • Python将内存分为了3“代”,分别对应三个链表,它们的垃圾收集频率与对象的存活时间的增大而减小。
    • 年轻代(第0代):新创建的对象分配在年轻代,年轻代链表的总数达到上限时,Python垃圾收集机制就会被触发,把不会回收的对象移到中年代
    • 中年代(第1代):不会回收的对象移到中年代
    • 老年代(第2代):老年代中的对象是存活时间最久的对象,存活于整个系统的生命周期内。

字符编码

1.发展史

  • 阶段一:一家独大

    • 美国人发明了计算机,为了让计算机识别英文字符,有了他们的字符编码——ASCII码(只能识别英文,不能识别除英文以外的文字)
    • ASCII码:记录英文字符和数字的对应关系,用1bytes来存储字符(A-Z:65-99,a-z:97-122)
  • 阶段二:群雄割据

    • 计算机传到其他国家后,其他国家使用计算机时发现ASCII对于有些语言来说不好使,于是各个国家发明了各自的字符编码。
    • 中国:需要计算机识别中文,开发了一套中文的编码表——GBK码
      • GBK码:记录了中文字符、英文字符与数字的对应关系,2bytes起步存储中文(生僻字使用更多),1bytes存储英文
    • 韩国:需要计算机识别韩文,开发了一套韩文编码表——Euc_kr码
      • Euc_kr码:记录了韩文字符、英文字符与数字的对应关系
    • 日本:需要计算机识别日文,开发了一套日文编码表——shift_JIS码
      • shift_JIS码:记录了日文字符、英文字符与数字的对应关系
    • 各国计算机文本文件无法直接交互,否则会出现乱码的情况
  • 阶段三:天下统一

    • 由于各个国家各自的字符编码不同,不同国家之间在传输信息的时候就会出现乱码的情况,于是就发明了万国码国码——Unicode
      • unicode:所有字符全部使用2bytes起步存储
    • utf针对Unicode的优化版本——UTF-8
      • UTF-8:英文采用1bytes,其他统一采用3bytes
    • 内存使用Unicode,硬盘使用UTF-8

2.实际应用

2.1.编码与解码

  • 编码(encode):将人类能够读懂的字符翻译成计算机能够读懂的字符
s1 = '你是猪'
res = s1.encode('utf-8')
print(res, type(res))
  • 解码(decode):将计算机能够读懂的字符翻译成人类能够读懂的字符
s1 = '你是猪'
res1 = res.decode('utf-8')
print(res1)

2.2.乱码问题

  • 当一组数据用不同的字符编码进行编码解码时,就会出现乱码的情况。
  • 解决乱码措施:什么编码存就用什么编码解

2.3.Python默认编码

  • python2.x默认的字符编码是ASCII(不支持中文),默认的文件编码是ASCII
    • python解释器可以识别中文和其他语言的方法

      • 方法一:告知python解释器,这个.py文件里的文本是用UTF-8编码的。这样,python就会依照utf-8的编码形式解读其中的字符,然后转换成unicode编码内部处理使用
      # coding:utf8 或 -*- coding:utf8 -*-
      # -*- coding:XXX -*-声明的编码方式要与.py文件的编码方式一致
      
      • 方法二:在定义字符串时习惯在前面加u
      name = u'张三'
      
    • python2不区分str和unicode,但在拼接str和unicode时,str将自动转换成unicode

  • python3.x默认的字符编码是Unicode(支持中文),默认的文件编码是UTF-8
    • python3严格区分了bytes和str,二者不能进行拼接。文本总是unicode,有str表示;二进制数据则由bytes表示。

ASCII码表

image

文件操作简介

1.文件

  • 文件其实是操作系统暴露给用户操作计算机硬盘的快捷方式

2.文件操作

  • 文件操作流程:
    • 打开文件:由应用程序向操作系统发起系统调用open(文件路径,读写模式,字符编码),操作系统打开该文件,对应一块硬盘空间,并返回一个文件对象赋值给一个变量f
    • 操作文件:调用文件对象下的读/写方法,会被操作系统转换为读/写硬盘的操作
    • 关闭文件:向操作系统发起关闭文件的请求,回收系统资源
f = open('a.txt', 'r', encoding = 'utf-8') # 打开文件
data=f.read() # 操作文件

# 关闭文件
方式1(手动写关闭文件代码):
	f.close()
方式2(推荐):
	with open() as f:
	# 子代码运行结束之后自动调用close()方法

作业

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']
dict_l = {}
for i in l1:
    dict_l[i] = l1.count(i)
print(dict_l)

2.编写员工管理系统
1.添加员工信息
2.修改员工薪资
3.查看指定员工
4.查看所有员工
5.删除员工数据
提示:用户数据有编号、姓名、年龄、岗位、薪资
数据格式采用字典:思考如何精准定位具体数据>>>:用户编号的作用

data_dict = {}
while True:
    print("""
        1.添加员工信息
        2.修改员工薪资
        3.查看指定员工
        4.查看所有员工
        5.删除员工数据
    """)
    func_id = input('请输入功能的编号:').strip()
    if func_id == '1':
        emp_id = input('请输入员工编号:').strip()
        if emp_id in data_dict:
            print('该员工编号已经存在')
            continue
        emp_name = input('请输入员工姓名:').strip()
        emp_age = input('请输入员工年龄:').strip()
        emp_job = input('请输入员工岗位:').strip()
        emp_salary = input('请输入员工薪资:').strip()
        temp_dict = {}
        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
        data_dict[emp_id] = temp_dict  # {'1':{}}
    elif func_id == '2':
        target_emp_id = input('请输入想要修改的员工编号:').strip()
        if target_emp_id not in data_dict:
            print('当前员工编号不存在 无法修改!!!')
            continue
        emp_data = data_dict.get(target_emp_id)  # {}
        new_salary = input('请输入该员工新的薪资:').strip()
        emp_data['emp_salary'] = new_salary
        data_dict[target_emp_id] = emp_data
        print(f'员工编号:{target_emp_id} 员工姓名:{emp_data.get("emp_name")}薪资修改成功')
    elif func_id == '3':
        target_emp_id = input('请输入想要查询的员工编号:').strip()
        if target_emp_id not in data_dict:
            continue
        emp_data = data_dict.get(target_emp_id)
        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':
        all_emp_data = data_dict.values()
        for emp_data in all_emp_data:
            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':
        target_delete_id = input("请输入想要删除的员工编号:").strip()
        if target_delete_id not in data_dict:
            print('员工编号不存在')
            continue
        data_dict.pop(target_delete_id)
        print(f'员工编号{target_delete_id}数据删除成功')
    else:
        print('输入指令错误,请重新输入')
 posted on 2022-06-28 19:39  念白SAMA  阅读(76)  评论(0)    收藏  举报