2012-04-28 17 views
26

Si una función necesita modificar una variable declarada en el alcance global, necesita usar la declaración global. Sin embargo, si la función sólo tiene que leer una variable global que puede hacerlo sin necesidad de utilizar una declaración global:Python: ¿Por qué se necesita global solo en la asignación y no en las lecturas?

X = 10 
def foo(): 
    global X 
    X = 20 # Needs global declaration 
def bar(): 
    print(X) # Does not need global 

Mi pregunta es sobre el diseño de Python: ¿por qué Python diseñado para permitir la lectura de variables globales sin usando la declaración global? Es decir, ¿por qué solo la asignación de fuerza tiene carácter global? ¿Por qué no forzar globalmente al leer también? (Eso lo haría uniforme y elegante.)

Nota: Puedo ver que no hay ambigüedad durante la lectura, pero al asignarla no está claro si se pretende crear una nueva variable local o asignarla a la global. Pero, espero que haya una mejor razón o intención para esta opción de diseño desigual por parte de la BDFL.

+2

Para ocultar errores sutiles? – Inverse

Respuesta

15

mirada a este código:

from module import function 

def foo(x): 
    return function(x) 

El nombre function que aquí hay una global. Sería terriblemente tedioso si tuviera que decir global function para que este código funcione.

Antes de decir que su X y mi function son diferentes (porque se trata de una variable y la otra es una función importada), recuerda que todos los nombres en Python son tratados de la misma: cuando se utiliza, su valor se busca en la jerarquía de alcance Si necesitaras global X, necesitarías global function. Ick.

+3

Sin embargo, eso realmente no responde la pregunta. También podría ampliar este argumento para modificar los globales. ¿Por qué el global explícito para modificar globales? – jterrace

+3

Porque si no incluye 'global X' la declaración' X = 10' crearía una 'X' local unida a' 10' en lugar de volver a enlazar la 'X' global a' 10'. –

+4

@jterrace: la pregunta era "¿Por qué se necesita global * solo * en una tarea?, "no", por qué es necesario global en la asignación. " –

24

Con ámbitos anidados, las búsquedas variables son fáciles. Ocurren en una cadena que comienza con los lugareños, a través de defs adjuntos, a los módulos globales, y luego a los builtins. La regla es que el primer partido encontrado gana. En consecuencia, no necesita una declaración "global" para búsquedas.

Por el contrario, con las escrituras debe especificar en qué ámbito escribir. De lo contrario, no hay manera de determinar si "x = 10" en la función significaría "escribir en un espacio de nombres local" o "escribir en un espacio de nombres global".

Resumen ejecutivo, con la escritura tiene la opción de espacio de nombres, pero con las búsquedas basta la primera regla encontrada. Espero que esto ayude :-)

Edit: Sí, es así "porque así lo dijo BDFL", pero no es inusual en otros idiomas sin declaraciones de tipo tener una regla encontrada por primera vez para las búsquedas y solo requiere un modificador para escrituras no locales. Cuando lo piensas, esas dos reglas conducen a un código muy limpio ya que los modificadores del alcance solo se necesitan en el caso menos común (escrituras no locales).

+2

+1 para LEGB, siempre encontré fácil recordar – okm

16

Porque explícito es mejor que implícito.

No hay ambigüedad cuando lee una variable. Siempre obtiene el primero encontrado al buscar ámbitos desde locales hasta globales.

Al asignar, solo hay dos ámbitos que el intérprete puede suponer inequívocamente que está asignando: locales y globales. Dado que la asignación a local es el caso más común y la asignación a global en realidad se desaconseja, es el valor predeterminado. Para asignar a global tienes que hacerlo explícitamente, diciéndole al intérprete que donde sea que uses esa variable en este ámbito, debería ir directamente al alcance global y sabes lo que estás haciendo. En Python 3 también puede asignar al alcance envolvente más cercano con 'no local'.

Recuerde que cuando asigna un nombre en Python, esta nueva asignación no tiene nada que ver con el nombre previamente existente asignado a otra cosa. Imagínese si no hubiera ningún valor predeterminado en local y Python buscó en todos los ámbitos tratando de encontrar una variable con ese nombre y asignándole como lo hace al leer. El comportamiento de sus funciones podría cambiar basado no solo en sus parámetros, sino en el alcance adjunto. La vida sería miserable

