如果类型(其他)== str,则覆盖 MyClass 中的“__rmod__”不起作用

Overriding the '__rmod__' in MyClass does not work if type(other) == str

我试图在我的 class 中覆盖 __rmod__ 的行为;但是,除非 MyClass 继承自 'str',否则它不起作用。这与 Python Issue 28598 类似,我认为解决该问题的原因是如果我将 subclass 'str' 与 MyClass 一起使用,它将起作用。不过我不想subclass 'str'!

显示问题的示例代码(第 4 个 assertEqual 将失败):

类型错误:在字符串格式化期间并非所有参数都已转换

import unittest


class MyClass:
    def __init__(self, value):
        self.value = value

    def __mod__(self, other):
        return self.value % int(other)

    def __rmod__(self, other):
        return int(other) % self.value

    def __add__(self, other):
        return self.value + int(other)

    def __radd__(self, other):
        return self.__add__(other)


class UnitTests(unittest.TestCase):
    def test_rmod(self):
        self.assertEqual(100, MyClass(50) + "50")
        self.assertEqual(100, "50" + MyClass(50))
        self.assertEqual(1, MyClass(101) % "10")
        self.assertEqual(1, "101" % MyClass(10))


if __name__ == '__main__':
    unittest.main()

如果我将 MyClass 更新为 subclass 'str'

class MyClass(str)

测试都会通过。

Python 仅在两种特定情况下调用 MyClass.__rmod__()

  • 如果左侧操作数拒绝通过 returning NotImplememted 处理 % 操作,或者没有实现 __mod__ 挂钩。
  • 如果右侧操作数的类型是左侧操作数类型的子class。

Python 字符串可以在 % 运算符的右侧处理 any 类型的对象,因此第一种情况不适用。 str.__mod__() 如果使用右手操作数由于某种原因不起作用并且将 never return NotImplemented.

因为你的 class 没有继承自 str 第二种情况也不适用。

其他操作,如 + 确实有效,因为第一种情况适用;字符串只接受其他字符串作为右侧值,因此 return NotImplemented.

如果你必须拦截 string_value % MyClass(),恐怕你 唯一的选择 是潜入 class str

另见 documentation on __rmod__:

These functions are only called if the left operand does not support the corresponding operation.

链接到 footnote:

“Does not support” here means that the class has no such method, or the method returns NotImplemented.

主要文档后面有注释:

If the right operand’s type is a subclass of the left operand’s type and that subclass provides a different implementation of the reflected method for the operation, this method will be called before the left operand’s non-reflected method. This behavior allows subclasses to override their ancestors’ operations.