Python面向对象(三)

  • Python对象的声明周期,以及周期方法
  • 概念
  • 涉及问题
  • 监听对象生命周期
  • 内存管理机制


Python对象的声明周期,以及周期方法

概念

指对象从诞生到消亡的过程

当一个对象被创建时,会在内存中分配相应的内存空间进行存储

当这个对象不再使用,为了节约内存,就会把这个对象释放

涉及问题

如何监听一个对象的生命过程?

Python如何掌控一个对象的生命?

监听对象生命周期

  1. __new__方法
  2. __init__方法
  3. __del__方法
class Person:
    # def __new__(cls, *args, **kwargs):
    #     print("拦截了")

    def __init__(self):
        print("初始化")
        self.name="sz"
    def __del__(self):
        print("释放了")
    pass

p = Person()
print(p)
print(p.name)
class Person:
    __personCount =0
    def __init__(self):
        print("计数 + 1")
        Person.__personCount += 1
        # self.__class__.__personCount += 1 也可以
    def __del__(self):
        print("计数 - 1")
        Person.__personCount -= 1
        # self.__class__.__personCount -= 1 也可以

    @classmethod
    def log(cls):
        print("当前人的个数是%d个"%Person.__personCount)

p = Person()
p2 = Person()
del p
Person.log()
# 计数 + 1
# 计数 + 1
# 计数 - 1
# 当前人的个数是1个
# 计数 - 1  # 因为最后会调用del释放空间

内存管理机制

  • 存储方面
  1. 在Python中万物皆对象
  2. 所有对象都会在内存中开辟一块空间进行存储,会根据不同的类型以及内容,开辟不同不同的空间大小进行存储
    返回该空间的地址给外界接收(称为"引用"),用于后续对这个对象的操作
    可通过id()函数获取内存地址(10进制)
    通过hex()函数可以查看对应的16进制地址
class Person:
    pass

p = Person()
print(p)
print(id(p))
print(hex(id(p)))
# <__main__.Person object at 0x00000159A2287390>
# 1484484277136
# 0x159a2287390
  1. 对于整数和短小的字符,Python会进行缓存,不会创建多个相同对象
  2. 容器对象,存储的七大对象,仅仅是对其他对象的引用,并不是其他对象本身
  • 垃圾回收方面
  1. 引用计数器
    概念:一个对象,会记录着自身被引用的个数
    每增加一个引用,这个对象的引用计数会自动+1
    每减少一个引用,这个对象的引用计数会自动-1
    查看引用计数
import sys
sys.getrefcout(对象)  # 因为sys.getrefcout又引用了一次,所以会大一
#-----------------引用计算器-------------------

import sys
class Person:
    pass

p1 = Person()  # 1

print(sys.getrefcount(p1))
p2 = p1 # 2
print(sys.getrefcount(p1))

del p2
print(sys.getrefcount(p1)) # 1

del p1
print(sys.getrefcount(p1)) # NameError: name 'p1' is not defined
#-----------引用计数器机制-特殊场景-循环引用问题----------

# 内存管理机制 = 引用计数器机制 + 垃圾回收机制
# 当一个对象, 如果被引用 + 1, 删除一个引用: -1   0: 被自动释放
# 循环引用

# objgraph
# objgraph.count() 可以查看,垃圾回收器,跟踪的对象个数

import objgraph

class Person:
    pass

class Dog:
    pass

p = Person()
d = Dog()

print(objgraph.count("Person"))
print(objgraph.count("Dog"))
p.pet = d
d.master = p
# 删除p,d之后,对应的对象是否被释放
del p
del d
print(objgraph.count("Person"))
print(objgraph.count("Dog"))
# 1
# 1
# 1
# 1
# 并没有被释放,引用计数器的弊端
  1. 垃圾回收(引用计数器的扩展)
  1. 主要作用:从经历过“引用计数器机制”仍未被释放的对象中,找到“循环引用”,干掉相关对象
  2. 底层机制(难 没看懂)
  3. 垃圾回收时机
  • 自动回收
# 1. 自动回收

# 开启垃圾回收机制
# gc.enable # 开启垃圾回收机制(默认开启)
# gc.disable # 关闭
# gc.isenabled # 判定是否开启
import gc
gc.disable()
print(gc.isenabled())
gc.enable()
print(gc.isenabled())

# 并且
# 达到了垃圾回收的阈值
# 垃圾回收器中,新增的对象个数和释放的对象个数之差达到某个阈值
# 涉及方法
#     gc.get_threshold() 获取自动回收阈值
#     gc.set_threshold() 设置自动回收阈值

print(gc.get_threshold())
  • 手动回收
#  2. 手动回收
import objgraph
import gc
class Person:
    pass
class Dog:
    pass
p = Person()
d = Dog()

p.pet = d
d.master = p

del p
del d

gc.collect() #并不关心垃圾回收机制是否开启 

print(objgraph.count("Person"))
print(objgraph.count("Dog"))