2010-06-21 21 views
13

Soy un novato de Python procedente de un fondo de C++. Aunque sé que no es Pythonic intentar encontrar un concepto que coincida con mi antiguo conocimiento de C++, creo que esta pregunta sigue siendo una pregunta general:Orden de inicialización del módulo de Python?

En C++, existe un problema conocido llamado inicialización de variable global/estática Fiasco de orden, debido a la incapacidad de C++ para decidir qué variable global/estática se inicializaría primero en las unidades de compilación, así una variable global/estática dependiendo de otra en diferentes unidades de compilación podría inicializarse antes que sus contrapartes de dependencia, y cuando el dependiente comenzó a utilizar los servicios proporcionados por el objeto de dependencia, tendríamos un comportamiento indefinido. Aquí no quiero profundizar en cómo C++ resuelve este problema. :)

En el mundo de Python, veo usos de variables globales, incluso a través de diferentes archivos .py, y un caso de uso típico que vi fue: inicializar un objeto global en un archivo .py y en otro .py archivos, el código simplemente comienza sin miedo a usar el objeto global, suponiendo que debe haber sido inicializado en otro lugar, lo que bajo C++ definitivamente no lo acepto por mi cuenta, debido al problema que especifiqué anteriormente.

No estoy seguro si el caso de uso anterior es una práctica común en Python (Pythonic), y ¿cómo soluciona Python este tipo de problema de orden de inicialización de variable global en general?

¡Muchas gracias!

Lin

Respuesta

10

En C++, no es un problema bien conocido llamado mundial/estática inicialización de variables para f iasco, debido a la incapacidad C++ 's para decidir qué variable global/estática se inicializa primero a través de las unidades de compilación,

Creo que la declaración pone de manifiesto una diferencia clave entre Python y C++: en Python, no hay tal cosa como diferentes unidades de compilación. Lo que quiero decir con eso es que, en C++ (como saben), dos archivos de origen diferentes pueden compilarse de forma completamente independiente uno del otro, y por lo tanto, si compara una línea en el archivo A y una línea en el archivo B, no hay nada que decir usted que se colocará primero en el programa. Es algo así como la situación con múltiples hilos: no se puede decir si una sentencia particular en el hilo 1 se ejecutará antes o después de una declaración particular en el hilo 2. Se podría decir que los programas C++ se compilan en paralelo.

Por el contrario, en Python, la ejecución comienza en la parte superior de un archivo y continúa en un orden bien definido a través de cada instrucción en el archivo, ramificándose a otros archivos en los puntos donde se importan.De hecho, casi podría pensar en la directiva import como #include, y de esa manera podría identificar el orden de ejecución de todas las líneas de código en todos los archivos fuente del programa. (Bueno, es un poco más complicado que eso, ya que un módulo solo se ejecuta realmente la primera vez que se importa, y por otros motivos). Si los programas C++ se compilan en paralelo, los programas Python se interpretan en serie.

Su pregunta también toca el significado más profundo de los módulos en Python. Un módulo de Python, que es todo lo que está en un único archivo .py, es un objeto real. Todo lo que se declara al alcance "global" en un solo archivo fuente es en realidad un atributo de ese objeto de módulo. No hay un verdadero alcance global en Python. (Los programadores de Python a menudo dicen "global" y de hecho hay una palabra clave global en el idioma, pero siempre se refiere al nivel superior del módulo actual). Pude ver que era un concepto un poco extraño acostumbrarse a viniendo de un fondo de C++. Me tomó un tiempo acostumbrarse a mí, viniendo de Java, y en este sentido, Java es mucho más similar a Python que C++. (Tampoco hay un alcance global en Java)

Mencionaré que en Python es perfectamente normal usar una variable sin tener idea de si se ha inicializado/definido o no. Bueno, tal vez no sea normal, pero al menos aceptable en circunstancias apropiadas. En Python, tratar de usar una variable indefinida plantea un NameError; no obtienes un comportamiento arbitrario como lo harías en C o C++, por lo que puedes manejar fácilmente la situación. Es posible que vea este patrón:

try: 
    duck.quack() 
except NameError: 
    pass 

que no hace nada si duck no existe. En realidad, lo que va más comúnmente se ve es

try: 
    duck.quack() 
except AttributeError: 
    pass 

que no hace nada si duck no tiene un método denominado quack. (AttributeError es el tipo de error que obtienes cuando intentas acceder a un atributo de un objeto, pero el objeto no tiene ningún atributo por ese nombre.) Esto es lo que se aprueba para una verificación de tipo en Python: calculamos que si todos nosotros Necesitamos que el pato que hacer es curandero, podemos pedirle que graznar, y si lo hace, no nos importa si es Realmente un pato o no. (Se llama pato escribiendo ;-)

+0

¡Definitivamente es una explicación completa del problema que publiqué, exactamente al punto! ¡Gracias! – Lin

12

importación de Python ejecuta nuevos módulos de Python de principio a fin. Las importaciones posteriores solo dan como resultado una copia de la referencia existente en sys.modules, incluso si todavía está en el medio de la importación del módulo debido a una importación circular. Los atributos del módulo ("variables globales" están realmente en el alcance del módulo) que se han inicializado antes de que exista la importación circular.

main.py:

import a 

a.py:

var1 = 'foo' 
import b 
var2 = 'bar' 

b.py:

import a 
print a.var1 # works 
print a.var2 # fails 
+0

El orden de inicialización de la variable global Python se realiza y aplica explícitamente a través de la instrucción "import", lo cual tiene sentido, ya que C++ no tiene forma de especificar explícitamente las relaciones de dependencia de la unidad de compilación. Gracias por aclararlo! – Lin

Cuestiones relacionadas