Me pregunto acerca de un código como este:
def all_lines(filename): with open(filename) as infile: yield from infileEl objetivo de un administrador de contexto es tener un control explícito sobre la vida útil de alguna forma de estado, por ejemplo, un identificador de archivo. Un generador, por otro lado, mantiene su estado hasta que se agota o se elimina.
Sé que ambos casos funcionan en la práctica. Pero me preocupa si es una buena idea. Considere por ejemplo esto:
def all_first_lines(filenames): return [next(all_lines(filename), None) for filename in filenames]Nunca agoto los generadores. En cambio, su estado se destruye cuando se elimina el objeto generador. Esto funciona bien en implementaciones con recuento de referencias como CPython, pero ¿qué pasa con las implementaciones recolectadas como basura? ¡Prácticamente confío en el contador de referencia para administrar el estado, algo que los administradores de contexto fueron diseñados explícitamente para evitar!
E incluso en CPython no debería ser demasiado difícil construir casos en los que un generador sea parte de un ciclo de referencia y necesite que se destruya el recolector de basura.
Para resumir: ¿Consideraría prudente evitar los administradores de contexto en los generadores, por ejemplo, refactorizando el código anterior en algo como esto?
def all_lines(filename): with open(filename) as infile: return infile.readlines() def first_line(filename): with open(filename) as infile: return next(infile, None) def all_first_lines(filenames): return [first_line(filename) for filename in filenames]Hay dos respuestas a tu pregunta:
No soy un experto en las diferencias de las implementaciones de Python alt ( consulte esta página para ver el ejemplo de PyPy ), pero planteo que este problema de por vida no ocurrirá en el 99% de los casos. Si tiene éxito en producción, entonces sí, debe abordarlo (ya sea con su propuesta o una combinación de generador con administrador de contexto) de lo contrario, ¿por qué molestarse? Lo digo de una manera amable: su punto es estrictamente válido, pero irrelevante para la mayoría de los casos.
Si bien extiende la vida útil del objeto hasta que el generador sale o se destruye, también puede hacer que los generadores sean más fáciles de usar.
Considere la posibilidad de crear los generadores bajo un exterior y pasar el archivo como argumento en lugar de que lo abran. Ahora el archivo no es válido para su uso después de salir del administrador de contexto, aunque los generadores aún se pueden ver como utilizables.
Si es importante limitar el tiempo durante el cual se mantienen presionadas las manijas, puede cerrar explícitamente los generadores usando el método de cierre una vez que haya terminado con ellos.
Este es un problema similar al que trio intenta resolver con sus viveros para tareas asincrónicas, donde el administrador de contexto del vivero espera que todas las tareas generadas desde ese vivero finalicen antes de continuar, el ejemplo del tutorial ilustra esto. Esta publicación de blog del autor puede proporcionar algún razonamiento sobre la forma en que se hace en trío, lo que puede ser una lectura interesante que está algo relacionada con el problema.