1.del
销毁魔术方法
触发时机:当一个对象在内存中被销毁的时候自动执行
参数:至少有一个self,接收对象
返回值:无
作用:在对象销毁的时候做一些操作
注意:程序自动调用此方法,不需要我们手动调用。
class Person(object):
def __init__(self):
print('init了...')
# 当没有对象引用的时候,自动执行
def __del__(self):
print('销毁了...')
person = Person()
del person # 手动销毁内存中的对象
print('程序结束了...')
# print(person) # 报错,找不到person对象
运行结果:
init了...
销毁了...
程序结束了...
2、call
call():可以让类的实例具有类似于函数的行为,
进一步模糊了函数和对象之间的概念。
使用方式:
对象后面加括号,触发执行。即:对象() 或者 类()()
class Person(object):
def __call__(self, *args, **kwargs): # 参数可传可不传
print('call...')
person=Person() # 将Person()的内存地址赋值给person
person() # 内存地址
Person()() # 内存地址
Person()(10)
运行结果:
call...
call...
call...
练习 使用__call__方法实现斐波那契数列
class Fibonaqi():
def __call__(self, num):
a=1
b=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.lst
fibo=Fibonaqi()
a=int(input('请输入要取得斐波那契数的个数:'))
ret=fibo(a)
print(ret)
运行结果:
请输入要取得斐波那契数的个数:5
[1, 1, 2, 3, 5]
3.repr
repr():改变对象的字符串显示
-
此方法是__str__()的备胎,如果找不到__str__()就会找__repr__()方法。
-
%r 默认调用的是 repr()方法,如果是字符串会默认加上 ‘’
-repr()方法默认调用__repr()方法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 # 如果没有__str__的时候,会执行__repr__方法 # 如果有就不执行__repr__方法 def __repr__(self): msg='name--->{},age--->{}'.format(self.name,self.age) return msg person=Person('zs',20) print(person) s1='hello' print('i Say %s' % s1) # i Say hello print('i Say %r' % s1) # i Say 'hello' # 多添加了一对单引号 print('i Say %s' % person) # i Say name:zs,age:20 # 调用__str__方法 print('i Say %r' % person) # i Say name--->zs,age--->20 # 调用__repr__方法 # 使用内置repr()方法,默认调用对象的__repr__方法 print(repr(person)) # 默认调用__repr__方法 # name--->zs,age--->20
运行结果:
name:zs,age:20
i Say hello
i Say 'hello'
i Say name:zs,age:20
i Say name--->zs,age--->20
name--->zs,age--->20
4.new
实例化魔术方法
触发时机: 在实例化对时触发
参数:至少一个cls 接收当前类
返回值:必须返回一个对象实例
作用:实例化对象
注意:实例化对象是Object类底层实现,其他类继承了Object的__new__才能够实现实例化对象。
没事别碰这个魔术方法,先触发__new__才会触发__init__
class Person(object):
# 初始化
def __init__(self):
print('init...')
# 实例化方法(构造方法) ---->创建对象,如果没有此方法,将会默认调用父类的__new__方法
#
def __new__(cls, *args, **kwargs):
print('new...')
ret = super().__new__(cls) # 调用父类的__new__方法创建对象,然后用返回值来接收
# print(ret)
return ret # 将对象返回给person
person = Person()
# print(person)
print(id(person))
person1=Person()
print(id(person1))
运行结果:
new...
init...
35706864
new...
init...
35706976
4.Python中的比较is和 ==
is 比较两个对象的 id 值是否相等,是否指向同一个内存地址;
== 比较的是两个对象的内容是否相等,即内存地址可以不一样,内容一样就可以了。
默认会调用对象的 eq()方法。继承自 object 的 eq 方法比较两个对象的id
简单举例;
lst1=['a','b','c']
lst2=['a','b','c']
print(lst1==lst2) # True 比较的是值
print(id(lst1)) # 31702216
print(id(lst2)) # 31728648
print(lst1 == lst2) # True 比较的是内容
print(lst1 is lst2) # False 比较的是内存地址
运行结果;
True
31702216
31728648
True
False
per1=Person('zs',10)
per2=Person('zs',10)
print(per1.__dict__) # {'name': 'zs', 'age': 10}
print(per2.__dict__) # {'name': 'zs', 'age': 10}
print(per1 == per2) # True
print(per1 is per2) # False
lst=[]
per1=Person('zs',10)
per2=Person('zs',10)
lst.append(per1)
# in: 底层调用的是==
if per2 not in lst:
lst.append(per2)
else:
print('已经有了')
运行结果:
{'name': 'zs', 'age': 10}
{'name': 'zs', 'age': 10}
True
False
已经有了
通过在添加对象方法__eq__方法来返回比较的内容,进而就可以进行 == 的比较。
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
# 在父类__eq__方法中比较,默认返回id值,在这里复写,返回的是
# 实例对象的属性,以字典的形式返回
def __eq__(self, other):
return self.__dict__ == other.__dict__
per1 = Person('zs', 10)
per2 = Person('zs', 10)
print(per1.__dict__) # {'name': 'zs', 'age': 10}
print(per2.__dict__) # {'name': 'zs', 'age': 10}
print(per1 == per2) # True
print(per1 is per2) # False
5.hash
哈希(hash)也翻译作散列。Hash算法,是将一个不定长的输入,通过哈希函数变换成一个定长的输出,即哈希值。
这种哈希变换是一种单向运算,具有不可逆性即不能根据哈希值还原出输入信息。常见的hash算法有:SM3、MD5、SHA-1等 。
Hash主要应用在数据结构以及密码学领域。
在不同的应用场景下,hash函数的选择也会有所侧重。比如在管理数据结构时,主要要考虑运算的快速性。
在python中有内置的哈希函数hash(),返回一个对象(数字、字符串,不能直接用于 list、set、dictionary)的哈希值。示例代码如下:
s = ‘hello’
ret = hash(s)
print(ret)
运行结果:
2375505071164695267
在python中set集合要求数据类型是可哈希的,因为set集合会默认调用对象的__hash__函数进行快速查询,如果找到了则调用对象的__eq__判断两个是是否相同,如果相同则不添加。
保证数据的唯一性(自动去重功能)。
dict 数据结构的key必须是可哈希的,因为dict是无序的因此通过key的hash算法来快速查询,节约时间。
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
person1 = Person('zs', 32)
person2 = Person('ls', 32)
person3 = Person('ww', 32)
set1 = {person1, person2, person3}
print(set1) # 打印的是set1的内存地址 # {<__main__.Person object at 0x00000000023CD860>, <__main__.Person object at 0x00000000023CD898>}
# 默认object.__hash__()算出来的值是,id值的1/16
print(id(person1)/hash(person1)) # 16.0
# 内置方法默认调用对象的__hash__()方法
print(id(person1)) # 35637232
print(hash(person1)) # 2227327
print(id(person1) / hash(person1)) # 16.0
1.自定义对象能不能添加到集合中呢?能默认调用父类的__hash__和__eq__
2.object的 hash 值是怎么算的呢,id 是hash 的16倍
3.自定义对象添加到集合中,一般认为两个对象的属性值相同就是同一个对象
–自定义计算规则。
4.注意,如果只定义了__eq__方法,没有定义__hash__方法,__hash__方法会隐式设置成None
在自定义类中,如果没有实现__eq__()和__hash__()方法,会继承object的__eq__()方法和__hash__()方法。
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
# 如果只定义了__eq__方法,没有定义__hash__方法,那么就是不可哈希类型
def __eq__(self, other):
return self.__dict__ == other.__dict__
def __hash__(self):
return hash(self.name)+hash(self.age)
person1 = Person('zs', 32)
person2 = Person('zs', 32)
# 去重原理。先根据哈希值快速查找,__hash__() --->hash值 --->id()
# id不同,哈希值就不同
# 需求:只要是对象的属性值相同.就认为是一个对象,就不让添加
# person1--->hash值
set1={person1}
set1.add(person2) # person1和person2内容相同,id不同,根据集合去重原理,在__eq__方法和__hash__方法同时创建的情况下,会检测到他们两个的哈希值不同,但是内容相同,将不会添加person2,将只打印person1的内存地址.
print(set1)
# print(id(person1)/ha sh(person1))
运行结果:
{<__main__.Person object at 0x00000000021CD860>}