首页 > 其他分享 >8. 深浅拷贝、可变与不可变、垃圾回收机制、字符编码、文件操作

8. 深浅拷贝、可变与不可变、垃圾回收机制、字符编码、文件操作

时间:2024-07-23 18:43:54浏览次数:14  
标签:编码 字符 666 列表 深浅 可变 print 拷贝 id

1. 可变和不可变数据类型

1.1 概念

可变数据类型:当指定值被修改时内存空间地址不变

不可变数据类型:当指定值被修改时内存空间地址发生改变

1.2 常见类型的代码实现

可变类型:list   dict  set

不可变类型:str int  float bool tuple

(1)整数   不可变

a = 1
print(id(a))  # 2549145403632
a = 2
print(id(a))  # 2549145403632

(2)浮点型  不可变

b = 1.01
print(id(b))  # 1369240625488
b = 2.02
print(id(b))  # 1369240630864

(3)字符串   不可变

c = 'messi'
print(id(c))  # 2077972897840
c = 'leomessi'
print(id(c))  # 2077972974448

(4)布尔值  不可变

d = True
print(d, type(d), id(d))  # True <class 'bool'> 140709452925800
d = False
print(d, type(d), id(d))  # False <class 'bool'> 140709452925832

(5)元组  不可变

e = (1, 2, 3)
print(e, type(e), id(e))  # (1, 2, 3) <class 'tuple'> 2759659910528
e = e.__add__((9, 10, 11))
print(e, type(e), id(e))  # (1, 2, 3, 9, 10, 11) <class 'tuple'> 2759660046368

(6)列表  可变

f = [1, 2, 3]
print(f, type(f), id(f))  # [1, 2, 3] <class 'list'> 2513866568320
f.append(666)
print(f, type(f), id(f))  # [1, 2, 3, 666] <class 'list'> 2513866568320

(7)字典  可变

g = {'name': 'messi'}
print(g, type(g), id(g))  # {'name': 'messi'} <class 'dict'> 2838915653376
g['name'] = 'Leomessi'
print(g, type(g), id(g))  # {'name': 'Leomessi'} <class 'dict'> 2838915653376

(8)集合  可变

h = {'messi', 'ronaldo'}
print(h, type(h), id(h))  # {'ronaldo', 'messi'} <class 'set'> 2297948368096
h.add(11)
print(h, type(h), id(h))  # {11, 'ronaldo', 'messi'} <class 'set'> 2297948368096

总结:在python中可变与不可变的区别是值被修改后内存空间地址是否改变

 1.3 值传递和引用传递

(1)概念

值传递:每一次的值都会有一个自己的内存空间地址

引用传递:在中间有一块内存地址负责中转对应的值

 严格意义上来说,python既不是值传递,也不是引用传递

(2)python的传递规则是:

如果传递的是不可变类型,在函数中修改,就不会影响原来的变量

如果传递的是可变数据类型,在函数中修改,不会影响原来的变量,修改,而不是重新赋值

(3)值与引用的概念

值是一个变量      =  具体的值(一块内存空间放着这个变量的值)

引用是一个变量  =  内存地址(内存地址指向了值) 

(4)参数传递

可变类型的参数传递:

如列表、字典,在函数中修改参数会影响原始对象

不可变类型的参数传递: 如数字、字符串,在函数中修改参数不会影响原始对象

# 可变数据类型就是修改原来的值但是内存空间地址不变
# 不可变数据类型就是修改原来的值但是内存空间地址会改变

2. 堆和栈的概念

堆(是一种数据结构):先进先出

栈(是一种数据结构):先进后出

 3. 垃圾回收机制

3.1 概念:

垃圾回收机制(简称GC)是Python解释器自带的一种机制,用来回收不可用的变量值所占用的内存空间(在内存中,没有变量名指向的数据都是垃圾数据)

3.2 作用:

程序运行过程中会申请大量的内存空间,而对于一些无用的内存空间如果不及时清理的话会导致内存使用殆尽(内存溢出),导致程序崩溃

3.3 堆区与栈区

在定义变量时,变量名与变量值都是需要存储的

栈区:变量名与值内存地址的关联关系通常被存放在程序的栈区

堆区:变量值存放于堆区,内存管理回收的是堆区的内容

3.4 原理

引用计数为主,分代回收、标记清除为辅

(1)引用计数

a = 1  # 变量值1的引用次数是1
b = a = 1  # 变量值1的引用次数是2
b = a = 2  # 变量值1的引用次数是0
a = 1  # 变量值1的引用次数是1

 解释器会将引用次数为0的数据清除

(2)标记清除

内存在每次运行时都会进行扫描

第一次扫描---发现某个值变成了垃圾---不会立即清除---可能在某块代码又对该值进行了引用---对该垃圾打标签---出现一次

第二次扫描---发现该值仍然是垃圾---不会立即清除---对该垃圾打标签---出现两次

当标签次数为10次进行权重提升

