ZetCode

Python __imod__ 方法

最后修改于 2025 年 4 月 8 日

这份综合指南探讨了 Python 的 __imod__ 方法,这是用于原地取模运算的特殊方法。我们将涵盖基本用法、自定义实现、实际示例和最佳实践。

基本定义

__imod__ 方法实现了原地取模运算 (%=)。它会原地修改对象,而不是创建一个新对象。

关键特征:它应该返回修改后的对象(通常是 self),对对象本身执行运算,并在使用 %= 运算符时被调用。 如果未实现,Python 将回退到 __mod__

基本的 __imod__ 实现

这是一个简单的实现,展示了 __imod__ 如何与自定义类一起工作。该示例演示了基本的原地取模行为。

basic_imod.py
class ModuloNumber:
    def __init__(self, value):
        self.value = value
    
    def __imod__(self, other):
        self.value %= other
        return self
    
    def __repr__(self):
        return f"ModuloNumber({self.value})"

num = ModuloNumber(17)
num %= 5
print(num)  # Output: ModuloNumber(2)

此示例显示了一个数字包装类,该类实现了原地取模。 __imod__ 方法修改实例的值并返回 self 以允许链式调用。

该方法首先对实例的值执行取模运算,然后返回修改后的实例。 这是原地运算的标准模式。

自定义取模行为

__imod__ 可以实现超出简单算术的自定义取模行为。此示例显示了一个跟踪取模运算的类。

custom_modulo.py
class TrackedModulo:
    def __init__(self, value):
        self.value = value
        self.operations = []
    
    def __imod__(self, other):
        self.operations.append(f"Mod by {other}")
        self.value %= other
        return self
    
    def show_history(self):
        return self.operations

tracked = TrackedModulo(23)
tracked %= 5
tracked %= 3
print(tracked.value)  # 1
print(tracked.show_history())  # ['Mod by 5', 'Mod by 3']

这个增强版本保留了所有执行的取模运算的历史记录。 每次使用 %= 时,它都会在执行计算之前记录该运算。

该方法在保持对象状态的同时添加了跟踪功能。 此模式对于调试或审计数学运算很有用。

矩阵取模运算

对于更复杂的对象(例如矩阵),__imod__ 可以执行逐元素运算。 此示例显示了一个简单的矩阵实现。

matrix_modulo.py
class Matrix:
    def __init__(self, rows):
        self.rows = rows
    
    def __imod__(self, scalar):
        self.rows = [[x % scalar for x in row] 
                    for row in self.rows]
        return self
    
    def __repr__(self):
        return '\n'.join(str(row) for row in self.rows)

matrix = Matrix([[10, 20], [30, 40]])
matrix %= 7
print(matrix)
# Output:
# [3, 6]
# [2, 5]

当使用 %= 运算符时,此矩阵类将取模应用于每个元素。 __imod__ 方法会原地修改矩阵。

该实现使用列表推导式将运算应用于每个元素。 这很有效率,并保持了矩阵结构。

带有验证的取模

__imod__ 可以包含验证逻辑,以确保安全地执行运算。 此示例验证取模操作数。

validated_modulo.py
class SafeModulo:
    def __init__(self, value):
        self.value = value
    
    def __imod__(self, other):
        if other == 0:
            raise ValueError("Cannot modulo by zero")
        if not isinstance(other, (int, float)):
            raise TypeError("Modulo operand must be numeric")
        self.value %= other
        return self
    
    def __repr__(self):
        return f"SafeModulo({self.value})"

num = SafeModulo(25)
try:
    num %= 4
    print(num)  # SafeModulo(1)
    num %= 0    # Raises ValueError
except ValueError as e:
    print(e)

这种安全的取模实现会检查除以零的情况,并确保操作数是数字。 它会为无效情况引发适当的异常。

验证发生在运算之前,从而防止非法状态。 这种防御性编程方法使该类更加健壮。

具有不同类型的取模

__imod__ 可以处理不同类型之间的运算。 此示例显示了一个可以处理数字和字符串的类。

multi_type_modulo.py
class FlexibleModulo:
    def __init__(self, value):
        self.value = value
    
    def __imod__(self, other):
        if isinstance(other, str):
            self.value = self.value % (other,)
        else:
            self.value %= other
        return self
    
    def __str__(self):
        return str(self.value)

flex = FlexibleModulo(10)
flex %= 3
print(flex)  # 1

flex = FlexibleModulo("Result: %d")
flex %= 42
print(flex)  # Result: 42

这个灵活的类可以处理数字取模和字符串格式化运算。 行为会根据操作数类型而变化。

当操作数是字符串时,它会执行字符串格式化。 对于数字,它会执行算术取模。 这展示了 __imod__ 的多功能性。

最佳实践

资料来源

作者

我的名字是 Jan Bodnar,我是一位充满热情的程序员,拥有丰富的编程经验。 自 2007 年以来,我一直撰写编程文章。 至今,我已经撰写了超过 1,400 篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出所有 Python 教程