类的魔法函数、python回收机制

类的常用魔法函数

1、__del__方法

销毁魔术方法
触发时机:当一个对象在内存中被销毁的时候自动执行
参数:至少有一个self,接收对象
返回值:无
作用:在对象销毁的时候做一些操作
注意:程序自动调用此方法,不需要我们手动调用。

class Person(object):

    def __init__(self):
        print('init')

    def __del__(self):
        print('销毁了。。。')


person = Person()
person1 = person
print('程序结束了....')

init
销毁了。。。
程序结束了....

  这里就不得不提一下python的垃圾回收机制,Python采用的是引用计数机制为主,标记-清除和分代收集两种机制为辅的垃圾回收策略。

引用计数机制
  一个对象会记录着引用自己的对象的个数,每增加一个引用,个数+1,每减 少一个引用,个数-1,在检测到对象引用个数为0时,对普通的对象进行释放内存的机制。比如对于一个函数,调用该函数的时候引用加1,函数调用结束减1,当没有任何程序使用该函数时,引用为0,就释放该函数的内存。

标记-清除
  但是,引用计数机制有个很大的缺陷----无法解决循环引用的问题而导致内存耗尽。
例如:
list1 = []
list2 = []
list1.append(list2)
list2.append(list1)
  即使不存在其他引用,list1、list2也有相互引用存在,导致引用计数不为0,这就使得所占用的内存永远无法被回收,这将是致命的。所以引入标记-清除机制。

标记 - 清除算法由标记阶段和清除阶段构成。
  标记阶段:是把所有活动对象都做上标记的阶段。
  清除阶段:是把那些没有标记的对象,也就是非活动对象回收的阶段。
  通过这两个阶段,就可以令不能利用的内存空间重新得到利用。

分代回收
  为了解决由于在标记清除时,扫描链表时,它的对象比较多,并且为了设置对象扫描的优先级,设置了分代回收。分代垃圾回收(Generational GC)在对象中导入了“年龄”的概念,通过优先回收容 易成为垃圾的对象,提高垃圾回收的效率。
  我们把刚生成的对象称为新生代对象,到达一定年龄的对象则称为老年代对象。新生代 GC 将存活了一定次数的新生代对象当作老年代对象来处理。我们把类似于这 样的新生代对象上升为老年代对象的情况称为晋升(promotion)。老年代对象很难成为垃圾,所以我们对老年代对象减少执行 GC 的频率, 从而提高效率。
  然后我们回过头看刚开始的__del__的例子,就会明白,它时自己调用了该方法(内存销毁的时候),而不是我们手动去调用。

2、__call__方法

可以让类的实例具有类似于函数的行为,
进一步模糊了函数和对象之间的概念。
使用方式:对象后面加括号,触发执行。即:对象() 或者 类()()

class Person(object):

    def __call__(self, *args, **kwargs):
        print('这里使用了call方法')


person = Person()  # 将Person()的内存地址赋值给person
person()  # 把类当成函数使用,也可以是Person()()

这里使用了call方法

  上面例子若没有定义__call__方法,你使用person,会直接输出该函数的内存地址,并不会运行该函数,若未定义__call__方法直接使用person(),则会报错。

3、__repr__方法

repr():改变对象的字符串显示
此方法是str()的备胎,如果找不到__str__()就会找__repr__()方法。
%r 默认调用的是 repr()方法

class Person(object):

    def __init__(self, name, age):
        self.name = name
        self.age = age

#     def __str__(self):
#         msg = 'name:%s,age:%s' % (self.name, self.age)
#         return msg
    # 如果没有__str__的时候,就会执行__repr__方法
    # 如果有就不执行__repr__方法。
    def __repr__(self):
        msg = 'name----》%s,age----》%s' % (self.name, self.age)
        return msg


person = Person('lee', 30)
print(person)

name----》lee,age----30

  上面例子因为没有__str__(),所以调用的__repr__(),但当__str__()存在时,则不会调用__repr__()方法。

class Person(object):

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        msg = 'name:%s,age:%s' % (self.name, self.age)
        return msg
    # 如果没有__str__的时候,就会执行__repr__方法
    # 如果有就不执行__repr__方法。
    def __repr__(self):
        msg = 'name----》%s,age----》%s' % (self.name, self.age)
        return msg
person = Person('lee', 30)
print('%s' % person)
print('%r' % person)

name:lee,age:30
name----》lee,age----30

  上面例子因为虽然有__str__(),但调用时加了"%r",所以调用的是__repr__()方法。

4、__new__方法

实例化魔术方法
触发时机: 在实例化对时触发
参数:至少一个cls接收当前类
返回值:必须返回一个对象实例
作用:实例化对象
注意:实例化对象是Object类底层实现,其他类继承了Object的__new__才能够实现实例化对象。
没事别碰这个魔术方法,先触发__new__才会触发__init__

class Person(object):

    # 初始化
    def __init__(self):
        print('init...')

    # 实例化方法(构造方法)---》创建对象
    def __new__(cls, *args, **kwargs):
        print('new...')
        ret = super().__new__(cls) # 调用父类的__new__()方法创建对象,并用接收返回值
        return ret # 将对象返回给person


person = Person()
print(person)

new...
init...
<__main__.Person object at 0x000002539D833C08>

5、__str__方法

触发时机:使用print(对象)或者str(对象)的时候触发
参数:一个self接收对象
返回值:必须是字符串类型
作用:print(对象时)进行操作,得到字符串,通常用于快捷操作

class Cat(object):
    def __str__(self):
        return '这是一只猫'

cat=Cat()
print(cat)
这是一只猫

  在python中 使用print()函数输出对象名称的时候默认情况下,会打印对象名引用的内存地址,如果希望打印对象的属性值,可以使用__str__(self)这个方法。

6、Python中的比较is和==

is 比较两个对象的 id 值是否相等,是否指向同一个内存地址;
== 比较的是两个对象的内容是否相等,即内存地址可以不一样,内容一样就可以了。

lst1 = [1, 2, 3]
lst2 = [1, 2, 3]
print(lst1 == lst2)
print(lst1 is lst2)

True
False
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值