对象引用、可变性和垃圾回收

1.python中变量是什么?

在数学概念中,变量表示没有固定值且可以改变的数值。
在计算机系统中,变量表示一段或者多段用来存储数据的内存。
变量名都是指代的一个指针。

在GO语言里面,变量总是有固定的类型,变量类型决定了数据在内存中的长度存储格式。

在python中,变量进行初始化的时候可以不指定类型,那它是如何存储的?
你可以将变量看成标签,比如
a = 1
现在将a这个便签绑定在1这个int类型的对象上面。
a = “kebi”
现在又将a重新绑定在”kebi“这个str类型的对象上面。
这种操作只能在动态类型的语言中才能完成。因为指代的不是同一种类型的对象。

在静态类型的语言中,编译之后的机器码不会有变量,直接使用内存地址来访问目标对象。
要阐述python中的变量,还是要从面向对象的角度来理解。

2.is和==的区别

is:比较双方是否是一个对象,其实时对象操作
==:比较两个对象的值是否相等,内部使用__eq__进行判断

在使用等号进行赋值操作的时候会创建一个新的对象

a = [1,2,3]
b = [1,2,3]
print(id(a),id(b))  #1553861243912 1553861191560
print(a is b)  #False  并不是同一个对象
print(a == b)  #True   但是值是相等的

如果是对象重新赋值,那么就是同一个值

c = a
print(id(a),id(c))  #2320288838728 2320288838728
print(c is a)  #True
print(c == a)  #True

但是,例如总是有的
在python中使用小整数、短字符串进行赋值时,为了节约内存空间,指向同一个内存地址。

e = 1
f = 1
print(id(e),id(f)) #1426481376 1426481376
k,j = ("abc","abc")
print(id(k),id(j))  #2347188715000 2347188715000

3.del语句和垃圾回收机制

python中垃圾回收的算法时采用引用计数。比如:
a = 1
b = a
现在计数2
del a #将a变量删掉,并将计数器减1.
当你将变量的计数器删为0的时候,python解释器会将这个对象删除。

当我们在做垃圾回收操作的时候,我们可以重写__del__语句,这样在调用del操作的时候就能实现自己的逻辑。

4.一个经典的参数错误

def add(a,b):
    a += b #a.extend(b)
    return a

a = 1
b = 2
print(add(a,b))  #3
print(a)  #1
print(b)  #2

c = [1,2]
d = [3,4]
print(add(c,d))  #[1, 2, 3, 4]
print(c)  #[1, 2, 3, 4]
print(d)  #[3, 4]

e = (1,2)
f = (3,4)
print(add(e,f))  #(1, 2, 3, 4)
print(e)  #(1, 2)print(f) #(3, 4)

这里你肯定要问,都是使用add操作,为啥在使用list的时候,会改变另一个对象的值。
下面的实例也会更能说明问题:

class Company:
    def __init__(self,staffs=[]):
        self.staffs = staffs

    def add(self, staffs_name):
        self.staffs.append(staffs_name)

com1 = Company([‘ke‘,‘mao‘])

com2 = Company()
com2.add(‘niao‘)
print(com1.staffs)  #[‘ke‘, ‘mao‘]
print(com2.staffs)  #[‘niao‘]

com3 = Company()
com3.add(‘ming‘)
print(com1.staffs)  #[‘ke‘, ‘mao‘]
print(com2.staffs)  #[‘niao‘, ‘ming‘]
print(com3.staffs)  #[‘niao‘, ‘ming‘]

这里改变com3.staffs去意外的改变了com2.staffs,但是com1.staffs为啥又没有改变了?
原因是
com2 = Company()
com3 = Company()
都是用是默认的staffs=[]这个空list,所以com2.staffs和com3.staffs引用的是同一个对象,
同时这个对象还是可变的,com2和com3中,这两个对象的add方法操控的是同一个对象,所以才会出现上述问题。
但是为啥com1不受影响了?[‘ke‘,‘mao‘]和[]不是同一个对象。
所以在以list等可变类型作为为参数的时候,我们必须清楚它可能被其它对象修改。

原文地址:https://www.cnblogs.com/yangmingxianshen/p/11288361.html

时间: 2024-10-11 01:59:43

对象引用、可变性和垃圾回收的相关文章

gj7 对象引用、可变性和垃圾回收

7.1 python变量到底是什么 #python和java中的变量本质不一样,python的变量实质上是一个指针 int str, 便利贴 a = 1 a = "abc" #1. a贴在1上面 #2. 先生成对象 然后贴便利贴 a = [1,2,3] b = a print (id(a), id(b)) print (a is b) b.append(4) print (a) --- 1642030876232 1642030876232 True [1, 2, 3, 4] 7.2

第七章python对象引用、可变性和垃圾回收

