程序员最近都爱上了这个网站  程序员们快来瞅瞅吧!  it98k网:it98k.com

本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长

+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

魔术方法

发布于2019-08-20 12:27     阅读(1523)     评论(0)     点赞(12)     收藏(5)


常用魔术方法

1、__ del __( )方法

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

2、__ call __( )方法

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

class Person():
    def eat(self):
        print('xxx')
    def __call__(self, *args, **kwargs):
        print('zzz')

person = Person()
person()
print('程序结束了')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

3、__ repr __( )方法

改变对象的字符串显示
此方法是__ str__()的备胎。如果找不到__str__()就会找__repr__()方法。
%r 默认调用的是 __ repr__()方法,如果是字符串会默认加上 ’ ’
repr()方法 默认调用__repr__()方法

class Person():
    def __init__(self,name,age):
        self.name = name
        self.age = age
    # def __str__(self):
    #     return str(self.__dict__)
    def __repr__(self):
        s = 'name:%s age:%s'%(self.name,self.age)
        return s

per = Person('zs',13)
print(per)
# 有__str__()方法就会调用__str__()方法
# 如果没有__str__()方法就会调用__repr__()方法
# %r 调用字符串 默认 给字符串加 ''
# text = 'I am 22 years old.'
# print('I said:%s.'%text)
# print('I said:%r'%text)
# %r 默认调用__repr__()
print('I said:%r.'%per) # 调用__repr__()
# print('I said:%s'%per) # 调用__str__()
# repr() 默认调用__repr__()方法。
print(repr(per))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

4、__ new __( )方法 (重点)

实例化魔术方法
触发时机:在实例化对象时触发
参数:至少一个cls接收当前类
返回值:必须返回一个对象实例
作用:实例化对象
注意:实例化对象是Object类底层实现,其他类继承了Object的__new__才能够实现实例化对象。
没事别碰这个魔术方法
先触发__new__才会触发__init__

练习1:查看__new__方法的执行时机
class Dog():
    def __new__(cls, *args, **kwargs):
        print('----__new__----')
    def __init__(self):
        print('__init__')
    def __del__(self):
        print('__del__')

# 1.只复写__new__()方法
dog = Dog()
print(dog) # None 说明没有创建对象,刚才不是说它负责创建对象吗
# 因为我们重写了__new__方法,只是打印没有实现创建对象的功能
# 调用父类的__new__方法就可以创建对象了
'''
打印结果:
----__new__----
None
'''
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
# 练习2:调用父类的__new__方法,创建当前对象。
class Dog():
    def __new__(cls, *args, **kwargs):
        print('----__new__----')
        new__ = object.__new__(cls)
        return new__
# 创建对象
dog1 = Dog()
print(dog1)
'''
打印结果:
----__new__----
None
'''
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

5、__ str __( )方法

触发时机:使用print(对象)或者str(对象)的时候触发
参数:一个self接收对象
返回值:必须是字符串类型
作用:print(对象)时,进行操作,得到字符串,通常用于快捷操作
在Python中 使用print()函数输出对象名称的时候默认情况下,会打印对象名引用的内存地址,
如果希望打印对象的属性值,可以使用__str__(self)这个方法。

# 创建Cat类,向控制台打印cat对象的name和age的值。
class Cat():
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def __str__(self):
        return '姓名:{},年龄:{}'.format(self.name,self.age)

cat = Cat('tom',10)
print(cat) # 姓名:tom,年龄:10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

6、is和==区别

is 比较两个对象的id值是否相等,是否指向同一个内存地址;
== 比较的是两个对象的内容是否相等,即内存地址可以不一样,内容一样就可以了。
默认会调用对象的__eq__()方法。继承自object的__eq__()方法比较两个对象的id

