Pergunta

Eu tinha um bug estranho ao portar um recurso para o Python 3.1 fork do meu programa. Eu reduzi-lo para a seguinte hipótese:

Em contraste com Python 2.x, em Python 3.x se um objeto tem um método __eq__ é automaticamente unhashable.

Isso é verdade?

Eis o que acontece no Python 3.1:

>>> class O(object):
...     def __eq__(self, other):
...         return 'whatever'
...
>>> o = O()
>>> d = {o: 0}
Traceback (most recent call last):
  File "<pyshell#16>", line 1, in <module>
    d = {o: 0}
TypeError: unhashable type: 'O'

O follow-up questão é: como faço para resolver o meu problema pessoal? Eu tenho um ChangeTracker objeto que armazena um WeakKeyDictionary que aponta para diversos objetos, dando para cada o valor de seu despejo picles em um determinado ponto do tempo no passado. Sempre que um objeto existente for verificado, o rastreador mudança diz se seu novo pickle é idêntico ao seu antigo, portanto dizendo se o objeto mudou nesse meio tempo. O problema é que agora não pode até mesmo verificar se o objeto dado está na biblioteca, porque torna gerar uma exceção sobre o objeto sendo unhashable. (Porque ele tem um método __eq__.) Como posso resolver isso?

Foi útil?

Solução

Sim, se você definir __eq__, o __hash__ padrão (ou seja, hash o endereço do objeto na memória) vai embora. Isto é importante porque as necessidades de hash para ser consistente com a igualdade:. Objetos iguais precisa de hash o mesmo

A solução é simples:. Apenas definir __hash__ juntamente com a definição __eq__

Outras dicas

Este parágrafo de http://docs.python.org/3.1 /reference/datamodel.html#object. de hash

Se uma classe que substitui __eq__() precisa manter a implementação de __hash__() de uma classe pai, o intérprete deve ser dito isso explicitamente, definindo __hash__ = <ParentClass>.__hash__. Caso contrário, o herança de __hash__() será bloqueadas, como se tivesse sido __hash__ explicitamente definido como Nenhum.

Verifique o manual Python 3 no object.__hash__ :

Se uma classe não define um método __eq__() não deve definir uma operação __hash__() qualquer um; se define __eq__() mas não __hash__(), suas instâncias não será utilizável como itens em coleções Hashable.

A ênfase é minha.

Se você quer ser preguiçoso, parece que você pode apenas definir __hash__(self) para id(self) retorno:

classes definidas pelo usuário têm __eq__() e __hash__() métodos por padrão; com eles, todos os objetos comparar desigual (exceto com eles mesmos) e x.__hash__() retornos id(x).

Não sou especialista python, mas não faria sentido que, quando você definir um método-eq, você também tem que definir um método de hash-bem (que calcula o valor de hash para um objeto) Caso contrário, o mecanismo de hashing não saberia se ele atingiu o mesmo objeto, ou um objeto diferente com apenas o mesmo hash de valor. Na verdade, é o contrário, ele provavelmente iria acabar computação diferentes valores de hash para objetos considerados iguais por seu método __eq__.

Eu não tenho idéia o que isso função hash é chamado, porém, __hash__ talvez? :)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top