美文网首页Python编程python
python 魔术方法1 运算符重载

python 魔术方法1 运算符重载

作者: Vector_Wan | 来源:发表于2019-06-21 21:14 被阅读22次

    python中存在一些特殊的方法,这些方法通常采用格式:__method__()。这些方法会在特定的情况下自动调用。例如:__new__()__init__()__del__() 等生命周期方法。正是这些特殊方法,构建了python的语言风格。特殊方法有很多,比如下面列出来的这些,我们按照类别研究其中的一部分。其他的等到真的用到的再往上加吧。

    更多魔术方法

    python中的魔术方法

    我们先来看看这些特殊方法有什么用,它作了什么简化,一般在实际情况下我们什么时候才会使用到这些方法。
    假设有一个表示在线订单的类,具有购物车 (列表) 和顾客 (代表顾客的str或其他类的实例)两种数据。
    在这种情况下,要获得购物车列表的长度是很自然的。新接触 Python 的人可能会选择在他们的类中实现一个叫get_cart_len()的方法来执行此项。但是,你也可以重载内置函数len(),以便在给定对象时返回购物车列表的长度。

    在另一种情况下, 我们可能需要添加一些东西到购物车。再次,新接触 Python 的人会想到实现一个append_to_cart()方法,以添加东西到购物车列表。但是你也可以配置运算符+,用它来将新内容添加到购物车中。
    Python 使用特殊的方法来做这些。这些特殊方法具有命名约定,其中名称以两个下划线开头, 后跟一个标识符, 并以另一对下划线结尾。(就是我们说的魔术方法啦)

    本质上, 每个内置函数或运算符都有一个与之对应的特殊方法。例如,对应于 len()__len__(),对应于运算符 +__add__()

    默认情况下, 大多数内置函数和运算符都不能与自定义类的对象一起使用。必须在类定义中添加相应的特殊方法,才能使对象与内置和运算符兼容。这就是我们接下来要讨论的 python 运算符重载。

    执行此操作时,与其关联的函数或运算符的行为将根据方法中定义的方式进行更改。

    在说运算符重载之前,我们来看一下魔术方法的特点:(敲黑板儿)

    • 特殊方法定义在class中
    • 不需要直接调用
    • python的某些函数或操作符会调用相应的特殊方法

    运算符重载

    目的:让自定义的类生成的对象(实例)能够使用运算符进行操作。依据运算数据的不同,为运算符定义不同的行为。

    作用(好处)

    • 让自定义的实例像内建对象一样进行运算符操作,令用户定义的对象能够使用中缀运算符(如 + 和 | )或一元运算符(如 - 和 ~ )等运算符。
    • 让程序简洁易读;
    • 对自定义对象将运算符赋予新的规则。

    我们知道,数据类型 = 数据结构 + 运算 ,有了运算符重载意味着我们可以定义自己的数据类型了。

    为了做好灵活性、可用性和安全性方面的平衡,Python对运算符重载施加了一些限制:

    • 不能重载内置类型的运算符;
    • 不能新建运算符,只能重载现有运算符;
    • 某些运算符不能重载,如is、and、or和not(不过位运算符&、| 和 ~可以)。

    下面我们来看一个例子:二维向量类的加法。(这个例子太经典啦哈哈哈)

    假设有Vector2D类代表一个二维向量。我们知道Vector2D(3,4) + Vector2D(1,1) = Vector2D(4,5),我们通过重载魔术方法__add__来实现这一功能。

    class Vector2D:
    
        def __init__(self, x, y):
            self.x = x
            self.y = y
    
        def __add__(self, other):
            x = self.x + other.x
            y = self.y +other.y
            return Vector2D(x, y)
    
        def __str__(self):
            return "Vector2D(x={}, y={})".format(self.x, self.y)
    
    
    v1 = Vector2D(1, 2)
    v2 = Vector2D(3, 4)
    
    v3 = v1 + v2
    print(v3)
    
    Vector2D(x=4, y=6)
    

    结果是正确的,我们并没有调用__add__而是直接使用 + 就可以啦,还记得之前我们说过的魔术方法的特点吗?

    当我们在重载双目运算符的时候,会多传入一个参数other

    在上面的例子中我们还重载了一个特殊方法__str__, 我们下面会介绍这个方法, 这个方法通过 print() 函数调用。

    接下来我们在重载一些其他的运算:

    from math import hypot,sqrt
    
    class Vector:
    
        def __init__(self, x, y):
            self.x = x
            self.y = y
        
        #__str__方法,会在打印变量时,自动调用
        def __str__(self):
            return 'Vector(%r,%r)' %(self.x, self.y)
        
        #__abs__函数会在调用abs()函数时,自动调用
        def __abs__(self):
            #hypot(x,y) 返回欧几里得范数 sqrt(x*x + y*y)
            return hypot(self.x, self.y)
            
        #__bool__函数会在调用bool()函数时,自动调用
        def __bool__(self): 
            return bool(abs(self))
            
        # 执行a + b时,自动调用
        def __add__(self, other):
            x = self.x + other.x
            y = self.y + other.y
            return Vector(x,y)
        
        # 执行a+=b时,自动调用
        def __iadd__(self, other):
            return self + other
        
        # 执a * b的时候,会自动调用
        def __mul__(self, scalar):
            return Vector(self.x * scalar,self.y * scalar)
        
        # 求-a时,自动调用    
        def __neg__(self):
            return Vector(-self.x,-self.y)
            
        def __matmul__():
            pass
            
    v1 = Vector(2,4)
    v2 = Vector(2,1)
    print(v1 + v2)
    v = Vector(3,4)
    print(abs(v))
    print(v * 3)
    print(abs(v * 3))
    print(-v)
    v1 += v2
    print(v1)
    
    Vector(4,5)
    5.0
    Vector(9,12)
    15.0
    Vector(-3,-4)
    Vector(4,5)
    

    在上面我们实现了自加操作,(+=)实际上因为我们实现了 + 操作,解释器会自动实现这个方法。

    值得注意的是反向操作,如果你了解 Matlab 一定知道Matlab有左除与右除。python也有类似的用法。我们以加法为例:辨析 __add__()__radd__()的不同.

    先看一个例子:

    class A:
    
        def __add__(self, other):
            print('A add')
    
        def __radd__(self, other):
            print('B add')
    
    
    class B:
    
        pass
    
    
    if __name__ == "__main__":
        a = A()
        b = B()
    
        a + b
        b + a
    
    A add
    B add
    

    在这个例子中,在b + ab没有实现加法操作,那么解释器就调用了,a 的反向方法。

    执行a + b 的流程如下:

    • 如果a__add__方法,而且返回值不是NotImplemented,调用a.__add__(b),然后返回结果。
    • 如果a没有__add__方法,或者调用__add__方法返回NotImplemented,检查b有没有__radd__方法,如果有,而且没有返回NotImplemented,调用b.__radd__(a),然后返回结果。
    • 如果b没有__radd__方法,或者调用__radd__方法返回NotImplemented,抛出TypeError,并在错误消息中指明操作数类型不支持。
    常见的运算符重载方法 中缀运算符

    相关文章

      网友评论

        本文标题:python 魔术方法1 运算符重载

        本文链接:https://www.haomeiwen.com/subject/wzqfqctx.html