+6

Como nota al margen que no encajo particularmente en la respuesta, he estado programando en Python profesionalmente durante 8 años y nunca ** he usado global para nada. –

+0

Pedro: Si estás escribiendo un script simple cuya función necesita modificar el estado global, ¿qué haces? ? ¿Qué pasa si las clases son demasiado pesadas para la secuencia de comandos simple? –

6

Usted mismo dice que con las lecturas no hay ambigüedad y con las escrituras hay. Por lo tanto, necesita algún mecanismo para resolver la ambigüedad con escrituras.

Una opción (posiblemente utilizada realmente por versiones mucho más antiguas de Python, IIRC) es simplemente decir que las escrituras siempre van al alcance local. Entonces no hay necesidad de una palabra clave global, y no hay ambigüedad. Pero entonces no se puede escribir en variables globales (sin usar cosas como globals() para obtenerlas de forma aproximada), así que eso no sería genial.

Otra opción, utilizada por los lenguajes que declaran variables estáticamente, es comunicar a la implementación del lenguaje por adelantado para cada alcance qué nombres son locales (los que declaras en ese alcance) y qué nombres son globales (nombres declarados en el alcance del módulo). Pero Python no tiene variables declaradas, por lo que esta solución no funciona.

Otra opción sería asignar x = 3 a una variable local solo si no hay un nombre en algún ámbito externo con el nombre x. Parece que intuitivamente haría lo correcto? Sin embargo, conduciría a algunos casos de esquina seriamente desagradables. Actualmente, donde x = 3 escribirá está estáticamente determinado por el analizador sintáctico; o bien no hay global x en el mismo ámbito y es una escritura local, o hay un global x y es una escritura global. Pero si lo que hará dependerá del alcance del módulo global, deberá esperar hasta el tiempo de ejecución para determinar dónde va la escritura , lo que significa que puede cambiar entre las invocaciones de una función. Piénsalo. Cada vez que creas un global en un módulo, alterarías el comportamiento de todas las funciones en el módulo que pasó a usar ese nombre como un nombre de variable local. Realice un cálculo de alcance de módulo que use tmp como una variable temporal y diga adiós al uso de tmp en todas las funciones en el módulo. Y me estremece pensar en los bugs oscuros que implican la asignación de un atributo en un módulo que has importado y luego llamar a una función desde ese módulo. Yuck.

Y otra opción es comunicarse con la implementación del idioma en cada tarea, ya sea local o global. Esto es a lo que Python se ha ido. Dado que hay un valor predeterminado sensato que cubre casi todos los casos (escribir en una variable local), tenemos la asignación local como predeterminada y marca explícitamente las asignaciones globales con global.


Existe una ambigüedad con las asignaciones que necesita algún mecanismo para resolverlo. global es uno de esos mecanismos. No es el único posible, pero en el contexto de Python, parece que todos los mecanismos alternativos son horribles. No sé qué tipo de "mejor razón" estás buscando.

+0

Ben: novato de Python aquí. ¿Es posible "inyectar" una nueva variable global en el tiempo de ejecución, aparte de th ¿Los que ya figuran en el código fuente en el alcance global? Tus respuestas parecen indicar esto, me gustaría saber cómo es posible. –

+1

@Ashwin El alcance global no es diferente de cualquier otro ámbito. No hay una sola declaración estática de lo que contiene; Python simplemente ejecuta el código en un módulo, como resultado de qué nombres se asignan en el ámbito global. Esto es exactamente de la misma manera que los nombres se definen en el ámbito local. Además de eso, cualquier otro código con una referencia al módulo (después de importarlo) puede asignar atributos en él, y los atributos del módulo son solo las variables globales dentro de ese módulo. Las funciones más en el módulo podrían usar 'global'. ¿Es ese el tipo de cosa al que te refieres? – Ben

+0

Ben: Entendido. Gracias :-) –

Cuestiones relacionadas