# 1.a和b的地址相同
a = ['I','love','python']
b = a # 将a的地址赋值给b
print(a,id(a))
print(b,id(b))
print(a is b)
print(a == b)
# 2.a和b的地址不同
a = ['I','love','python']
b = ['I','love','python']
print(a,id(a))
print(b,id(b))
print(a is b)
print(a == b)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
class Person():
    def __init__(self,name,age):
        self.name = name
        self.age = age
    # def __eq__(self, other):
    #     return self.__dict__ == other.__dict__

per1 = Person('zs',12)
per2 = Person('zs',13)
per3 = Person('zs',12)
print(id(per1))
print(id(per2))
print(id(per3))
# 1.对象值不同进行比较
print(per1 is per2) # False
print(per1 == per2) # False 值不相同
# 2.对象值相同进行比较
print(per1 is per3) # False
print(per1 == per3) # False 值相同为什么是False呢?而list中的==就相同了呢。
# 默认调用的是对象的__eq__()方法
# object.__eq__()方法 默认比较的是两个对象的地址
per3 = per1 # 把per1的地址赋值给per3
print(per3==per1) # True,为什么
# 3.对于自定义对象一般我们认为对象的值相同就是同一个对象。因此需要复写__eq__()方法
print(per1 == per3) # True
# 练习:在实际应用中,有一个场景是处理对象是否在list里,不在就加入。
# 注意:list的in操作就是通过==来判断是否在list中。
lst1 = []
lst1.append(per1)
print(lst1) # [<__main__.Person object at 0x0000000002149748>]
if per3 not in lst1:
    lst1.append(per3)
print(lst1) # [<__main__.Person object at 0x0000000002149748>]
# per1 和 per3的值相同,所以我们认为per1和per3是同一个对象,所以per3(即per1)在列表中,所以if条件不满足,lst1中只有一个元素
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

注意:
因为python缓存并复用了小的整数和小的字符串,对象42也许并不像我们所说的被回收;
相反地,它将可能仍被保存一个系统表中,等待下次你的代码生成42来重复利用。
尽管这样,大多数种类的对象都会在不再引用时马上回收,对那些不会被回收的,缓存机制与代码并没有什么关系。

a = 42
b = 42
print(a is b) # True
print(a == b) # True
  • 1
  • 2
  • 3
  • 4

7、__ hash __( )方法

哈希(hash)也翻译作散列。Hash算法,是将一个不定长的输入,通过哈希函数变换成一个定长的输出,即哈希值。
这种哈希变换是一种单向运算,具有不可逆性即不能根据哈希值还原出输入信息。常见的Hash算法有:SM3、MD5、SHA-1等。
Hash主要应用在数据结构以及密码学领域。
在不同的应用场景下,hash函数的选择也会有所侧重。比如在管理数据结构时,主要考虑运算的快速性。
在python中有内置函数hash(),返回一个对象(数字、字符串,不能直接用于list、set、dictionart)的哈希值。
在python中set集合要求数据类型是可哈希的,因为set集合会默认调用对象的__hash__函数进行快速查询,如果找到了则调用对象的__eq__判断两个是否相同,如果相同则不添加。
保证数据的唯一性(自动去重功能)
dict数据结构的key必须是可哈希的,因为dict是无序的因此通过key的hash算法来快速查询,节约时间。

set1 = {'a','b',[1,2,3]}
print(set1) # 报错,[1,2,3]列表时不可哈希的。
  • 1
  • 2
class Person():
    def __init__(self,num):
        self.num = num

p1 = Person(1)
p2 = Person(2)
p3 = Person(3)
lst = [p1,p2,p3]
set1 = set(lst)
print(set1)
# hash()函数默认调用object类的__hash__()方法。
# 默认object.__hash__()方法的哈希值是 id值/16
print(id(p1)/16) # 180781786495.0
print(hash(p1))  # 180781786495 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14


所属网站分类: 技术文章 > 博客

作者:239289

链接:https://www.pythonheidong.com/blog/article/49233/22f856cc3b1c67792af2/

来源:python黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

12 0
收藏该文
已收藏

评论内容:(最多支持255个字符)