7.2 算术运算符的特殊方法

    一共有13个二进制运算符以及相关的特殊方法。先关注一些常用的算术运算符。如下面表格所示,每个特殊方法名对应一个各自的运算符(函数)。


    方法

    运算符

    object. add (self, other)

    +

    object. sub (self, other)

    -

    object. mul (self, other)


    object. truediv (self, other)

    /

    object. floordiv (self, other)

    //

    object. mod (self, other)

    %

    object. divmod (self, other)

    divmod() 函数

    object. pow (self, other[, modulo])

    pow() 函数和 *

    以上运算符中包含了两个函数。还有很多特殊方法,也对应了一元运算符和函数,如下表所示。


    方法

    运算符

    object. neg (self)

    -

    object. pos (self)

    +

    object. abs (self)

    abs() 函数

    object. complex (self)

    complex() 函数

    object. int (self)

    int() 函数

    object. float (self)

    float() 函数

    object. round (self[, n])

    round() 函数

    object. trunc (self[, n])

    math.trunc() 函数

    object. ceil (self[, n])

    math.ceil() 函数

    object. floor (self[, n])

    math.floor() 函数

    以上列表包含了很多函数。可以使用Python的内部追踪,看看内部的具体细节。以下定义了一个简单的追踪函数,来看一下其中的部分细节。

    def trace( frame, event, arg ):
      if frame.fcode.coname.startswith(""):
        print( frame.f_code.co_name, frame.f_code.co_filename, event )

    这个函数会打印出名称以"__"为起始的特殊方法名称,可以使用如下代码把这个追踪函数安装到Python中。

    import sys
    sys.settrace(trace)

    一旦完成安装,系统中任何执行代码都会经过trace()函数。我们会过滤出所有特殊方法名的事件。接下来会定义一个内部类的子类,以探究方法的解析规则。

    class noisyfloat( float ):
      def add( self, other ):
      print( self, "+", other )
      return super().add( other )
    def radd( self, other ):
      print( self, "r+", other )
      return super().radd( other )

    这个类只重载了运算符中的两个特殊方法。当执行noisyfloat值的加法时,会看到打印出的运算符相关的统计信息。而且,追踪信息会告诉我们发生了什么。如下代码演示了Python为一个给定运算符选择类的过程。

    >>> x = noisyfloat(2)
    >>> x+3
    add <stdin> call
    2.0 + 3
    5.0
    >>> 2+x
    radd <stdin> call
    2.0 r+ 2
    4.0
    >>> x+2.3
    add <stdin> call
    2.0 + 2.3
    4.3
    >>> 2.3+x
    radd <stdin> call
    2.0 r+ 2.3
    4.3

    x+3开始,可以看到noisyfloat+int是如何将int对象值3提供给add()方法的。这个值传入了基类float中,将3转换为float类型并做加法。而2+x则演示了noisyfloat类的运算符右边的加法函数是如何被调用的。int再次被传入基类中进而被转换为float。对于表达式x+2.3,我们得知noisyfloat+float使用了运算符左边的子类中的加法函数。相应地,对于表达式2.3+x而言,float+noisyfloat则使用了运算符右边的子类中的反向加法函数radd()