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