一 常用的魔术方法
1.__del__
销毁魔术方法
触发时机:当一个对象在内存中被销毁的时候自动执行
参数:至少有一个self,接收对象
返回值 : 无
作用 : 在对象销毁的时候做一些操作
注意 : 程序自动调用此方法,不需要我们手动调用
练习1 : 测试__del__()方法的执行时机
class Person(object):
def __init__(self):
print('init...')
def __del__(self):
print('销毁了')
per1 = Person()
del per
per2 = Person()
print('程序结束了')
"""
init......
销毁了
程序结束了
"""
per 是一个全局变量,当程序执行完后,per变量才会从内存中消失,因此先打印‘’销毁了‘’
在打印‘程序结束了’
del关键字 是从内存中删除变量,因此先打印‘init...’
2 __call__ ()
__call__():可以让类的实例具有类似于函数的行为,进一步模糊了函数和对象之间的概念。
使用方式:
对象后面加括号,触发执行,即:对象()或者类()()
class Person(object):
def __call__(self,*args,**kwargs):
print('call...')
#调用方式
person = Person() #将Person地址赋值给person
person() #内存地址调用
Person()() #内存地址调用
"""
call...
call...
"""
练习2 使用__call__方法实现斐波那契数列
class Fibonacci(object):
def __call__(self,num):
a,b = 1,1 #元组方式
self.lst = []
if num <= 2 :
self.lst.append(a)
self.lst.append(b)
else:
for i in range(1 , num + 1):
self.lst.append(a)
a,b = b , a + b
return self.let
fibo = Fibonacci()
ret = fibo(8)
print(ret)
"""
[1, 1, 2, 3, 5, 8, 13, 21]
"""
3 __repr__
__repr__():改变对象字符串显示
此方法是__str__()的备胎,如果找不到__str__()就会找__repr__()的方法
--%r 默认调用的是__repr()方法,如果是字符串会默认加上' '
-- repr()方法默认调用__repr__(方法)
calss Person(object):
def __init__(self,name,age):
self.name = name
self.age = age
def __str__(self):
msg = 'name{},age{}'.format(self.name,self.age)
return msg
#如果没有__str__的时候,会执行__repr__方法
#如果有就不执行
def __repr__(self):
msg = 'name--->>>{},age--->>>{}'.format(self.name,self.age)
return msg
person = Person('赵四',30)
print(person) #name赵四,age30
#当注释掉__str__时 #name--->>>赵四,age--->>>30
print('%s' % person) #name赵四,age30
print('%s' % person) #name---->>赵四,age---->>30
print(repr(person)) #name---->>赵四,age---->>30
4 __new__()方法
实例化魔术方法
触发时机:在实例化对象时触发
参数:至少一个cls 接受当前类
返回值 : 必须返回一个对象实例
作用:实例对象化
注意:实例对象化是object类底层实现,其他类继承了object的__new__才能够实现实例化对象
PS : 没事别碰这个魔术方法,先触发__new__才会触发__init__
class Person(object):
def __init__(self):
print('init...')
#实例化方法(构造方法)————>>先创建对象,在初始化 所以先执行__new__,再执行__init__
def __new__(cls,*args,**kwargs):
print('new...')
ret = super().__new__(cls) #调用父类中的__new__方法 创建对象
#接受返回值
return ret
person = Person()
print(person)
"""
new...
init...
<__main__.Person object at 0x0000000001170EB8>
"""
5 python中的比较 is 和 ==
is 比较两个对象的 id 值是否相等,是否指向同一个内存地址;
== 比较的是两个对象的内容是否相等,即内存地址可以不一样,内容一样就可以了。
默认会调用对象的 __eq__()方法。继承自 object 的 __eq__ 方法比较两个对象的id
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def __eq__(self, other):
return self.__dict__ == other.__dict__ #判断值是否相等
per1 = Person('zs',10)
per2 = Person('zs',10)
print(per1.__dict__) #{'age': 10, 'name': 'zs'}
# per2 = per1
print(per1 == per2) #True
print(per1 is per2) #False
class Person(object):
def __init__(self,name,age):
self.name = name
self.age = age
# def __eq__(self, other):
# print('xxx')
def __eq__(self,other):
return self.__dict__ == other.__dict__
per1 = Person('zs',12)
per2 = Person('ks',24)
per3 = Person('ww',36)
# print(id(per1)) #12062560
# print(id(per2)) #12062616
# print(id(per3)) #12062672
#1对象值不同进行比较
print(per1 is per2) #False
print(per1 == per2) #False 值不相同
#2 对象值相同进行比较
print(per1 is per3) #False
print(per1 is per3) #False 值不相同为什么还是False呢?
# 而list中的 == 就相同了呢
# == 默认调用的是对象的__eq__()方法。object.__eq__()方法
#默认比较的是两个对象的地址
per3 = per1
6 __hash__
哈希(hash)也翻译做散列。Hash算法,是将一个不定长的输入,用过哈希函数换成一个定长的输出,即哈希值
这种哈希变换也是一种单向运算,具有不可逆性即不能根据哈希值还原出输入消息。常见的hash算法有:SM3 MD5 SHA-等等
hash主要应用在数据结构和密码数学领域
在不同的应用场景下,hash函数的选择也会有所侧重。比如在管理数据结构时,主要要考虑运算的快速性
在python中有内置的哈希函数hash(),返回一个对象(数字 字符串 不能直接用于list set dictionary)的哈希值,示例代码如下
s = 'a'
ret = hash(s)
print(ret)
#840845198308593275
在python中set集合要求数据类型是可哈希的,因为set 集合会默认调用的__hash__函数进行快速查询时,如果找到了则调用对象__eq__判断两个是否相同
如果相同则不添加。保证数据的唯一性(自动去重功能)
dict 数据结构类型的key必须是可哈希的,因为dict是无序的,因此通过key的hash算法来快速查询,节约时间
不可哈希数据类型 内部__hash__直接等于了None set集合无法通过内置的__hash__来算出哈希值,因此不能存放
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
msg = 'name{},age{}'.format(self.name, self.age)
return msg
per1 = Person('zs',10)
per2 = Person('kh',30)
per3 = Person('ww',60)
set = {per1,per2,per3 }
print(set)
#默认 object 中的__hash__()算出来的值,是id值得1/16
print(id(per1)/hash(per1))
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
# def __str__(self):
# msg = 'name{},age{}'.format(self.name, self.age)
# return msg
# 在向集合添加元素时,要判断哈希值 和属性值 所以要福复写一下两个方法
def __eq__(self, other):
return self.__dict__ == other.__dict__
def __hash__(self):
return hash(self.name)+hash(self.age)
per1 = Person('zs',10)
per2 = Person('kh',10)
集合去重原理 :先根据哈希值快速查找,又没有一个对象的哈希值和我的相同,
再比较属性值是否相同,所以要用__eq__()比较属性值
__hash__()--->>hash值 --->>> id 值
id不同 hash就不同
需求 只要是对象的属性值相同,就认为是同一个对象,就不让添加
print(per1)
print(per2)
set = {per1}
set.add(per2)
print(set)
自定义对象添加到集合中,我们一般认为两个对象的属性值相同就是同一个对象。因此需要我们手动复写__eq__方法和__hash__方法。
注意,如果只定义了__eq__方法,没有定义__hash__方法,__hash__方法会隐式设置成None