1.python变量是什么 python的变量实质是一个指针,而java普通变量是一个容器直接存入值. 为什么b也变了呢,由于a,b同时指向同一个地址,导致a指向的内容改变也会让b改变,id()获得对象所指向的内存中的地址,如果是对象本身的地址的话a,b应该是不相同的. 1 a = [1, 2, 3] 2 b = a 3 # a和b实质是指针都指向同一个地址,修改a同时会修改b 4 print(id(a), id(b)) # 54866344 54866344 5 print(a is b) #

JavaGC专家(1)—深入浅出Java垃圾回收机制

在学习GC之前,你首先应该记住一个单词:"stop-the-world".Stop-the-world会在任何一种GC算法中发生.Stop-the-world意味着 JVM 因为要执行GC而停止了应用程序的执行.当Stop-the-world发生时,除了GC所需的线程以外,所有线程都处于等待状态,直到GC任务完成.GC优化很多时候就是指减少Stop-the-world发生的时间. 按代的垃圾回收机制 在Java程序中不能显式地分配和注销内存.有些人把相关的对象设置为null或者调用Sy

CMS垃圾回收机制

详解CMS垃圾回收机制 原创不易,未经允许,不得转载~~~ 什么是CMS? Concurrent Mark Sweep. 看名字就知道,CMS是一款并发.使用标记-清除算法的gc. CMS是针对老年代进行回收的GC. CMS有什么用? CMS以获取最小停顿时间为目的. 在一些对响应时间有很高要求的应用或网站中,用户程序不能有长时间的停顿,CMS 可以用于此场景. CMS如何执行?  总体来说CMS的执行过程可以分为以下几个阶段: 3.1 初始标记(STW) 3.2 并发标记 3.3 并发预清理

JVM那些事儿(二)——垃圾回收

这节小汪介绍一下jvm的垃圾回收机制,首先我们先提问: 1.为什么要有不同的垃圾算法 2.垃圾回收器要解决的终极目的是什么 3.小汪该如何选择自己的垃圾回收器 一.垃圾回收算法 众所周知,java堆内存的垃圾回收由java虚拟机管理,目前java有几种算法用来解决垃圾回收(以下只介绍最重要的两个算法) 1.1 复制算法 如图所示,复制算法可以说是最直观最简洁的算法了.按照复制算法的思路,内存要分为两块 Eden Survivor区域,Eden有一个,Survivor有两个. 首先,各种对象都在E

深入理解JAVA虚拟机之JVM性能篇---垃圾回收

一.基本垃圾回收算法 1. 按基本回收策略分 1) 引用计数(Reference Counting)  对象增加一个引用,即增加一个计数,删除一个引用则减少一个计数.垃圾回收时,只用收集计数为0的对象.此算法最致命的是无法处理循环引用的问题. 2)标记-清除(Mark-Sweep)  执行分两阶段.第一阶段从引用根节点开始标记所有被引用的对象,第二阶段遍历整个堆,把未标记的对象清除. 缺点是此算法需要暂停整个应用,同时会产生内存碎片. 3)复制(Copying) 把内存空间划为两个相等的区域,每

各种垃圾回收 (转)

1. 垃圾回收的意义 在C++中,对象所占的内存在程序结束运行之前一直被占用,在明确释放之前不能分配给其它对象:而在Java中,当没有对象引用指向原先分配给某个对象的内存时,该内存便成为垃圾.JVM的一个系统级线程会自动释放该内存块.垃圾回收意味着程序不再需要的对象是"无用信息",这些信息将被丢弃.当一个对象不再被引用的时候,内存回收它占领的空间,以便空间被后来的新对象使用.事实上,除了释放没用的对象,垃圾回收也可以清除内存记录碎片.由于创建对象和垃圾回收器释放丢弃对象所占的内存空间,

Java内存分配与垃圾回收

1.JVM管理的内存包含下图所示的几个运行时数据区域,其中方法区和堆为线程共享的数据区域,程序计数器,虚拟机栈以及本地方法栈为线程私有的数据区域. 程序计数器:可以看做是当前线程所执行的字节码的行号指示器,告诉字节码解释器该读取哪条指令 虚拟机栈:生命周期和线程相同,每个方法在执行的同时都会创建一个栈帧,用于存储局部变量表,操作数栈,动态链接,方法出口等信息,每一个方法从调用到完成的过程就对应了一个栈帧在虚拟机中入栈到出栈的过程.栈中存放了编译器可知的各种基本数据类型和对象引用. 本地方法栈:与

【JVM】JVM系列之垃圾回收(二)

一.为什么需要垃圾回收 如果不进行垃圾回收,内存迟早都会被消耗空,因为我们在不断的分配内存空间而不进行回收.除非内存无限大,我们可以任性的分配而不回收,但是事实并非如此.所以,垃圾回收是必须的. 二.哪些内存需要进行垃圾回收 对于虚拟机中线程私有的区域,如程序计数器.虚拟机栈.本地方法栈都不需要进行垃圾回收,因为它们是自动进行的,随着线程的消亡而消亡,不需要我们去回收,比如栈的栈帧结构,当进入一个方法时,就会产生一个栈帧,栈帧大小也可以借助类信息确定,然后栈帧入栈,执行方法体,退出方法时,栈帧出