¿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 x
encuentra 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 spam
se 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 (
def
olambda
), 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 (
def
olambda
), del interior al exteriorG lobal (módulo): nombres asignados en el nivel superior de un archivo de módulo o ejecutando una
global
declaración en undef
archivoB uilt-in (Python) - Los nombres preasignados en el módulo incorporado nombres:
open
,range
,SyntaxError
, etc.Entonces, en el caso de
El
for
bucle no tiene su propio espacio de nombres. En orden LEGB, los ámbitos seríandef spam
(encode3
,code4
ycode5
)def
)x
declarada globalmente en el módulo (incode1
)?x
en Python.x
nunca 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_name
sin 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 3
y
está siendo escrito y no hayglobal y
declaraciones, 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
def
yclass
, 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
for
bucle 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
def
harí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.modules
variable; 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
UnboundLocalError
una 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,
nonlocal
viene a rescatar:La
nonlocal
documentación dice quees decir,
nonlocal
siempre se refiere al ámbito externo no global más interno donde se ha vinculado el nombre (es decir, asignado, incluido el utilizado como lafor
variable de destino, en lawith
clá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
print
declaración. En Python 2.6-2.7 puede obtener laprint
función Python 3 con:En
from __future__ import print_function
realidad, no importa laprint
función en ningún lugar de Python 2; en cambio, solo deshabilita las reglas de análisis para laprint
declaración en el módulo actual, se manejaprint
como cualquier otro identificador de variable y, por lo tanto, permite queprint
la 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
method
ymethod_local_ref
deben destacarse.method
puede acceder a la variable global e imprimirla como en5. Global x
. Peromethod_local_ref
no puede porque más adelante define una variable local con ese mismo nombre. Puede probar esto quitando lax = 200
línea y ver la diferenciaPython resuelve sus variables con, generalmente, tres espacios de nombres disponibles.
Hay dos funciones:
globals
ylocals
que 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
x
debe 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
for
declaración (y otras declaraciones compuestas comoif
ytry
) 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.code2
tambié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.variable
elegir la instancia como el espacio de nombres. Notarás queself
es 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