2010-08-31 10 views
107

No estoy preguntando sobre las reglas de alcance de Python; Por lo general, entiendo cómo funciona el alcance en Python para bucles. Mi pregunta es por qué las decisiones de diseño se tomaron de esta manera. Por ejemplo (sin juego de palabras):Scoping en bucles "for" de Python

for foo in xrange(10): 
    bar = 2 
print(foo, bar) 

Lo anterior se imprimirá (9,2).

Esto me parece extraño: 'foo' realmente solo controla el ciclo, y 'bar' se definió dentro del ciclo. Puedo entender por qué podría ser necesario que 'bar' fuera accesible fuera del bucle (de lo contrario, los bucles tendrían una funcionalidad muy limitada). Lo que no entiendo es por qué es necesario que la variable de control permanezca en el alcance después de que termine el ciclo. En mi experiencia, simplemente satura el espacio de nombres global y hace que sea más difícil rastrear los errores que podrían atrapar los intérpretes en otros idiomas.

+3

Si no desea que el bucle 'for' abarrote su espacio de nombres global, envuélvalo en una función. Cierres en abundancia! – jathanism

+13

A menos que esté ejecutando un bucle en el espacio de nombres global (poco común), está abarrotando un espacio de nombres * local *. –

+1

Si esto no existiera, ¿cómo continuarías procesando más tarde en el punto que dejaste dentro del ciclo? Simplemente defina la variable de control * antes de * el ciclo? – endolith

Respuesta

67

La respuesta más probable es que simplemente mantiene la gramática simple, no ha sido un obstáculo para la adopción, y muchos se alegran de no tener que eliminar la ambigüedad del alcance al que pertenece un nombre al asignarlo dentro de un ciclo construir. Las variables no se declaran dentro de un alcance, está implícito en la ubicación de las declaraciones de asignación. La palabra clave global existe solo por este motivo (para indicar que la asignación se realiza en un ámbito global).

actualización

He aquí una buena discusión sobre el tema: http://mail.python.org/pipermail/python-ideas/2008-October/002109.html

propuestas anteriores para realizar ciclo for variables locales al bucle han tropezado con el problema de código existente que se basa en la variable de bucle manteniendo su valor después de salir del bucle , y parece que esto es considerado como una característica deseable.

En resumen, es probable que pueda echarle la culpa a la comunidad Python: P

+0

¿Cómo sería la gramática más complicada si el alcance de la variable de inducción estuviera limitado al cuerpo del ciclo? Tal cambio se limitaría al análisis semántico en Python, no a su gramática. –

+2

Los bucles no son bloques en Python. Este tipo de cambio de comportamiento requeriría cambiar la gramática fundamentalmente o proporcionar un caso especial. El concepto completo de una variable de inducción tampoco se expresa en la gramática actual.La gramática proporciona el contrato de cómo interpretará el intérprete. Mi punto es que no puedo prever cómo se puede hacer un cambio en este comportamiento sin hacer la gramática más complicada. Todo es discutible ya que el efecto secundario de la decisión de diseño se ha convertido en una característica. –

27

Un caso muy útil para esto es cuando se utiliza enumerate y desea que el recuento total en el final:

for count, x in enumerate(someiterator): 
    dosomething(count, x) 
print "I did something {0} times".format(count) 

es necesario? No. Pero, seguro, es conveniente.

Otra cosa a tener en cuenta: en Python 2, las variables en las listas por comprensión se filtraron así:

>>> [x**2 for x in range(10)] 
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81] 
>>> x 
9 

embargo, el mismo no se aplica a Python 3.

+2

Podrías haber hecho eso presumiblemente en la cláusula 'else', es decir. 'else: print" Hice algo {0} veces ".format (count)' - before scope local (que no existe en Python) desaparece –

+3

Solo el segundo ejemplo no funciona en Python 3, ¿verdad? El primero todavía? ¿Notas sobre por qué fue eliminado de Python 3? – endolith

+4

** para count, item in enumerate (a, start = 1): ** # default index es de cero –

41

Python no tiene bloques, al igual que en otros lenguajes (como C/C++ o Java). Por lo tanto, la unidad de alcance en Python es una función.

+1

Estoy confundido: ¿qué impide que Python analice los bucles de la misma manera que las funciones tienen un alcance? – chimeracoder

+17

No es cierto, es solo que la gramática no se vuelve loca. (http://docs.python.org/reference/executionmodel.html#naming-and-binding) "Un bloque es una parte del texto del programa Python que se ejecuta como una unidad. Los siguientes son bloques: un módulo, una función cuerpo, y una definición de clase ... " –

+1

@thebackhand, nada. Simplemente se consideró innecesario. – habnabit

1

Una de las principales influencias para Python es ABC, un lenguaje desarrollado en los Países Bajos para la enseñanza de los conceptos de programación para principiantes. El creador de Python, Guido van Rossum, trabajó en ABC durante varios años en la década de 1980. No sé casi nada sobre ABC, pero como está destinado a principiantes, supongo que debe tener un número limitado de ámbitos, al igual que los primeros BASIC.

+0

@Prune: ¿Qué vínculo? –

+0

No tengo idea de cómo se realizó esta objeción de solo enlace. Gracias por la alerta. Debo haber hecho clic mal. – Prune

1

Para los principiantes, si las variables fueran loops locales, esos loops serían inútiles para la mayoría de la programación del mundo real.

En la situación actual:

# Sum the values 0..9 
total = 0 
for foo in xrange(10): 
    total = total + foo 
print total 

produce 45. Ahora, considere cómo funciona la asignación en Python. Si las variables de bucle eran estrictamente local:

# Sum the values 0..9? 
total = 0 
for foo in xrange(10): 
    # Create a new integer object with value "total + foo" and bind it to a new 
    # loop-local variable named "total". 
    total = total + foo 
print total 

produce 0, porque total dentro del bucle después de la asignación no es la misma variable como total fuera del bucle. Este no sería el comportamiento óptimo o esperado.

+4

No respondiendo la pregunta. El OP estaba preguntando acerca de foo, no total (o barra en su ejemplo). –

+4

@JamesBradbury 'total' y' foo' todavía tendrían enlaces de bucle local en el escenario del PO y la lógica es la misma. –

+1

OP: "Puedo entender por qué podría ser necesario que 'bar' fuera accesible fuera del bucle (de lo contrario, los bucles tendrían una funcionalidad muy limitada). Lo que no entiendo es por qué es necesario para la variable de control * * para permanecer en el alcance después de que el bucle salga ". (el énfasis es mío) –