类的常用魔法函数
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