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

如何强制Pandas不对用作索引的对象进行缓存?

问题:Pandas MultiIndex 缓存导致自定义对象实例被复用

自定义实现了__hash__和__eq__方法的DemoObj类后,通过pd.MultiIndex.from_tuples创建多层索引并设置为DataFrame索引时,索引中对象的唯一id数量为4,但预期应为8。经测试确认这是Pandas MultiIndex的缓存逻辑导致,现需解决如何禁用该缓存的问题。

原始测试代码

import pandas as pd

class DemoObj:
    def __init__(self, x):
        self.x = x

    def __hash__(self):
        return hash(self.x)

    def __eq__(self, other):
        return self.x == other.x


df = pd.DataFrame({'a': [1, 2, 3, 4]})

df.index = pd.MultiIndex.from_tuples(((DemoObj('a0'), DemoObj('b0')),
                                      (DemoObj('a1'), DemoObj('b1')),
                                      (DemoObj('a0'), DemoObj('b0')),
                                      (DemoObj('a1'), DemoObj('b1'))))

print(len({id(e) for i in df.index for e in i}))  # 输出4,预期8

补充验证代码及输出

indexes = ((DemoObj('a0'), DemoObj('b0')),
           (DemoObj('a1'), DemoObj('b1')),
           (DemoObj('a0'), DemoObj('b0')),
           (DemoObj('a1'), DemoObj('b1')))

df.index = pd.MultiIndex.from_tuples(indexes)

print(len({id(e) for i in indexes for e in i}))  # 输出8
print(len({id(e) for i in df.index for e in i})) # 输出4

原因分析

Pandas的MultiIndex在创建过程中,会对通过__eq__判断为相等的对象进行缓存复用。由于DemoObj根据x的值判断相等且哈希值相同,相同x的不同实例会被替换成同一个,最终导致唯一id数量减少。

解决方案

目前Pandas没有直接暴露禁用该缓存的参数,可通过以下两种方式绕过:

1. 修改自定义对象的哈希逻辑,避免实例被视为相等

修改__hash__方法,将实例自身的id()加入哈希计算,让相同x的不同实例拥有不同哈希值,从而阻止Pandas复用:

class DemoObj:
    def __init__(self, x):
        self.x = x

    def __hash__(self):
        # 加入实例id,确保每个实例哈希唯一
        return hash((self.x, id(self)))

    def __eq__(self, other):
        # 可保留原有的x相等逻辑,也可改为严格实例相等(加上id判断)
        return self.x == other.x

注意:此方法会让x相同的实例被视为不同的索引项,若需保留"x相同即索引项相等"的逻辑,不建议使用。

2. 手动构建MultiIndex的levels和codes,跳过缓存逻辑

直接通过pd.MultiIndex(levels=[...], codes=[...])的方式构建索引,手动指定每个层级的所有实例和对应位置代码,避免Pandas自动去重缓存:

import pandas as pd

class DemoObj:
    def __init__(self, x):
        self.x = x

    def __hash__(self):
        return hash(self.x)

    def __eq__(self, other):
        return self.x == other.x

indexes = ((DemoObj('a0'), DemoObj('b0')),
           (DemoObj('a1'), DemoObj('b1')),
           (DemoObj('a0'), DemoObj('b0')),
           (DemoObj('a1'), DemoObj('b1')))

# 拆分每个层级的原始实例
level0 = [t[0] for t in indexes]
level1 = [t[1] for t in indexes]

# 手动构建MultiIndex,保留所有原始实例
df = pd.DataFrame(
    {'a': [1,2,3,4]}, 
    index=pd.MultiIndex(
        levels=[level0, level1], 
        codes=[[0,1,2,3], [0,1,2,3]]
    )
)

print(len({id(e) for i in df.index for e in i}))  # 输出8

此方法保留了DemoObj原有的相等和哈希逻辑,同时让所有原始实例都保留在索引中。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 22:01:16