superclasses method herency example python inheritance tuples

python - method - ¿Cómo proporcionar una inicialización adicional para una subclase de namedtuple?



python superclasses (2)

El código en la pregunta podría beneficiarse de una súper llamada en el __init__ en caso de que alguna vez se subclasifique en una situación de herencia múltiple, pero por lo demás es correcta.

class Edge(EdgeBase): def __init__(self, left, right): super(Edge, self).__init__(a, b) self._hash = hash(self.left) * hash(self.right) def __hash__(self): return self._hash

Mientras que las tuplas son de solo lectura, solo las partes de la tupla de sus subclases son de solo lectura, otras propiedades pueden escribirse como de costumbre, lo que permite la asignación a _hash independientemente de si se hace en __init__ o __new__ . Puede hacer que la subclase sea completamente de solo lectura estableciendo su __slots__ a (), que tiene el beneficio adicional de guardar memoria, pero luego no podrá asignar a _hash.

Supongamos que tengo una namedtuple así:

EdgeBase = namedtuple("EdgeBase", "left, right")

Quiero implementar una función hash personalizada para esto, así que creo la siguiente subclase:

class Edge(EdgeBase): def __hash__(self): return hash(self.left) * hash(self.right)

Como el objeto es inmutable, quiero que el valor de hash se calcule solo una vez, así que hago esto:

class Edge(EdgeBase): def __init__(self, left, right): self._hash = hash(self.left) * hash(self.right) def __hash__(self): return self._hash

Esto parece estar funcionando, pero realmente no estoy seguro acerca de la creación de subclases y la inicialización en Python, especialmente con tuplas. ¿Hay alguna trampa para esta solución? ¿Hay alguna manera recomendada de cómo hacer esto? ¿Está bien? Gracias por adelantado.


editar para 2017: resulta que namedtuple no es una gran idea . attrs es la alternativa moderna.

class Edge(EdgeBase): def __new__(cls, left, right): self = super(Edge, cls).__new__(cls, left, right) self._hash = hash(self.left) * hash(self.right) return self def __hash__(self): return self._hash

__new__ es lo que quieres llamar aquí porque las tuplas son inmutables. Los objetos inmutables se crean en __new__ y luego se devuelven al usuario, en lugar de rellenarse con datos en __init__ .

cls tiene que pasarse dos veces a la super llamada en __new__ porque __new__ es, por razones históricas / impares, implícitamente un staticmethod .