举例说明Python的 __floordiv__() 方法

511 阅读3分钟

语法

object.__floordiv__(self, other)

Python__floordiv__() 方法实现了整数除法运算// ,称为*地板除法--*与真正的除法运算/ 相对。例如,为了评估表达式x // y ,Python 试图调用x.__floordiv__(y) 。如果这个方法没有实现,Python首先尝试在右边的操作数上调用__rfloordiv__ ,如果这个方法也没有实现,它就会引发一个TypeError

我们把这称为 "Dunder Method",即*"Double UnderscoreMethod"(也称为"Magic Method")*。

例子

在下面的例子中,你创建了一个自定义类Data ,并覆盖了__floordiv__() 方法,这样当你试图用真正的除法操作a / b分割 两个Data 对象时,它会返回一个假字符串。

class Data:
        
    def __floordiv__(self, other):
        return '... my result of floordiv...'


a = Data()
b = Data()
c = a // b

print(c)
# ... my result of floordiv...

如果你没有定义__truediv__() 方法,Python 会引发一个TypeError

如何解决TypeError:不支持//的操作数类型

考虑下面的代码片段,你试图在没有定义dunder方法的情况下分割两个自定义对象__truediv__()

class Data:
    pass


a = Data()
b = Data()
c = a // b

print(c)

在我的电脑上运行这个导致了以下错误信息。

Traceback (most recent call last):
  File "C:\Users\xcent\Desktop\code.py", line 7, in <module>
    c = a // b
TypeError: unsupported operand type(s) for //: 'Data' and 'Data'

这个错误的原因是,__floordiv__() dunder方法从未被定义过--而且默认情况下没有为自定义对象定义该方法。所以,为了解决TypeError: unsupported operand type(s) for // ,你需要在你的类定义中提供__floordiv__(self, other) 方法,如前所示。

class Data:
        
    def __floordiv__(self, other):
        return '... my result of floordiv...'

Python __floordiv__ vs __div__ vs __truediv__

  • 在Python 3中调用Python__floordiv__() dunder方法来实现整数除法操作。
  • Python__div__() dunder方法被调用来实现Python 2中正常的 "真除法 "操作。它在Python 3中不再起作用了。
  • Python__truediv__() dunder方法被调用来实现Python 3中正常的 "真除法 "操作。

Python的__floordiv__与__rfloordiv__对比

假设,你想用地板除法来分割两个对象xy

print(x // y)

Python 首先尝试调用左边对象的__floordiv__() 方法x.__floordiv__(y) 。但这可能因为两个原因而失败。

  1. 方法x.__floordiv__() 首先没有实现,或者
  2. 方法x.__floordiv__() 已经实现,但返回一个NotImplemented 值,表明数据类型不兼容。

如果失败了,Python 试图通过调用y.__rfloordiv__() 来解决这个问题,用于在右边的运算符y 上进行反向地板除法。如果这个方法被实现了,Python知道它没有遇到非交换性操作的潜在问题。如果它只是执行y.__floordiv__(x) 而不是x.__floordiv__(y) ,那么如果除法是非交换性的,就会引起一个错误。这就是为什么需要y.__rfloordiv__(x) ,它表明楼层除法毕竟是可能的。

因此,x.__floordiv__(y)x.__rfloordiv__(y) 之间的区别是,前者计算x // y 而后者计算y // x - 两者都调用定义在对象x 上的各自的楼层划分方法。

你可以在这里看到这个效果,我们试图在左边的操作数x 上调用地板除法,但是由于它没有实现,Python 只是在右边的操作数y 上调用反向的地板除法操作。

class Data_1:
    pass

class Data_2:
    def __rfloordiv__(self, other):
        return 'called rfloordiv'


x = Data_1()
y = Data_2()

print(x//y)
# called rfloordiv