python的魔术方法

一、魔术方法特殊属性

  • __name__ : 类、函数、方法等的名字
  •  __module__: 定义所在的模块名
  •  __class__ : 对象或类所属的类
  •  __bases__ : 类的基类的元组,顺序为它们在基类列表中出现的顺序
  •  __doc__ : 类、函数的文档字符串,如果没有定义则为None
  •  __mro__ :类的mro,class.mro()返回结果的保存在__mro__中
  •  __dict__ : 类或实例的属性,可写的字典

二、查看属性

1、__dir__方法:

  • 返回类或者对象的所有成员名称列表,dir()函数就是调用__dir__方法
  • 如果提供__dir__(),则返回属性的列表,否则会尽量从__dict__属性中收集信息

2、dir()对应不同类型的对象具有不同的行为:

  •  如果对象是模块对象,列表包含模块的属性名
  •  如果对象是类型或类对象,列表包含类的属性名,机它的基类的属性名
  •  否则,列表包含对象的属性名,它的类的属性名和类的基类的属性名

三、魔术方法的分类

  • 创建与销毁:__init__与__del__
  • hash:__hash__方法:内建函数hash()调用的返回值,返回一个整数,如果定义这个方法该类的实例就可hash
举例:
    class A:
        def __init__(self):
            self.a = 'a'
            self.b = 'b'
        
        def __hash__(self):
            return 1
        
        def __eq__(self,other):
            return self.a = other.a

print(hash(A()))
print((A(),A()))
print({A(),A()})
s = {A(),A()}  # set集合
print(s)    

执行输出:
    1
    (<__main__.A object at 0x0000000004E4C780>, <__main__.A object at 0x0000000004E4C860>)
    {<__main__.A object at 0x0000000004E4C6D8>, <__main__.A object at 0x0000000004E4C860>}
    {<__main__.A object at 0x0000000004E4C780>, <__main__.A object at 0x0000000004E4C6D8>}

    上例set为什么不能剔除相同的key

1、__eq__方法:对应==操作符,判断2个对象是否相等,返回值bool

class A:
    def __init__(self):
        self.a = 'a'
        self.b = 'b'
    
    def __hash__(self):
        return 1
    
    def __eq__(self,other):
        return self.a == other.a

print(hash(A()))
print((A(),A()))
print({A(),A()})
s = {A(),A()}  # set集合
print(s)
执行输出:
1
(<__main__.A object at 0x0000000004E4C9B0>, <__main__.A object at 0x0000000004E4CB00>)
{<__main__.A object at 0x0000000004E4CB38>}
{<__main__.A object at 0x0000000004E4C9B0>}


__hash__方法只是返回一个hash值作为set的key,但是去重还需要__eq__来判断2个对象是否相等
hash值相等,只是hash冲突,不能说明两个对象是相等的,因此,一般来说提供__hash__方法是为了作为set或者dict的key的,所以去重要同时提供__eq__方法
可hash对象必须提供__hash__方法,没有提供的话,isinstance(p1,collections.Hashable)一定为False


2、list类为什么不可hash?

  • 源码中有一句__hash__ = None,也就是说如果调用__hash__()相当于None(),一定报错
  • 所有类都继承object,而这个类是具有__hash__()方法的,如果一个类不能被hash,就是把__hash__设置为None了
from collections import Hashable

class Point:
    def __init__(self,x,y):
        self.x = x
        self.y = y
    
    def __hash__(self):
        return hash((self.x,self.y))
    
    def __eq__(self,other):
        return self.x == other.x and self.y == other.y

p1 = Point(4,5)
p2 = Point(4,5)
print(hash(p1))
print(hash(p2))

print(p1 is p2)
print(p1 == p2)
print(set((p1,p2)))

执行输出:
    3713084879518070856
    3713084879518070856
    False
    True
    {<__main__.Point object at 0x0000000004E5C2E8>}

3、bool方法

  • __bool__方法: 内建函数bool(),或者对象放在逻辑表达式的位置,调用这个函数返回布尔值
  •  没有定义__bool__(),就找__len__()返回长度,非0为真,如果__len__()也没有定义,那么所有实例都返回真
举例:
    class A:
    pass

print(bool(A()))   #没有定义

    class B:
        def __bool__(self): # 定义了返回函数返回值
            return False

print(bool(B))
print(bool(B()))

    class C:
        def __len__(self):  #定义了len
            return 0
print(bool(C()))


四、可视化

  • __repr__ : 内建函数repr()对一个对象获取字符串表达,调用__repr__方法返回字符串表达;如果__repr__没有定义,就直接返回object的定义就是显示内存地址信息
  •  __str__ : str()函数,内建函数format,print()函数调用,需要返回对象的字符串表达;如果没有定义,就去调用__repr__方法返回字符串表达,如果__repr__没有定义,就直接返回对象的内存地址信息
  •  __bytes__ : bytes的时候,返回一个对象的bytes表达,即返回bytes对象
举例:
    class A:
    def __init__(self):
        self.a = 'a'
        self.b = 'b'
    def __repr__(self):
        return 'repr:{},{}'.format(self.a,self.b)
    
    def __str__(self):
        return 'str:{},{}'.format(self.a,self.b)

print(A())  # 优先使用__str__函数
print([A()]) # []使用__str__,但其内部使用__repr__
print(([str(A())])) #[]使用__str__,str()函数也是用__str__
print('str:a,b')
s = 'b'
print(['a'],(s,))

执行输出:
str:a,b
[repr:a,b]
['str:a,b']
str:a,b
['a'] ('b',)


五、运算符重载

  •  operator模块提供以下的特殊方法,可以将类的实例使用下面的操作符类操作
  •  比较运算符:__lt__,__le__,__eq__,__gt__,__ge__,__ne__
  •  算数运算符、移位:__add__,__sub__,__mul__,
举例:
    
    class A:
        def __init__(self,x):
            self.x = x
        
        def __sub__(self,other):
            return self.x - other.x
        
        def __isub__(self,other):
            tmp = self.x - other.x
            return A(tmp)
        
        def __str__(self):
            return str(self.x)

x = A(5)
y = A(4)
print(x,y)
print(x-y,x.__sub__(y))

x -= y
print(x)


完成Point类设计,实现判断点相等的方法,并完成向量的加法

class Point:
    def __init__(self,x,y):
        self.x = x
        self.y = y
    
    def add(self,other):
        return Point(other.x + self.x, other.y + self.y)
    
    def __add__(self,other):
        return (self.x + other.x, self.y + other.y)
    
    def __eq__(self,other):
        return self.x == other.x and self.y == other.y
    
    def __str__(self):
        return "Point:{},{}".format(self.x,self.y)

p1 = Point(1,1)
p2 = Point(2,2)
points = (p1,p2)
print(points[0].add(points[1]))

print('=========运算符重载============')
print(points[0] + points[1])
print(Point(*(points[0] + points[1])))
print(p1 == p2)


运算符重载应用场景
    往往是用面向对象实现的类,需要做大量的运算符是这样运算在数学上最常见的表达方式
    提供运算符重载,比直接提供加法方法要更加合适该领域内使用者的习惯


 

原文地址:https://www.cnblogs.com/jiangzuofenghua/p/11448547.html