Entrada / Salida¶
En este bloque se tratan los casos de estudio relacionados con la entrada / salida de información
- Generar de informes: Word, Excel...
- Exportación / importación de información
- Transformación de datos
- Exportar información de forma portable: XML, JSON, YAML...
IO-001 - Envío de información por múltiples canales¶
Problema¶
Mi aplicación muestra información por pantalla pero he de cambiar mucho código cuando, posteriormente, quiero añadir nuevas funciones en esos mismos puntos nuevas acciones como:
- Añadir niveles de logging.
- Volcar esa misma información a un fichero.
- Enviar esa información a más de una ubicación.
Este es el código normal, con un print(...):
1 2 3 4 5 6 7 8 9 | # ----------------------------------------------------------------------
def hello():
"""Display a hello world text"""
print("hello")
# ----------------------------------------------------------------------
if __name__ == '__main__':
hello()
|
Vemos realmente el problema cuando queremos añadir más localizaciones donde enviar el texto:
1 2 3 4 5 6 7 8 9 10 11 12 | # ----------------------------------------------------------------------
def hello():
"""Display a hello world text"""
print("hello")
with open("my_file.txt", "") as f:
f.write("hello")
# ----------------------------------------------------------------------
if __name__ == '__main__':
hello()
|
Y todavía se complica más si queremos añadir niveles de verbosidad:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | # ----------------------------------------------------------------------
def hello(verbosity):
"""Display a hello world text"""
print("hello")
if verbosity > 0:
with open("my_file.txt", "") as f:
f.write("hello")
if verbosity > 0:
print("verbosity 1")
# ----------------------------------------------------------------------
if __name__ == '__main__':
hello(1)
|
Solución¶
Usar un objeto estático y global que será el encargado de mostrar la información y que podremos configurar en función de lo que necesitemos.
Cómo¶
Para ello tenemos que declarar una clase estática global, que siga el patrón Singleton en Python, configurarla y llamarla de forma adecuada:
Nota
El patrón Singleton nos asegura que solo haya corriendo una instancia de un determinad objeto a la vez.
Si se crea otra nueva instancia, internamente no creará un nuevo objeto, sino que “rescatará” de la memoria el primer objeto que se creó y se reutilizará.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | # ----------------------------------------------------------------------
class Displayer:
instance = None
def __new__(cls, *args, **kwargs):
if cls.instance is None:
cls.instance = object.__new__(cls, *args, **kwargs)
cls.__initialized = False
return cls.instance
def config(self, **kwargs):
self.out_file = kwargs.get("out_file", None)
self.out_screen = kwargs.get("out_screen", True)
self.verbosity = kwargs.get("verbosity", 0)
if self.out_file:
self.out_file_handler = open(self.out_file, "w")
def display(self, message):
if self.verbosity > 0:
self.__display(message)
def display_verbosity(self, message):
if self.verbosity > 1:
self.__display(message)
def display_more_verbosity(self, message):
if self.verbosity > 2:
self.__display(message)
def __display(self, message):
if self.out_screen:
print(message)
if self.out_file_handler:
self.out_file_handler.write(message)
def __init__(self):
if not self.__initialized:
self.__initialized = True
self.out_file = None
self.out_file_handler = None
self.out_screen = True
self.verbosity = 0
# ----------------------------------------------------------------------
def hello():
"""Display a hello world text"""
# Use displayer
out = Displayer()
out.display("hello")
out.display_verbosity("hello")
# This will not be displayed by the verbosity level to 1
out.display_more_verbosity("hello")
# ----------------------------------------------------------------------
if __name__ == '__main__':
# Config displayer
d = Displayer()
d.config(out_screen=True,
out_file="~/my_log.txt",
verbosity=1)
# Call function
hello(1)
|