python集中的哈希表冲突?

2024-09-30 02:28:01 发布

您现在位置:Python中文网/ 问答频道 /正文

在python set 2中如何可能有相同的元素?是python的错误吗?你知道吗

type(data_chunks)
<class 'set'>

len(data_chunks)
43130

same = [x for x in data_chunks if x.md5==chunk.md5]
[<Model.Chunk.Chunk o...x0DB40870>, <Model.Chunk.Chunk o...x0DB40870>]

len(same)
2

same[0] is same[1]
True

same[0] == same[1]
True

len(set(same))
1

但当我用它建立字典时,重复的部分就被删除了!你知道吗

len({k:k.product_id for k in data_chunks})
43129

为什么它适用于dictionary而不适用于set?我以为这是哈希表中的冲突,但事实上重复的对象是同一个对象,所以在添加下一个元素时,在集合查找中找不到它(?)你知道吗

其他信息:

  • Chunk定义了__hash____eq__方法
  • python 3.7.2版
  • 我已经意识到Chunk有一些属性会抛出一个错误-这不重要,因为它们没有被调用
  • 处理代码行是: data_chunks = data_chunks | another_set
  • vscode中去bugging会话期间的交互式提示
  • 运行代码时,有时会发生
  • 但是在这个调试会话中,从数据块创建新的集合总是相同的长度

编辑

区块实现

class Chunk(object):
    def __init__(self,
                 md5,
                 size=None,
                 compressedMd5=None,
                 # ... (more elements)
                 product_id=None):
       self.md5 = md5
       self.product_id = product_id
       # (etc.)

    def __eq__(self, other):
        if self.compressedMd5:
            return self.compressedMd5 == other.compressedMd5 and self.product_id == other.product_id
        return self.md5 == other.md5 and self.product_id == other.product_id

    def __hash__(self):
        return self.name.__hash__()

    @property
    def name(self):
        return self.compressedMd5 if self.compressedMd5 is not None else self.md5

=====================

编辑 好的,代码中的内容如下:

repository-json描述符

chunking_strategy = ...-主要是存储设置的类,例如块将被压缩。你知道吗

result_handler = Strategy.DefaultResultHandler(repository) 生成存储库中chunks对象的唯一哈希:chunks和相应的文件映射。稍后它将调用压缩作业,然后设置compressedMd5和现有块的其他属性。

generation_strategy = Strategy.CachingGenerationStrategy(
            result_handler,
            Settings().extra_io_threads,
        )

data_chunks = Strategy.DepotChunker(repository, chunking_strategy, generation_strategy)()

在DeputChunker init上:todo分块作业是基于分块策略设置准备的。然后generation_strategy.__call__方法处理所有作业:根据先前定义的块对象将文件分割成小块。这是在multiprocessing.Pool中完成的。创建物理块之后,检查md5,并用compressedMd5compressedSizeproduct_id更新块对象。 然后(仅在更改Chunk object后)将Chunk对象添加到set。 这个集合是从DepotChunker返回的

然后压缩的块被保存在缓存中。你知道吗


然后,所有的数据块都搜索小尺寸的小对象,从中创建由合并的小文件组成的物理块(内存缓冲区中)。我们把它们叫做小块。它们被添加到data_chunks

     sfChunk = Chunk(
                sfCompressedContentMD5,  # yes I see that this is compressed md5 - it was intended for some reason I don't know
                size=sfSize,
                compressedMd5=sfCompressedContentMD5,
                compressedSize=sfCompressedSize,
                product_id=productId
            )
        if not sfChunk in data_chunks:  # purly sanity check
            data_chunks.add(sfcChunk)

最后创建元文件,并将它们分块并添加到data_chunks

然后元文件是转储,它们也被分块。你知道吗

for depot in manifest_depots:
        data_chunks = data_chunks | simpleChunker(depot)

此时,从一开始就记录了调试器会话


Tags: 文件对象selfiddatalenproductmd5
2条回答

一个问题是__eq__对于一个有compressedMd5而另一个没有compressedMd5的对象对是不可交换的(即其compressedMd5被设置为None)。这意味着可以构造两个对象ab,使得a == b同时b != a。你知道吗

一个相关的问题是__eq____hash__在相似的情况下不一致(__eq__会拒绝看other.compressedMd5如果self.compressedMd5None

易变性也可能是一个问题,如下例所示:

class Chunk(object):
  def __init__(self, md5):
    self.md5 = md5

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

s = set()
chunk = Chunk('42')
s.add(chunk)
chunk.md5 = '123'
s.add(chunk)
print(s)

在我的电脑上,这会产生set([<__main__.Chunk object at 0x106d03390>, <__main__.Chunk object at 0x106d03390>]),即同一对象在集合中出现两次。你知道吗

如果更改md5或设置/取消设置/更改compressedMd5,代码中可能会发生类似的情况。你知道吗

好吧,我知道这是一种很难可靠重现的行为,所以我们所能提供的只是关于可能导致此类问题的建议。。。你知道吗

除了NPE已经提到的,你确实有一个潜在的问题Chunk是可变的:md5compressedMd5属性可以随时更改,因此hash(chunk)的结果不能保证是稳定的。您可能需要在这里检查您的代码库,以查找最终的小精灵。如果在achunk被添加到集合之后发现任何更新这些属性之一的代码,那么可能就是罪魁祸首。FWIW请记住,Python从不隐式地复制这样的内容:

chunks = set()

def make_chunk(md5, ...)
   c = Chunk(md5, ...)
   chunks.add(c)
   return c

def do_something_bad(chunk):
    chunk.md5 = something_else

def main():
   c = make_chunk()
   # ... lots of code here
   do_something_bad(c)

会反映出chunks的变化,把一切都搞砸(注:是的,你很可能已经知道了,但对于来自更主流语言的人来说,这是一个非常常见的陷阱)

注意:这只是一个问题,如果任何东西改变了其中一个属性,当然,但使它们成为只读的仍然会更安全(好吧,至少根据Python对“只读”和“安全”即xD的定义)。你知道吗

相关问题 更多 >

    热门问题