En Python, ¿qué sucede cuando importas dentro de una función? [duplicar]
¿Cuáles son las ventajas y desventajas de importar un módulo y/o función de Python dentro de una función, con respecto a la eficiencia de la velocidad y la memoria?
¿Se vuelve a importar cada vez que se ejecuta la función, o quizás solo una vez al principio, ya sea que se ejecute la función o no?
¿Se vuelve a importar cada vez que se ejecuta la función?
No; o mejor dicho, los módulos de Python se almacenan esencialmente en caché cada vez que se importan, por lo que importar una segunda (o tercera, o cuarta...) vez en realidad no los obliga a pasar por todo el proceso de importación nuevamente. 1
¿Importa una vez al principio independientemente de que la función se ejecute o no?
No, solo se importa si y cuando se ejecuta la función. 2 , 3
En cuanto a los beneficios: depende, supongo. Si solo puede ejecutar una función muy raramente y no necesita importar el módulo en ningún otro lugar, puede ser beneficioso importarlo solo en esa función. O si hay un conflicto de nombres u otra razón por la que no desea que el módulo o los símbolos del módulo estén disponibles en todas partes , es posible que solo desee importarlo en una función específica. (Por supuesto, siempre hay algo from my_module import my_function as f
para esos casos).
En la práctica general, probablemente no sea tan beneficioso. De hecho, la mayoría de las guías de estilo de Python alientan a los programadores a colocar todas las importaciones al principio del archivo del módulo.
La primera vez que import goo
desde cualquier lugar (dentro o fuera de una función), goo.py
(u otra forma importable) se carga y sys.modules['goo']
se configura en el objeto del módulo así creado. Cualquier importación futura dentro de la misma ejecución del programa (nuevamente, ya sea dentro o fuera de una función) simplemente búsquela sys.modules['goo']
y vincúlela a barename goo
en el alcance apropiado. La búsqueda de dict y la vinculación de nombres son operaciones muy rápidas.
Suponiendo que el primero import
se amortiza totalmente durante la ejecución del programa de todos modos, tener el "alcance apropiado" a nivel de módulo significa que cada uso de goo.this
, goo.that
, etc., son dos búsquedas de dict: una para goo
y otra para el nombre del atributo. Tenerlo como "nivel de función" paga una configuración de variable local adicional por ejecución de la función (¡incluso más rápido que la parte de búsqueda en el diccionario!) pero guarda una búsqueda de dict (intercambiándola por una búsqueda de variable local, increíblemente rápida) para cada goo.this
( etc) acceso, básicamente reduciendo a la mitad el tiempo que toman dichas búsquedas.
Estamos hablando de unos pocos nanosegundos de una forma u otra, por lo que no es una optimización que valga la pena. La única ventaja potencialmente sustancial de tener import
dentro de una función es cuando esa función puede no ser necesaria en absoluto en una ejecución determinada del programa, por ejemplo, esa función se ocupa de errores, anomalías y situaciones raras en general; si ese es el caso, cualquier ejecución que no necesite la funcionalidad ni siquiera realizará la importación (y eso es un ahorro de microsegundos, no solo nanosegundos), solo las ejecuciones que sí necesiten la funcionalidad pagarán el precio (modesto pero mensurable).
Sigue siendo una optimización que sólo vale la pena en situaciones bastante extremas, y hay muchas otras que consideraría antes de intentar exprimir microsegundos de esta manera.