您的位置:首页 > 编程语言 > Python开发

Python基础 面向对象常用魔术方法

2019-01-16 21:51 399 查看

一 常用的魔术方法

1.__del__

销毁魔术方法

触发时机:当一个对象在内存中被销毁的时候自动执行

参数:至少有一个self,接收对象

返回值 : 无

作用 : 在对象销毁的时候做一些操作

注意 : 程序自动调用此方法,不需要我们手动调用

练习1 : 测试__del__()方法的执行时机

[code]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__():可以让类的实例具有类似于函数的行为,进一步模糊了函数和对象之间的概念。

使用方式:

对象后面加括号,触发执行,即:对象()或者类()()

[code]class Person(object):
def __call__(self,*args,**kwargs):
print('call...')

#调用方式
person = Person()  #将Person地址赋值给person
person()           #内存地址调用
Person()()         #内存地址调用

"""
call...
call...
"""
[code]练习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__(方法)

[code]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__

[code]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

[code]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
[code]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)的哈希值,示例代码如下

[code]s = 'a'
ret = hash(s)
print(ret)
#840845198308593275

在python中set集合要求数据类型是可哈希的,因为set 集合会默认调用的__hash__函数进行快速查询时,如果找到了则调用对象__eq__判断两个是否相同

如果相同则不添加。保证数据的唯一性(自动去重功能)

dict 数据结构类型的key必须是可哈希的,因为dict是无序的,因此通过key的hash算法来快速查询,节约时间

不可哈希数据类型 内部__hash__直接等于了None set集合无法通过内置的__hash__来算出哈希值,因此不能存放

[code]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))
[code]
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

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: