Hay varios problemas con el primer método:
- El alias no se actualizará cuando el atributo al que hace referencia cambie, a menos que salte a través de aros adicionales. Podría, por ejemplo, hacer
house
un property
con un setter, pero eso es un trabajo no trivial para algo que no debería requerirlo. Vea el final de esta respuesta para una implementación de muestra.
cleanup_house
No será heredable. Un objeto de función definido en una clase es un descriptor que no es de datos que puede heredarse y anularse, así como vincularse a una instancia. Un atributo de instancia como en el primer enfoque no está presente en la clase en absoluto. El hecho de que sea un método encuadernado es incidental. Una clase secundaria no podrá acceder super().cleanup_house
, por un ejemplo concreto.
person.cleanup_house.__name__ != 'cleanup_house'
. Esto no es algo que verifique con frecuencia, pero cuando lo haga, esperaría que fuera el nombre de la función cleanup
.
La buena noticia es que no tiene que repetir las firmas varias veces para usar el enfoque n. ° 2. Python ofrece la muy conveniente notación splat ( *
) / splatty-splat ( **
) para delegar todas las comprobaciones de argumentos al método que se está envolviendo:
def cleanup_house(self, *args, **kwargs):
return self.house.cleanup(*args, **kwargs)
Y eso es. Todos los argumentos regulares y predeterminados se pasan como están.
Esta es la razón por la que # 2 es, con mucho, el enfoque más pitónico. No tengo idea de cómo interactuará con los editores que admiten sugerencias de tipo a menos que copie la firma del método.
Una cosa que puede ser un problema es que cleanup_house.__doc__
no es lo mismo que house.cleanup.__doc__
. Esto podría merecer una conversión de house
a property
, cuyo setter asigna cleanup_house.__doc__
.
Para abordar el problema 1. (pero no 2. o 3.), puede implementarlo house
como una propiedad con un establecedor. La idea es actualizar los alias cada vez que house
cambie el atributo. Esta no es una buena idea en general, pero aquí hay una implementación alternativa a lo que tiene en la pregunta que probablemente funcionará un poco mejor:
class House:
def cleanup(self, arg1, arg2, kwarg1=False):
"""clean house is nice to live in!"""
pass
class Person:
def __init__(self, house: House):
self.house = house # use the property here
@property
def house(self):
return self._house
@house.setter
def house(self, value):
self._house = house
self.cleanup_house = self._house.cleanup
Person.cleanup_house
hacer. Obtiene la casa asociada con esa persona y la limpia. # 1 limpiará alguna casa, y en algún momento (inicialización), esa casa fue la correcta. No se trata bien con la persona que cambia de casa, o si una persona no tiene casa