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

一. python变量到底是什么

  python和Java的变量本质不一样,Java是定义好一个类型,然后申请一个空间(大小和类型有关),相当于一个盒子只能放固定类型,python变量的实质是一个指针(大小都相同),指向int,string等等,相当于一个便利贴(先生成对象,然后贴便利贴),可以贴在很多东西上。

a=[1,2]
b=a
b.append(3)
#a和b贴在同一个对象上面
print(a)
print(a is b)
print(id(a),id(b))

二. ==和is的区别

  is是判断是否是同一个对象,而==是判断值是否相等

a=[1,2,3]
b=[1,2,3]
print(a is b)
print(id(a),id(b))
#为什么能判断是相等的,也是魔法函数(list中的__eq__)
print(a==b)

  

  对于小整数(python内部的intern机制),将一定范围的小整数(大概是-5~256),会建立全局唯一的变量,下次再遇到时直接指向之前的,小段的字符串,Python都有机制

#对于小整数(python内部的intern机制),将一定范围的小整数(大概是-5~256),会建立全局唯一的变量,下次再遇到时直接指向之前的,小段的字符串,Python都有机制
a=1
b=1
print(a is b)
print(id(a),id(b))

 

  

  类本身也是一个对象,而且全局只有唯一的:

#类本身也是一个对象,而且全局只有唯一的
class Person:
    pass
p1=Person()
print(type(p1) is Person)

三. del语句和垃圾回收(参考:Python垃圾回收机制)

  1.python中垃圾回收算法采用引用计数(cpython2.0之后就不仅仅是)

#这里比如1的计数为1
a=1
#这时1的计数会加1,相当于1上面有两个引用它
b=a
#这里没有回收1,只是将1的引用计数减一,当引用计数为0时就将这个对象回收
del a
print(b)

  2.标记清除:

    标记清除(Mark—Sweep)』算法是一种基于追踪回收(tracing GC)技术实现的垃圾回收算法。它分为两个阶段:第一阶段是标记阶段,GC会把所有的『活动对象』打上标记,第二阶段是把那些没有标记的对象『非活动对象』进行回收。

    对象之间通过引用(指针)连在一起,构成一个有向图,对象构成这个有向图的节点,而引用关系构成这个有向图的边。从根对象(root object)出发,沿着有向边遍历对象,可达的(reachable)对象标记为活动对象,不可达的对象就是要被清除的非活动对象。根对象就是全局变量、调用栈、寄存器。

  3.分代回收:

    分代回收是一种以空间换时间的操作方式,Python将内存根据对象的存活时间划分为不同的集合,每个集合称为一个代,Python将内存分为了3“代”,分别为年轻代(第0代)、中年代(第1代)、老年代(第2代),他们对应的是3个链表,它们的垃圾收集频率与对象的存活时间的增大而减小。新创建的对象都会分配在年轻代,年轻代链表的总数达到上限时,Python垃圾收集机制就会被触发,把那些可以被回收的对象回收掉,而那些不会回收的对象就会被移到中年代去,依此类推,老年代中的对象是存活时间最久的对象,甚至是存活于整个系统的生命周期内。同时,分代回收是建立在标记清除技术基础之上。分代回收同样作为Python的辅助垃圾收集技术处理那些容器对象

  4.可以自己写在类中写垃圾回收的逻辑(__del__魔法函数):

class A:
    def __del__(self):
        pass

四. 一个经典的错误

  1.原因:列表(可变对象),+=是直接修改a2,而不是创建一个新的list,因此a2也变化了

def add(a, b):
    a += b
    return a
if __name__=='__main__':
    a1=1
    b1=2
    c1=add(a1,b1)
    print(c1)
    print(a1,b1)
    #列表(可变对象),+=是直接修改a2,而不是创建一个新的list,因此a2也变化了
    a2=[1,2]
    b2=[3,4]
    c2=add(a2,b2)
    print(c2)
    print(a2,b2)
    #元组是不可变对象
    a3=(1,2)
    b3=(3,4)
    c3=add(a3,b3)
    print(c3)
    print(a3,b3)

  2.原因:类中传递的列表是一个可变对象,com2和com3都没有传递list,因此使用的是默认的list,其实是共用的一个对象(且可变)

class Company:
    def __init__(self,name,staffs=[]):
        self.name=name
        self.staffs=staffs
    def add(self,staff_name):
        self.staffs.append(staff_name)
    def remove(self,staff_name):
        self.staffs.remove(staff_name)
com1=Company('SWPU',['LYQ1','LYQ2'])
com1.add('NEW3')
com1.remove('LYQ2')
#这里没有问题
print(com1.staffs)
com2=Company('SWPU2')
com2.add('LYQ_com2')
print(com2.staffs)
#默认值
print(Company.__init__.__defaults__)
com3=Company('SWPU3')
com3.add('LYQ_com3')
print(com2.staffs)
print(com3.staffs)
#com2.staffs和com3.staffs是同一个对象
print(com2.staffs is com3.staffs)
#默认值
print(Company.__init__.__defaults__)

 

原文地址:https://www.cnblogs.com/lyq-biu/p/10425722.html