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

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等可变类型作为为参数的时候,我们必须清楚它可能被其它对象修改。

 

posted @ 2019-08-02 14:26  明王不动心  阅读(232)  评论(0编辑  收藏  举报