首页 > 解决方案 > 如果 type(other) == str 则覆盖 MyClass 中的 '__rmod__' 不起作用

问题描述

我试图覆盖__rmod__我班级中的行为;但是,除非MyClass从 'str' 继承,否则它不起作用。这类似于Python 问题 28598,我认为解决该问题的方法是为什么如果我使用 MyClass 子类化 'str' 它将起作用。我不想继承'str'!

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

TypeError:字符串格式化期间并非所有参数都转换了

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 更新为子类 'str'

class MyClass(str)

测试将全部通过。

标签: pythonoperator-overloading

解决方案


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

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

Python 字符串可以处理运算符右侧的任何%类型的对象,因此第一种情况永远不会适用。str.__mod__()如果使用右手操作数由于某种原因不起作用并且永远不会返回,则实现直接引发异常NotImplemented

由于您的类没有从str第二种情况继承,因此也不适用。

其他操作,例如+do 工作,因为适用第一种情况;strings 只接受其他字符串作为右手值,因此 return NotImplemented

如果你必须拦截string_value % MyClass(),你唯一的选择就是子类str,恐怕。

另请参阅以下文档__rmod__

仅当左操作数不支持相应操作时才调用这些函数。

链接到脚注

这里的“不支持”是指该类没有该方法,或者该方法返回NotImplemented

主要文档如下:

如果右操作数的类型是左操作数类型的子类,并且该子类为操作提供了反射方法的不同实现,则此方法将在左操作数的非反射方法之前调用。此行为允许子类覆盖其祖先的操作。


推荐阅读