Python中的变量和垃圾回收机制

1、python中的变量

pythonjava中的变量本质不一样。

java中声明变量时要指定变量的数据类型,int、str或某一类,之后虚拟机就会在内存中申请一块空间,空间的大小跟类型相关。通俗的理解就是把变量想象成一个盒子,盒子里能装什么东西,一开始就设定了。

比如a=1就是将1放到盒子里面。

python的变量实质是一个指针,指针的大小都是一样的。比如一个指向int类型的指针,指针本身大小是固定的,也不用考虑int本身所占的内存大小,反正是放在内存中。在访问int对象时只需要找到指针即可。

a=1来说,首先去内存中声明一个int类型对象,开辟一块空间用来存储1,然后将a指向1。

a = [1,2,3]
b = a
b.append(4)
print(a) # [1,2,3,4]

这里如果用盒子的思想去理解的话:将列表[1,2,3]放进一个盒子中,再将a放另一个盒子中,那么修改b之后打印a的话,a就不会发生改变。

a = [1,2,3]
b = a
print(a is b) # True

通过is也可看到ab是同一个对象,也就是a指向的对象id值和b指向的对象id值相同。

2、==和is的区别

  • is

上边最后说了a = [1,2,3] b = a这样a和b是同一个对象。那么如果是两个赋值呢?

a = [1,2,3]
b = [1,2,3]
ptint(a is b) # False
print(id(a) == id(b)) #False

从结果来看,此时的a和b是不同的对象。也就是说在使用赋值语句时会重新声明一个对象。

有一个特殊情况如下

a = 1
b = 1
print(a is b) #True

python内部的intern机制——遇到相同的一定范围内的小整数时不在生成新的对象,直接指向原来的那个对象。一种内部优化的机制。

小段字符串也是一样的。

a = "abc"
b = "abc"
print(a is b) #True

用is对类进行判断

class People:
    pass
person = People()
# isinstance(person,People)
if type(person) is People:
    print('Yes') # Yes

因为类本身也是一个对象,而且是全局唯一的对象,person实际上是指向People的,所以type(person)People的id是一样的。

  • ==
a = [1,2,3]
b = [1,2,3]
ptint(a == b) # True

a是一个list类型的对象,list中实现了一个魔法函数__eq__,当遇到==时就会调用该函数判断对象的值是否相等。

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

python中的垃圾回收算法采用的是引用计数。

先定义a=1b=a,然后1这个对象上就会自动生成一个计数器,a=1时计数器会加1,b=a说明b也指向了a,此时计数器再加1,相当于1上面有两个变量指向它。

当我们使用del a删除对象时,计数器则会减1。当计数器减少到0时,python解释器就会将对象回收(不能一直占用在内存中)。

c++中的删除语句是直接将对象回收,这和python不一样。

举个栗子

a=object()
b=a
del a
print(b) # object object at 0x0000000003D90F0
print(a) # name a is not defined

上面的结果就是b能打印出来,a打印不出来。过程就是将对象a删掉,同时将引用计数器减1。

python解释器回收对象时,会去调用对象的__del__魔法函数。所以当我们做垃圾回收时,希望某些资源在对象被回收时释放,就可以通过重载__del__函数来实现。

class A:
	def __del__(self):
		pass

4、关于传入列表的一下注意事项

第一种情况

def add(a,b):
    a+=b
    return a
if __name__ == "__main__":
    a = 1
    b = 2
    c=add(a,b)
    print(c) # 3
    print(a,b) # 1 2

第二种情况

def add(a,b):
    a+=b
    return a
if __name__ == "__main__":
    a = [1,2]
    b = [3,4]
    c=add(a,b)
    print(c) # [1,2,3,4]
    print(a,b) # [1,2,3,4] [3,4]

发现此时输入的a改变了,因为列表是可变类型,+=符号在运行过程中直接赋值给原前的列表变量a,所以原来的a发生了改变。

第三种情况

def add(a,b):
    a+=b
    return a
if __name__ == "__main__":
    a = (1,2)
    b = (3,4)
    c=add(a,b)
    print(c) # (1,2,3,4)
    print(a,b) # (1,2) (3,4)

总结

三种不同类型参数传递进来的时候,只有列表对象对原数据产生了影响。

所以当传递一个对象到函数中,对象如果是list、dict这类的值可被修改的类型,可能会引起原始数据的改变。

猜你喜欢

转载自blog.csdn.net/weixin_43901214/article/details/107039987