自定义__add__方法的DailyAmounts类触发mypy运算符与索引错误
DailyAmounts类的Mypy错误分析与解决
问题背景
定义了如下DailyAmounts类:
from datetime import date from typing import Dict, Callable, Iterator class DailyAmounts: def __init__(self) -> None: self.daily_map: Dict[date, int] = dict() self.total: int = 0 def __daily_math(self: 'DailyAmounts', other: 'DailyAmounts', function: Callable[[int, int], int]) -> 'DailyAmounts': if not isinstance(other, DailyAmounts): raise ValueError(f"Only {DailyAmounts.__name__} can be operated with") res = DailyAmounts() days = list(set(self.daily_map.keys()) | set(other.daily_map.keys())) for day in days: amount = function(self.daily_map.get(day, 0), other.daily_map.get(day, 0)) res[day] = amount return res def __add__(self: 'DailyAmounts', other: 'DailyAmounts') -> 'DailyAmounts': def add(a: int, b: int) -> int: return a + b return self.__daily_math(other, add) def __sub__(self: 'DailyAmounts', other: 'DailyAmounts') -> 'DailyAmounts': def sub(a: int, b: int) -> int: return a - b return self.__daily_math(other, sub) def __iter__(self: 'DailyAmounts') -> Iterator[date]: return iter(self.daily_map)
以及包含DailyAmounts属性的Item类:
class Item: def __init__(self) -> None: self.daily_amounts: DailyAmounts = DailyAmounts() # 值后续在其他地方计算
使用时出现两个Mypy错误:
- 运算符错误:
def some_function(old_item: Item): new_item = Item() # 错误提示:Unsupported operand types for + ("DailyAmounts" and "Callable[..., Any]") [operator] new_item.daily_amounts = old_item.daily_amounts + DailyAmounts() # 复制实例
- 索引赋值错误:
def another_function(my_item: Item, my_other_item: Item): # 错误提示:Unsupported target for indexed assignment ("Callable[..., Any]") [index] for entry in my_item.daily_amounts.daily_map.items(): my_other_item.daily_amounts[entry[0]] = entry[1]
错误原因
1. 运算符错误原因
- 类型注解解析问题:类内部使用字符串形式的
'DailyAmounts'作为类型注解,但未启用延迟注解求值,导致Mypy无法正确识别__add__方法的参数类型,误将DailyAmounts()实例推断为可调用对象。 - 缺失类型导入:如果未导入
date、Dict等核心类型,Mypy会将这些类型视为Any,干扰类型推断逻辑。
2. 索引赋值错误原因
DailyAmounts类未实现映射协议的核心方法__setitem__,Mypy判定该类实例不支持[]赋值操作。虽然可以通过daily_map直接访问内部字典,但直接对DailyAmounts实例使用索引赋值时,Mypy无法识别操作的合法性。
解决方法
1. 修复运算符错误
- 启用延迟注解求值:在文件顶部添加
from __future__ import annotations(Python 3.7+支持),让Mypy正确解析类内部的字符串类型注解。 - 补全类型导入:确保已导入
from datetime import date和from typing import Dict, Callable, Iterator。
2. 修复索引赋值错误
给DailyAmounts类添加__setitem__方法,同时建议补充__getitem__以完善映射协议支持:
class DailyAmounts: # 其他方法保持不变 def __setitem__(self, day: date, amount: int) -> None: self.daily_map[day] = amount # 可选:同步更新total值,保证数据一致性 old_amount = self.daily_map.get(day, 0) self.total += amount - old_amount def __getitem__(self, day: date) -> int: return self.daily_map[day]
额外优化
如果需要直接在DailyAmounts实例上调用items()(无需通过daily_map),可以添加如下方法:
def items(self) -> Iterator[tuple[date, int]]: return self.daily_map.items()
修改后,another_function可简化为:
def another_function(my_item: Item, my_other_item: Item): for day, amount in my_item.daily_amounts.items(): my_other_item.daily_amounts[day] = amount
内容的提问来源于stack exchange,提问作者mochatiger
相关产品推荐
相关产品推荐

