¿Cuáles son exactamente las reglas de alcance de Python?
Si tengo un código:
code1
class Foo:
code2
def spam.....
code3
for code4..:
code5
x()
Donde se xencuentra Algunas opciones posibles incluyen la siguiente lista:
- En el archivo fuente adjunto
- En el espacio de nombres de clase
- En la definición de la función
- En la variable de índice for loop
- Dentro del bucle for
También existe el contexto durante la ejecución, cuando la función spamse pasa a otro lugar. ¿Y quizás las funciones lambda pasan un poco diferente?
Debe haber una referencia o algoritmo simple en alguna parte. Es un mundo confuso para los programadores intermedios de Python.
python
scope
dynamic-languages
Charles Merriam
fuente
fuente

Respuestas:
En realidad, una regla concisa para la resolución de Python Scope, de Learning Python, 3rd. Ed. . (Estas reglas son específicas de nombres de variables, no de atributos. Si hace referencia a ellas sin un punto, se aplican estas reglas).
Regla LEGB
L ocal: nombres asignados de cualquier forma dentro de una función (
defolambda), y no declarados globales en esa funciónE nclosing-función - Nombres asignados en el ámbito local de cualquier y todas las funciones estáticamente de cerramiento (
defolambda), del interior al exteriorG lobal (módulo): nombres asignados en el nivel superior de un archivo de módulo o ejecutando una
globaldeclaración en undefarchivoB uilt-in (Python) - Los nombres preasignados en el módulo incorporado nombres:
open,range,SyntaxError, etc.Entonces, en el caso de
El
forbucle no tiene su propio espacio de nombres. En orden LEGB, los ámbitos seríandef spam(encode3,code4ycode5)def)xdeclarada globalmente en el módulo (incode1)?xen Python.xnunca se encontrará encode2(incluso en los casos en que podría esperar que lo haga, vea la respuesta de Antti o aquí ).fuente
global(var_name)es sintácticamente incorrecto. La sintaxis correcta seríaglobal var_namesin paréntesis. Sin embargo, tienes un punto válido.>>> def foo(x): ... y = x ... def bar(z): ... y = z ... bar(5) ... print x,y ... >>> foo(3) 3 3yestá siendo escrito y no hayglobal ydeclaraciones, vea el comentario de @ Peter.Esencialmente, lo único en Python que introduce un nuevo alcance es una definición de función. Las clases son un poco un caso especial en el sentido de que cualquier cosa definida directamente en el cuerpo se coloca en el espacio de nombres de la clase, pero no son accesibles directamente desde los métodos (o clases anidadas) que contienen.
En su ejemplo, solo hay 3 ámbitos en los que se buscará x:
Alcance del correo no deseado: contiene todo lo definido en el código 3 y el código 5 (así como el código 4, su variable de bucle)
El alcance global: que contiene todo lo definido en el código 1, así como Foo (y lo que cambie después)
El espacio de nombres incorporado. Un poco de un caso especial: contiene las diversas funciones y tipos incorporados de Python, como len () y str (). En general, esto no debe ser modificado por ningún código de usuario, por lo tanto, espere que contenga las funciones estándar y nada más.
Solo aparecen más ámbitos cuando introduce una función anidada (o lambda) en la imagen. Sin embargo, se comportarán más o menos como cabría esperar. La función anidada puede acceder a todo en el ámbito local, así como a cualquier cosa en el ámbito de la función de cierre. p.ej.
Restricciones
Se puede acceder a las variables en ámbitos que no sean las variables de la función local, pero no se pueden rebotar a nuevos parámetros sin más sintaxis. En cambio, la asignación creará una nueva variable local en lugar de afectar la variable en el ámbito primario. Por ejemplo:
Para modificar realmente los enlaces de las variables globales desde el alcance de una función, debe especificar que la variable es global con la palabra clave global. P.ej:
Actualmente no hay forma de hacer lo mismo para las variables al incluir ámbitos de funciones , pero Python 3 introduce una nueva palabra clave, "
nonlocal" que actuará de manera similar a global, pero para ámbitos de funciones anidadas.fuente
No hubo una respuesta completa sobre el tiempo de Python3, así que hice una respuesta aquí. La mayor parte de lo que se describe aquí se detalla en la Resolución 4.2.2 de los nombres de la documentación de Python 3.
Como se proporciona en otras respuestas, hay 4 ámbitos básicos, el LEGB, para Local, Enclosing, Global y Builtin. Además de esos, hay un alcance especial, el cuerpo de la clase , que no comprende un alcance cerrado para los métodos definidos dentro de la clase; cualquier tarea dentro del cuerpo de la clase hace que la variable a partir de ahí esté vinculada en el cuerpo de la clase.
Especialmente, ninguna declaración de bloque, además de
defyclass, crea un alcance variable. En Python 2, la comprensión de la lista no crea un alcance variable, sin embargo, en Python 3 la variable de bucle dentro de las comprensiones de la lista se crea en un nuevo alcance.Demostrar las peculiaridades del cuerpo de clase.
Por lo tanto, a diferencia del cuerpo de la función, puede reasignar la variable al mismo nombre en el cuerpo de la clase, para obtener una variable de clase con el mismo nombre; más búsquedas en este nombre resuelven la variable de clase en su lugar.
Una de las mayores sorpresas para muchos recién llegados a Python es que un
forbucle no crea un alcance variable. En Python 2, las comprensiones de la lista tampoco crean un alcance (¡mientras que los generadores y las comprensiones de dict sí lo hacen!) En cambio, pierden el valor en la función o el alcance global:Las comprensiones se pueden usar como una manera astuta (o horrible, si lo desea) para hacer variables modificables dentro de las expresiones lambda en Python 2: una expresión lambda crea un alcance variable, como lo
defharía la declaración, pero dentro de lambda no se permiten declaraciones. La asignación como una declaración en Python significa que no se permiten asignaciones variables en lambda, pero una comprensión de la lista es una expresión ...Este comportamiento se ha corregido en Python 3: no hay expresiones de comprensión ni generadores de variables de fuga.
Lo global realmente significa el alcance del módulo; el módulo principal de python es el
__main__; todos los módulos importados son accesibles a través de lasys.modulesvariable; para obtener acceso a__main__uno puede usarsys.modules['__main__'], oimport __main__; es perfectamente aceptable acceder y asignar atributos allí; se mostrarán como variables en el alcance global del módulo principal.Si alguna vez se asigna un nombre en el alcance actual (excepto en el alcance de la clase), se considerará que pertenece a ese alcance, de lo contrario se considerará que pertenece a cualquier alcance adjunto que se asigne a la variable (puede que no se asigne todavía, o no), o finalmente el alcance global. Si la variable se considera local, pero aún no se ha establecido o se ha eliminado, la lectura del valor de la variable dará como resultado
UnboundLocalErroruna subclase deNameError.El alcance puede declarar que quiere explícitamente modificar la variable global (alcance del módulo), con la palabra clave global:
Esto también es posible incluso si se sombreó en el alcance adjunto:
En python 2 no hay una manera fácil de modificar el valor en el alcance adjunto; generalmente esto se simula teniendo un valor mutable, como una lista con una longitud de 1:
Sin embargo, en Python 3,
nonlocalviene a rescatar:La
nonlocaldocumentación dice quees decir,
nonlocalsiempre se refiere al ámbito externo no global más interno donde se ha vinculado el nombre (es decir, asignado, incluido el utilizado como laforvariable de destino, en lawithcláusula o como un parámetro de función).Cualquier variable que no se considere local al alcance actual, o cualquier alcance que la incluya, es una variable global. Se busca un nombre global en el diccionario global del módulo; si no se encuentra, el global se busca desde el módulo integrado; el nombre del módulo fue cambiado de python 2 a python 3; en python 2 era
__builtin__y en python 3 ahora se llamabuiltins. Si asigna a un atributo del módulo integrado, será visible a partir de entonces para cualquier módulo como una variable global legible, a menos que ese módulo los sombree con su propia variable global con el mismo nombre.Leer el módulo integrado también puede ser útil; suponga que desea la función de impresión de estilo python 3 en algunas partes del archivo, pero otras partes del archivo aún usan la
printdeclaración. En Python 2.6-2.7 puede obtener laprintfunción Python 3 con:En
from __future__ import print_functionrealidad, no importa laprintfunción en ningún lugar de Python 2; en cambio, solo deshabilita las reglas de análisis para laprintdeclaración en el módulo actual, se manejaprintcomo cualquier otro identificador de variable y, por lo tanto, permite queprintla función se busque en las funciones incorporadas.fuente
Las reglas de alcance para Python 2.x ya se han descrito en otras respuestas. Lo único que agregaría es que en Python 3.0, también existe el concepto de un alcance no local (indicado por la palabra clave 'no local'). Esto le permite acceder directamente a los ámbitos externos y abre la posibilidad de hacer algunos trucos ingeniosos, incluidos los cierres léxicos (sin hacks feos que involucren objetos mutables).
EDITAR: Aquí está el PEP con más información sobre esto.
fuente
Un ejemplo un poco más completo de alcance:
salida:
fuente
methodymethod_local_refdeben destacarse.methodpuede acceder a la variable global e imprimirla como en5. Global x. Peromethod_local_refno puede porque más adelante define una variable local con ese mismo nombre. Puede probar esto quitando lax = 200línea y ver la diferenciaPython resuelve sus variables con, generalmente, tres espacios de nombres disponibles.
Hay dos funciones:
globalsylocalsque le muestran el contenido de dos de estos espacios de nombres.Los espacios de nombres se crean mediante paquetes, módulos, clases, construcción de objetos y funciones. No hay otros sabores de espacios de nombres.
En este caso, la llamada a una función denominada
xdebe resolverse en el espacio de nombres local o en el espacio de nombres global.Local en este caso, es el cuerpo de la función del método
Foo.spam.Global es, bueno, global.
La regla es buscar en los espacios locales anidados creados por funciones de método (y definiciones de funciones anidadas), luego buscar global. Eso es.
No hay otros ámbitos. La
fordeclaración (y otras declaraciones compuestas comoifytry) no crean nuevos ámbitos anidados. Solo definiciones (paquetes, módulos, funciones, clases e instancias de objeto).Dentro de una definición de clase, los nombres son parte del espacio de nombres de clase.
code2, por ejemplo, debe estar calificado por el nombre de la clase. En generalFoo.code2. Sin embargo,self.code2también funcionará porque los objetos Python miran la clase que lo contiene como una alternativa.Un objeto (una instancia de una clase) tiene variables de instancia. Estos nombres están en el espacio de nombres del objeto. Deben estar calificados por el objeto. (
variable.instance.)Desde un método de clase, tienes locales y globales. Dices
self.variableelegir la instancia como el espacio de nombres. Notarás queselfes un argumento para cada función miembro de la clase, por lo que es parte del espacio de nombres local.Consulte las Reglas de Python Scope , Python Scope , Variable Scope .
fuente
Python has two namespaces available. Global and local-to-something.x no se encuentra porque no lo has definido. :-) Se puede encontrar en code1 (global) o code3 (local) si lo pones allí.
code2 (miembros de la clase) no son visibles para el código dentro de los métodos de la misma clase; por lo general, se accede a ellos usando self. code4 / code5 (bucles) viven en el mismo ámbito que code3, por lo que si escribiera en x allí estaría cambiando la instancia de x definida en code3, no creando una nueva x.
Python tiene un alcance estático, por lo que si pasa 'spam' a otra función, el spam todavía tendrá acceso a los globales en el módulo del que proviene (definido en el código 1), y a cualquier otro ámbito que contenga (ver más abajo). Se accedería nuevamente a los miembros de code2 a través de self.
lambda no es diferente a def. Si tiene una lambda utilizada dentro de una función, es lo mismo que definir una función anidada. En Python 2.2 en adelante, los ámbitos anidados están disponibles. En este caso, puede vincular x en cualquier nivel de anidación de funciones y Python recogerá la instancia más interna:
fun3 ve la instancia x desde el ámbito que contiene más cercano, que es el ámbito de función asociado con fun2. Pero las otras instancias x, definidas en fun1 y globalmente, no se ven afectadas.
Antes de nested_scopes, en Python pre-2.1 y en 2.1, a menos que solicite específicamente la función mediante una importación desde el futuro, los alcances de fun1 y fun2 no son visibles para fun3, por lo que la respuesta de S.Lott se mantiene y obtendrá la x global :
fuente
En Python
Si no se puede encontrar una variable en el alcance actual, consulte el pedido LEGB.
fuente