zoukankan      html  css  js  c++  java
  • 对象引用、可变性和垃圾回收

    一. 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__)

     

  • 相关阅读:
    上周热点回顾(2.12-2.18)团队
    上周热点回顾(2.5-2.11)团队
    上周热点回顾(1.29-2.4)团队
    云计算之路-阿里云上:部分服务器未及时续费造成docker swarm集群故障团队
    Git学习系列之Windows上安装Git之后的一些配置(图文详解)
    Git学习系列之Git 的缺点有哪些?
    Git学习系列之Git的功能特性(从一般开发者的角度和主开发者的角度来剖析)
    Git学习系列之经典的Git开发过程
    Git学习系列之Windows上安装Git详细步骤(图文详解)
    Git学习系列之集中式版本控制系统vs分布式版本控制系统
  • 原文地址:https://www.cnblogs.com/lyq-biu/p/10425722.html
Copyright © 2011-2022 走看看