Getter con efecto secundario.

Creo una clase cuyos objetos se inicializan con un montón de código XML. La clase tiene la capacidad de extraer varios parámetros de ese XML y de almacenarlos en caché dentro de las variables de estado del objeto. La cantidad potencial de estos parámetros es grande y lo más probable es que el usuario no necesite la mayoría de ellos. Es por eso que he decidido realizar una inicialización “perezosa”.

En el siguiente caso de prueba, dicho parámetro es el title . Cuando el usuario intenta acceder a él por primera vez, la función getter analiza el XML, inicializa correctamente la variable de estado y devuelve su valor:

 class MyClass(object): def __init__(self, xml=None): self.xml = xml self.title = None def get_title(self): if self.__title is None: self.__title = self.__title_from_xml() return self.__title def set_title(self, value): self.__title = value title = property(get_title, set_title, None, "Citation title") def __title_from_xml(self): #parse the XML and return the title return title 

Esto se ve bien y funciona bien para mí. Sin embargo, estoy un poco molesto por el hecho de que la función getter es en realidad una “establecedora” en el sentido de que tiene un efecto secundario muy significativo en el objeto. ¿Es esta una preocupación legítima? Si es así, ¿cómo debo abordarlo?

Si bien el getter ciertamente realiza un efecto secundario, eso no es tradicionalmente lo que uno consideraría un efecto secundario malo. Dado que el getter siempre devuelve lo mismo (salvo los cambios de estado que intervienen), no tiene efectos secundarios visibles para el usuario. Este es un uso típico de las propiedades, por lo que no hay nada de qué preocuparse.

Este patrón de diseño se llama inicialización perezosa y tiene uso legítimo.

Bastantes años después, pero bien: aunque la inicialización perezosa está bien en sí misma, definitivamente no pospondré el análisis xml, etc., hasta que alguien acceda al title del objeto. Se supone que los atributos calculados se comportan como atributos simples, y el acceso a un atributo simple nunca boostá (suponiendo que el atributo existe, por supuesto).

FWIW Tuve un caso muy similar en un proyecto que asumí, con errores de análisis de xml en los lugares más inesperados, debido a que el desarrollador anterior usaba las propiedades de la misma manera que en el ejemplo OP, y tuve que corregirlo poniendo el Parte de análisis y validación en el momento de la instanciación.

Por lo tanto, use las propiedades para la inicialización lenta solo si, y cuando sepa, el primer acceso nunca boostá. En realidad, nunca use una propiedad para nada que pueda boost (al menos cuando se trata de una situación diferente). De lo contrario, no utilice una propiedad, convierta al obtentor en un método explícito y documente claramente que podría plantear esto o aquello.

NB: usar una propiedad para almacenar en caché algo no es el problema aquí, esto por sí solo está bien.