python中的常用魔术方法

常用魔术方法

1.__del__方法

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

class Person(object):

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

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


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

输出为:

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

如上代码所示,当程序运行结束时,没有再引用的变量时,__del__会生效,所以它不是像我们预想的那样,调用这个对象时__del__就生效,所以 不会输出

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

2.__call__方法

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

class Person(object):

    def __call__(self, *args, **kwargs):
        print('call...')


person = Person()  # 将Person()的内存地址赋值给person
person()  # 内存地址()
#或者是Person()()

输出为:

call...

如上代码所示,调用__call__时,并不需要person.__call__。因为在person=Person()时,就已经将Person()的内存地址赋值给了person,所以后面调用时person本身就代表了那个内存地址,当成函数使用person()

使用__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.lst


fibo = Fibonacci()
ret = fibo(10)
print(ret)

输出如下:

[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

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:%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

如果是使用%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

print('%s' % person)
print('%r' % person)

输出为:

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

或者使用print(repr(person))

print(repr(person))

输出为:

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

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 0x00000000021CC860>

如上代码所示,要先创建一个对象,才能初始化,所以输出是先输出new…,才输出init…

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

但是

class Person(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age


per1 = Person('lee', 10)
per2 = Person('lee', 10)
print(per1 == per2)
print(per1 is per2)

输出为:

False
False

是因为,它们在比较时候,调用的是对象中的__eq__方法比较,其默认比较的是内存地址。
如果要更改比较方式,则需要在__eq__方法中修改一下,如下代码所示

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('lee', 10)
per2 = Person('lee', 10)
print(per1 == per2)
print(per1 is per2)

输出为:

True
False

7.__hash__方法

哈希(hash)也翻译作散列。Hash算法,是将一个不定长的输入,通过哈希函数变换成一个定长的输出,即哈希值。
这种哈希变换是一种单向运算,具有不可逆性即不能根据哈希值还原出输入信息。常见的hash算法有:SM3、MD5、SHA-1等 。
Hash主要应用在数据结构以及密码学领域。
在不同的应用场景下,hash函数的选择也会有所侧重。比如在管理数据结构时,主要要考虑运算的快速性。
在python中有内置的哈希函数hash(),返回一个对象(数字、字符串,不能直接用于 list、set、dictionary)的哈希值。示例代码如下:

s = 'hello'
ret = hash(s)
print(ret)

输出的结果为:

2362592656088286249

在python中set集合要求数据类型是可哈希的,因为set集合会默认调用对象的__hash__函数进行快速查询,如果找到了则调用对象的__eq__判断两个是是否相同,如果相同则不添加。
保证数据的唯一性(自动去重功能)。
dict 数据结构的key必须是可哈希的,因为dict是无序的因此通过key的hash算法来快速查询,节约时间。
在这里插入图片描述
在这里插入图片描述

在自定义类中,如果没有实现__eq__()和__hash__()方法,会继承object的__eq__()方法和__hash__()方法。

hash()函数默认调用Object类的__hash__()方法。Hash值是对象id值1/16。

在这里插入图片描述
自定义对象添加到集合中,我们一般认为两个对象的属性值相同就是同一个对象。因此需要我们手动复写__eq__方法和__hash__方法。

用__hash__方法和__eq__方法解释集合去重

class Person(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __eq__(self, other):
        return self.__dict__ == other.__dict__

    def __hash__(self):
        return hash(self.name) + hash(self.age)


# 集合自动去重
# 先根据hash去快速查询有没有一个对象的hash值和我的相同
per1 = Person('zs', 10)
per2 = Person('zs', 10)
set1 = {per1, per2}
print(set1)

输出为:

{<__main__.Person object at 0x0000000001E7C8D0>}

猜你喜欢

转载自blog.csdn.net/weixin_44251004/article/details/86503238