(3)分代回收

每一次扫描都会发现垃圾 垃圾未必是当前必须清除掉的垃圾 打上标签

等级1 : 隔 10 min 扫描一次, 一直发现有一个垃圾存在 ,当标记次数达到 100 次就提权
等级2 : 隔 20 min 扫描一次 ,一直发现有一个垃圾存在 ,当标记次数达到 200 次的时候就提权
等级3 : 隔 30 min 扫描一次,  一直发现有一个垃圾存在, 当标记次数达到 300 次的时候就清除

垃圾可能会被捡起来重新使用 为了避免重复开销内存 于是就有了上述机制

4. 小整数池

python中经常使用的一些数值定义为小整数池,范围是[-5,256],python对这些数值已经提前创建好了内存空间

即使多次重新定义也不会在重新创建新的空间,但是小整数池外的数值在重新定义时都会再次创建新的空间。

所以对于小整数池中的数,内存地址一定是相同的,小整数池外的数,内存地址是不同的。

5. 深浅拷贝

5.1 深拷贝

是指创建一个新的对象,该对象与原始对象完全独立

递归地复制所有嵌套对象,包括内容,以便在修改新对象时不会影响到原始对象

(完整复制)

import copy
a = [1, 2, 3, [7, 8, 9]]
b = copy.deepcopy(a)  # 深拷贝产生的列表
print(b)  # [1, 2, 3, [7, 8, 9]]
# 修改原列表中的可变类型中的元素
a[3][0] = 666
print(a)  # 原列表[1, 2, 3, [666, 8, 9]]
print(b)  # 深拷贝列表[1, 2, 3, [7, 8, 9]]
# 修改原列表中的不可变类型
a[1] = 222
print(a)  # [1, 222, 3, [666, 8, 9]]
print(b)  # [1, 2, 3, [7, 8, 9]]

新对象和原对象对可变数据类型的引用不一致

5.2 浅拷贝

是指创建一个新的对象,并将原始对象的元素复制到新对象中

然而,如果原始对象包含可变的元素(如列表),则新对象中的这些元素仍然与原始对象中相应元素共享相同的内存地址

(只会复制一层)

import copy
a = [1, 2, 3]
b = copy.copy(a)  # 浅拷贝产生新的列表
a.append(666)
print(a)  # 原来的列表 [1, 2, 3, 666]
print(b)  # 浅拷贝的列表 [1, 2, 3]
b.append(999)
print(b)  # 修改浅拷贝的列表不会影响原列表 [1, 2, 3, 999]
import copy
c = [1, 2, 3, [7, 8, 9]]
d = copy.copy(c)  # 浅拷贝产生的列表
print(d)  # [1, 2, 3, [7, 8, 9]]
# 修改原列表中的可变数据类型中的元素
c[3][0] = 666
print(c)  # 原列表[1, 2, 3, [666, 8, 9]]
print(d)  # 浅拷贝的列表[1, 2, 3, [666, 8, 9]]
# 修改原列表中的不可变类型 c[1] = 222 print(c) # [1, 222, 3, [666, 8, 9]] print(d) # [1, 2, 3, [666, 8, 9]]

新对象和原对象中对可变数据类型的引用一致

总结:

深拷贝是创建一个完全独立的对象,并且递归的复制对象中的所有关系

浅拷贝是创建一个新对象,但是新对象共享原对象中的可变数据类型关联关系

6. 字符编码

6.1 概念:

计算机只能识别二进制数,人类与计算机交互时,用的都是人类能读懂的字符,如中文字符、英文字符

人类常用的字符与计算机中的数字交互,一定经历一个转换翻译过程,转换翻译的过程必须参照一个特定的标准,该标准称之为字符编码表

字符编码表上存放的是字符与数字的一 一对应关系

编码即指人类常用的字符转换成计算机能够识别的数字

6.2 字符编码的发展历史

第一阶段(一家独大):

计算机由美国人发明,为了让计算机能识别英文,定义了一个英文字符与数字的对应关系---ASCII码表,只记录英文字符和数字的对应关系

1Byte对应1个英文字符,1Byte=8bit,最多包含256个数字,对应着256个字符,足够表示所有英文字符

ASCII码表中:

A-Z   65-90

a-z    97-122

0-9    48-57

第二阶段(诸侯割据):

随着计算机的普及和发展,各个国家都需要将本国字符与二进制数进行转换

GBK码(国标):

记录中文、英文字符与数字的对应关系

1Byte存储英文字符,2Byte存储中文字符,如果不够用则使用 3Byte或 4Byte(2Byte最多能对应的中文字符数量为2**16=65536个)

Euc_kr:

记录韩文、英文字符与数字的对应关系

shift_JIS:

记录日文、英文字符与数字的对应关系

第三阶段(天下一统):

unicode(万国码):

记录了所有国家的字符与数字的对应关系,所有的字符最少采用2byte存储

