You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python Counter统计自定义类实例库存打印异常问题

问题原因

collections.Counter 统计重复元素的判断规则是:两个元素哈希值一致、且等值判定为True时,才会被归为同一项累计数量。

  • 库存存字符串时,值相同的字符串天然哈希一致、等值判定成立,因此Counter可以正常合并统计。
  • 换成自定义类实例后,每次调用Log()、Flint()这类构造方法生成的都是独立新实例。Python自定义类默认的等值判定规则是「只有实例自身和自身相等」,不同实例哪怕由同一个类创建、属性完全相同,也会被判定为不同对象,哈希值也互不相同,因此Counter无法自动合并同类型物品。
修复方案

可根据代码结构选择以下任意一种方案:

方案1:补全物品基类的等值和哈希方法(推荐)

从根源上让同类型物品实例满足Counter的统计要求,后续其他逻辑判断两个物品是否为同一种时也能复用规则。
仅需修改Item基类,补充__eq__和__hash__两个魔法方法,所有子类无需改动:

class Item:
    def __init__(self, name, description):
        self.name = name
        self.description = description

    def __str__(self):
        return self.name.title()

    def __eq__(self, other):
        if not isinstance(other, Item):
            return False
        # 同类型且名称一致,判定为同一种物品
        return type(self) is type(other) and self.name == other.name

    def __hash__(self):
        # 基于物品类型和名称生成哈希,保证同一种物品哈希一致
        return hash((type(self), self.name))

# 以下Log、Flint、SteelScrap子类代码保持原有逻辑不变即可
class Log(Item):
    def __init__(self):
        super().__init__(name="Log",
                         description="A Large wooden log.")

class Flint(Item):
    def __init__(self):
        super().__init__(name="Flint",
                         description="A fragment of flint.")

class SteelScrap(Item):
    def __init__(self):
        super().__init__(name="Steel Scrap",
                         description="A piece of steel scrap.")

修改完成后原有Player类的代码不需要任何调整,Counter即可正常统计同类型物品数量。

如果后续给物品增加耐久、附魔等需要区分堆叠的属性,只要把对应属性加入__eq__的判断条件、以及__hash__的生成元组即可。

方案2:调整计数逻辑,按物品标识手动统计

如果不想修改原有物品类的定义,可以直接调整库存打印的计数逻辑,不直接将实例列表传入Counter,而是手动以物品唯一标识(名称/类型)为key统计:

from collections import Counter
from items import *

class Player:
    def __init__(self):
        self.inventory = [Log(),Log(),Flint(),SteelScrap()]

    def print_inv(self):
        print(" -- Inventory -- ")
        inv_count = Counter()
        display_map = {}
        for item in self.inventory:
            inv_count[item.name] += 1
            display_map[item.name] = item
        for item_name, quantity in inv_count.items():
            print(f" > {display_map[item_name]}({quantity})")

Player().print_inv()

内容的提问来源于stack exchange,提问作者bigboibob

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 03:06:12