魔术方法:就是类中的方法(预定义的方法),在某个特定的时机会被自动的调用。

  1、__del__():销毁对象时,被自动的调用

 1 class Person:
 2     def __init__(self, name):
 3         self.name = name
 4         print('%s 被初始化' % self.name)
 5 
 6     def __del__(self):
 7         print("%s 被删除 " % self.name)
 8 
 9 
10 p1 = Person("奶茶")
11 p2 = Person("蛋糕")
12 
13 print('xixi')
14 del p1
15 print('haha')
16 
17 # 奶茶 被初始化
18 # 蛋糕 被初始化
19 # xixi
20 # 奶茶 被删除
21 # haha
22 # 蛋糕 被删除

  2、__call__():

    功能:让类的实例具有类似有函数(方法)的功能。让对象可以被调用, 调用时执行的就是__call__中的函数体

    触发时机:调用对象的时候——对象()

 1 class Person:
 2     def __init__(self, name, sex, age, sister=None, brother=None):
 3         self.name = name
 4         self.sex = sex
 5         self.age = age
 6         self.sister = sister
 7         self.brother = brother
 8 
 9     def __call__(self):  # 获取....
10         if self.sex == "boy":
11             print(self.sister)
12         else:
13             print(self.brother)
14 
15     def get_age(self):
16         print(self.age)
17 
18 
19 p1 = Person("xixi", "boy", 18, "haha")
20 print(p1.name)  # xixi
21 p1.get_age()  # 18
22 p1()  # haha

  3、__repr__():print(对象) 打印对象时会被调用

    __str__():print(对象) 打印对象时会被调用
   

    print(对象)默认情况下打印结果是,对象的内存地址
    重写__str__()方法,返回什么,print(对象)打印的结果就是什么

    区别与联系:

      1、TypeError:__repr__ returned non-string (type NoneType)
        以上两个函数都必须有返回值,且返回值类型为str类型;

      2、打印对象时, 如果使用%s占位符, 默认调用的是__str__()方法
        如果使用%r占位符, 默认调用的是__repr__()方法

      3、有repr, 没有str时,%s、%r 都可调用repr方法;
         没有repr, 有str时, %s 调用的是str的方法,%r 打印的是对象的地址(默认的)

      4、print(repr(对象)) 默认调用__repr__()方法
         print(str(对象)) 默认调用__str__()方法

 1 class Person:
 2     def __init__(self, name):
 3         self.name = name
 4 
 5     def __str__(self):
 6         return "我是str"
 7 
 8     def __repr__(self):
 9         return "我是repr"
10 
11 
12 p1 = Person("xixi")
13 # repr&str方法都没有
14 # print(p1)  # <__main__.Person object at 0x000000000214D198>
15 
16 # repr&str方法都有
17 # print("%s" % p1)  # 我是str
18 # print("%r" % p1)  # 我是repr
19 
20 # 只有repr方法:
21 # print("%s" % p1)  # 我是repr
22 # print("%r" % p1)  # 我是repr
23 
24 # 只有str方法
25 # print("%s" % p1)  # 我是str
26 # print("%r" % p1)  # <__main__.Person object at 0x00000000026BD198>
27 
28 print(repr(p1))
29 print(str(p1))

  4、__new__(cls):类方法

    功能:实例化一个对象

    触发时机:当实例化对象的时候,会被自动调用

    返回值:实例化的那个对象;

    __new__(cls)方法将实例化的对象传递给__init__(self)方法的第一个参数;

    __new__()是object类底层的实现——单例

 1 class Person:
 2     def __new__(cls, *args, **kwargs):  # 必须有返回值: 创建好的对象,类的实例
 3         print("我是new")
 4         return super().__new__(cls)
 5 
 6     def __init__(self):
 7         print("我是init")
 8 
 9 
10 p = Person()  # 创建对象
11 # 我是new
12 # 我是init
13 print(p)  # <__main__.Person object at 0x0000000001EA8358>

  5、__eq__:   

    只要俩对象的属性值都相等, 我们就认为这俩对象相等
    通过__eq__()方法去实现,必须有返回值bool用来代表是否相等
    使用__eq__()方法定义比较的规则,对象进行比较时需要使用 == 关系运算符进行比较

 

    对象.__dict__ 获取当前对象的属性, 包括私有(字典{"属性名": "属性值", ...})

 

    (1)基础数据类型的对象
      is : 比较的是对象的地址
      == : 比较的是对象的内容

 

      cmd 对于小整数 [-5, 256] 之间的数字进行了缓存,所以可以在缓存中重复使用
      pycharm做了优化,他把不可变数据类型中的很大范围的数据都做了缓存,所以在缓存中可以重复使用
      在pycharm中对某些即使很大的整数进行地址的比较 is 都是相等的

 

    (2)自定义类的对象
      is 和 == 比较的都是对象的地址

 

 1 a = "12345"
 2 b = "12345"
 3 
 4 print(a == b)  # True
 5 print(a is b)  # True
 6 print(id(a))  # 4772224
 7 print(id(b))  # 4772224
 8 
 9 
10 list1 = [1, 2, 3, 4]
11 list2 = [1, 2, 3, 4]
12 print(list1 == list2)  # True
13 print(list1 is list2)  # False
14 print(id(list1))  # 63488968
15 print(id(list2))  # 63184328
16 
17 
18 class Person:
19     def __init__(self, name, age):
20         self.name = name
21         self.age = age
22 
23     def __eq__(self, other):  # other, 另外一个要进行比较的对象
24         if self.__dict__ == other.__dict__:  # 如果当前对象和被比较对象的所有属性值相等, 我们就认为这俩对象相等
25             return True
26         else:
27             return False
28 
29 
30 p1 = Person('xixi', 6)
31 p2 = Person('xixi', 6)
32 print(p1 == p2)  # True
33 print(p1 is p2)  # False
34 print(id(p1))  # 43097840
35 print(id(p2))  # 43101544

 

  6、__hash__() : 当获取对象的哈希值时,调用该魔术方法

    hash(对象)

    set, list, dict 没有__hash__()方法, hash(列表对象):报错,不可被哈希
    列表对象.__hash__ ——> None

    如果只定义了__eq__()方法, 而没有定义__hash__(), 默认会将__hash__方法设置为None

 1 # 设计二维坐标类Point判断2个坐标是否相等,
 2 # 并能根据hash函数计算坐标的哈希值;
 3 
 4 class Point:
 5     def __init__(self, x, y):
 6         self.x = x
 7         self.y = y
 8 
 9     def __eq__(self, other):
10         if self.x == other.x and self.y == other.y:
11             return True
12         else:
13             return False
14 
15     def __hash__(self):
16         return hash((self.x, self.y))
17 
18 point1 = Point(3, 4)
19 point2 = Point(3, 4)
20 
21 print(point1 == point2)  # True
22 
23 print(hash(point1))  # 3713083796997400956
24 print(hash(point2))  # 3713083796997400956