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
.