现在的计算机可以输出所有国家的字符,内存使用的是unicode编码

由于unicode最少采用2byte,而ASCII码中1byte对应1个英文字符,因此unicode会浪费存储空间和io时间,所以又开发了一个编码(utf-8)

utf-8:

1byte存储英文字符

3byte存储中文字符

结论:

 内存中的编码不需要考虑,只考虑硬盘上的即可

汉字、英文------unicode------GBK

韩文、英文------unicode------Euc_k

 万国字符--------unicode-------utf-8

6.3 字符编码应用 

6.3.1 编码与解码

编码(encode):将人类常用字符转换成计算机能识别的二进制数

解码(decode):将计算机的二进制数转换成人类常用的字符

 

 

标签:编码,字符,666,列表,深浅,可变,print,拷贝,id
From: https://www.cnblogs.com/hbutmeng/p/18318621

相关文章

  • iOS开发基础140-音频编码
    音频编码是将音频信号转换为数字信号的过程,这样可以便于存储、传输和解码。在iOS开发中,我们通常使用CoreAudio来处理音频编码和解码的过程。本篇文章主要介绍如何使用CoreAudio的AudioToolbox框架来进行音频编码。音频编码的步骤音频编码的过程通常涉及以下几个步骤:设置音......
  • iOS开发基础138-视频编码
    为完善视频编码的封装和提供一定的拓展性,以下是视频编码的详细示例,其中包括编码参数设置和数据提取处理。以下示例侧重于视频编码部分。视频编码器示例下面的代码示例展示了一个视频编码器的实现,包括如何设置关键编码参数和从回调中提取H.264数据。//VideoEncoder.h#import<......
  • 系统整容纪:揭秘Java编程之美:掌握这些编码规范,让你的代码一跃成为行业典范
     分享工作中的点点滴滴,贯彻千里之行,始于足下,最终以微不足道的量变引起化蝶的质变精神。以自己为例拒绝在舒适的中央区域安逸的躺着,以便在不知不觉中被社会所淘汰,也不盲目的直接跃迁进困哪区域,在受挫的同时又跌回原有的舒适区域内,造成这样一个浑浑噩噩的让人无法进步的循环怪圈......
  • TopoDS_Shape的拷贝
    TopoDS_Shape的拷贝有两种方式1)TopoDS_ShapenewShape=oldShape;2)BRepBuilderAPI_Copytool;tool.perform(oldShape,true,false);//!"false"sinceI'mnotinterestedincopyingthetriangulationnewShape=tool.Shape();两者的不同在于shape数据的拷贝深度,TopoDS......
  • 如何理解JAVA的编码格式是Unicode
    背景今天看以前的JAVA视频,发现课件里面写着JAVA的内部的编码格式是Unicode。这句话,突然勾起了我的好奇心。因为的JAVA代码文件都是UTF8编码,怎么跟Unicode扯上关系的呢?我去问了一下AI,然后整理了一下Unicode是JAVA编译器的读取class文件使用的编码假设,我的如下代码是UTF-8编......
  • 【c++经典面试题】有关string类的深浅拷贝
    题目背景基于自实现string类substr成员函数时遇到的问题。代码展示stringstring::substr(size_tpos,size_tlen)//声明时len的参省值位npos { assert(pos<_size); if(len>_size-pos)//如果len的长度大于有效字符长度,那么重置为有效字符长度 { le......
  • 后端API接口定义返回编码规则
    code状态码code返回状态码,一般小伙伴们是在开发的时候需要什么,就添加什么。如接口要返回用户权限异常,我们加一个状态码为101吧,下一次又要加一个数据参数异常,就加一个102的状态码。这样虽然能够照常满足业务,但状态码太凌乱了。我们应该可以参考HTTP请求返回的状态码(下面是常见的......
  • 数据共享(浅拷贝)与数据独立(深拷贝)
    在FFmpeg中,数据共享和数据独立的区别在于浅拷贝和深拷贝的使用。让我们详细探讨这两个概念及其在FFmpeg内存模型中的实现。数据共享(浅拷贝)浅拷贝是指在拷贝对象时,只拷贝对象的引用,而不拷贝实际的数据内容。对于FFmpeg中的AVPacket来说,浅拷贝意味着两个Packet共享同一个数据缓冲......
  • 通信原理之编码
    1.通信系统简介信源通过震动发出模拟信号,经过模数转化传输--数字信号可以识别、增强、再生,比模拟信号抗干扰能力更强、传输距离更长等优势。声音是一种波,我们可以使用两种方式进行传播:1.以信号的原始频率(基带信号)2.将声音和高频的信号结合(载波),改变载波以便于更好的传输数据......
  • 生成模型---变分自编码器
    1.设计思路1.1自编码器基础自编码器(Autoencoder)是一种神经网络模型,由编码器和解码器组成。编码器将输入数据压缩成一个潜在空间的表示(即编码),解码器则将这种表示重构为原始数据。设定:输入数据为x......