Explicación necesaria con respecto a la explicación de objetos hashable

Mark Ransom respondió a una pregunta SO sobre hashes aquí en SO:

[…] Un objeto es hashable si tiene un valor hash que nunca cambia durante su vida útil . Por lo tanto, según la definición oficial, cualquier cosa mutable no puede ser hashable, incluso si tiene una función __hash__() . Mi afirmación sobre la necesidad de que ambos requisitos sean falsos, porque ser hashable ya implica el requisito de ser inmutable.

Quiero asegurarme de que lo hice bien, incluso como un hablante no nativo, por lo que espero que alguien me corrija si me equivoco.

Asumiendo esta clase

 class Author(object): def __init__(self, id, name, age): self.id = id self.name = name self.age = age def __eq__(self, other): return self.id==other.id\ and self.name==other.name def __hash__(self): return hash(('id', self.id, 'name', self.name)) 

Entiendo que __eq__ me permite comparar objetos de esta clase con el operador == . De la respuesta de Marks, entiendo, que incluso si mi objeto peter = Author(1, "Peter", 33) tiene un __hash__ no es hashable porque potencialmente podría hacer algo como peter.age = 43 que significa que no es inmutable. Entonces, ¿mis objetos de la clase Author no son hashables y, por lo tanto, no se pueden usar como claves en diccionarios, por ejemplo? ¿Me entendí bien o parece que necesito más explicación? 🙂

    Las instancias de esta clase son hashables si prometes nunca restablecer la id o el name en ellas. No puede garantizar que estos atributos nunca se restablecerán, según el principio de Python de que “todos somos adultos que consienten aquí” , pero sería un estilo muy malo ofrecer métodos que restablecen los atributos en los que confía __hash__ .

    Por ejemplo, si ofrece un método set_name en instancias de Author , pero no set_id , los clientes de la clase pueden suponer razonablemente que __hash__ opera solo en el id .

    Si desea dejar claro a los clientes de Author que no deben restablecer algún atributo, puede etiquetarlo como privado anteponiendo una _ a su nombre. Si aún así desea ofrecer acceso (solo lectura) al atributo usando su nombre común, puede convertirlo en una propiedad :

     class Author(object): def __init__(self, id, name, age): self._id = id self._name = name self.age = age # ages tend to change, so mutable id = property(lambda self: self._id) name = property(lambda self: self._name) def __eq__(self, other): return self.id==other.id\ and self.name==other.name def __hash__(self): return hash(('id', self.id, 'name', self.name))