| You are here: Inicio > Inmersión en Python > Procesamiento de HTML > locals y globals | << >> | ||||
Inmersión en PythonPython de novato a experto |
|||||
Hagamos por un minuto un inciso entre tanto procesamiento de HTML y hablemos sobre la manera en que Python gestiona las variables. Python incorpora dos funciones, locals y globals, que proporcionan acceso de tipo diccionario a las variables locales y globales.
¿Se acuerda de locals? La vio por primera vez aquí:
def unknown_starttag(self, tag, attrs):
strattrs = "".join([' %s="%s"' % (key, value) for key, value in attrs])
self.pieces.append("<%(tag)s%(strattrs)s>" % locals())
No, espere, todavía no puede aprender cosas sobre locals. Antes debe aprender sobre espacios de nombres. Es un material árido pero es importante, así que preste atención.
Python utiliza lo que llamamos espacios de nombres[7] para llevar un seguimiento de las variables. Un espacio de nombres es como un diccionario donde las claves son los nombres de las variables y los valores del diccionario son los de esas variables. En realidad, puede acceder a un espacio de nombres de Python como a un diccionario, como veremos en breve.
En cualquier momento en particular en un programa de Python se puede acceder a varios espacios de nombres. Cada función tiene su propio espacio de nombres, que llamamos espacio local, que contiene las variables que define la función, incluyendo sus argumentos y las variables definidas de forma local. Cada módulo tiene su propio espacio de nombres, denominado espacio global, que contiene las variables del módulo, incluyendo sus funciones, clases y otros módulos que haya importado, así como variables y constantes del módulo. Y hay un espacio de nombres incorporado, accesible desde cualquier módulo, que contiene funciones del lenguaje y excepciones.
Cuando una línea de código solicita el valor de una variable x, Python busca esa variable en todos los espacios de nombres disponibles, por orden:
Si Python no encuentra x en ninguno de estos espacios, se rendirá y lanzará una NameError con el mensaje There is no variable named 'x', que ya vio en su momento en Ejemplo 3.18, “Referencia a una variable sin asignar”, pero no podía aún apreciar todo el trabajo que Python estaba realizando antes de mostrarle ese error.
Python 2.2 introdujo un cambio sutil pero importante que afecta al
orden de búsqueda en los espacios de nombre: los ámbitos anidados. En las
versiones de Python anteriores a la 2.2, cuando hace referencia a una
variable dentro de una función
anidada o función
lambda, Python buscará esa variable en el espacio de la
función actual (anidada o lambda) y después en el espacio de
nombres del módulo. Python 2.2 buscará la variable en el espacio de
nombres de la función actual (anidada o lambda),
después en el espacio de su función madre, y luego en
el espacio del módulo. Python 2.1 puede funcionar de ambas maneras; por
omisión lo hace como Python 2.0, pero puede añadir la siguiente línea al
código al principio de su módulo para hacer que éste funcione como
Python 2.2:from __future__ import nested_scopes |
|
¿Ya está confundido? ¡No desespere! Esto es realmente bueno, lo prometo. Como muchas cosas en Python, a los espacios de nombre se puede acceder directamente durante la ejecución. ¿Cómo? Bien, al espacio local de nombres se puede acceder mediante la función incorporada locals, y el espacio global (del módulo) es accesible mediante la función globals.
>>> def foo(arg):... x = 1 ... print locals() ... >>> foo(7)
{'arg': 7, 'x': 1} >>> foo('bar')
{'arg': 'bar', 'x': 1}
Lo que hace locals con los espacios de nombres locales (función), lo hace globals para el espacio de nombres global (módulo). globals es más interesante, sin embargo, porque el espacio un módulo es más interesante.[8] El espacio de nombres del módulo no sólo incluye variables y constantes del módulo, también incluye todas las funciones y clases definidas en él. Además, incluye cualquier cosa que se haya importado dentro del módulo.
¿Recuerda la diferencia entre from módulo import e import módulo? Con import módulo se importa el módulo en sí, pero retiene su espacio de nombres, y esta es la razón por la que necesita usar el nombre del módulo para acceder a cualquiera de sus funciones o atributos: módulo.función. Pero con from módulo import, en realidad está importando funciones y atributos específicos de otro módulo al espacio de nombres del suyo propio, que es la razón por la que puede acceder a ellos directamente sin hacer referencia al módulo del que vinieron originalmente. Con la función globals puede ver esto en funcionamiento.
Mire el siguiente bloque de código al final de BaseHTMLProcessor.py:
if __name__ == "__main__": for k, v in globals().items():print k, "=", v
| Para que no se sienta intimidado, recuerde que ya ha visto todo esto antes. La función globals devuelve un diccionario y estamos iterando sobre él usando el método items y una asignación multivariable. La única cosa nueva es la función globals. |
Ahora ejecutar el script desde la línea de órdenes nos da esta salida (tenga en cuenta que la suya puede ser ligeramente diferente, dependiendo de la plataforma en que haya instalado Python):
c:\docbook\dip\py> python BaseHTMLProcessor.pySGMLParser = sgmllib.SGMLParserhtmlentitydefs = <module 'htmlentitydefs' from 'C:\Python23\lib\htmlentitydefs.py'>
BaseHTMLProcessor = __main__.BaseHTMLProcessor
__name__ = __main__
... se omite el resto de la salida por abreviar ...
| SGMLParser se importó desde sgmllib, usando from módulo import. Esto significa que lo importamos directamente en el espacio de nombres del módulo, y aquí está. | |
| En contraste con esto tenemos htmlentitydefs, que importamos usando import. Esto significa que es el módulo htmlentitydefs quien se encuentra en el espacio de nombres, pero la variable entitydefs definida en su interior, no. | |
| Este módulo sólo define una clase, BaseHTMLProcessor, y aquí la tenemos. Observe que el valor aquí es la propia clase, no una instancia específica de la clase. | |
| ¿Recuerda el truco if __name__? Cuando ejecuta un módulo (en lugar de importarlo desde otro), el atributo __name__ que incorpora contiene un valor especial, __main__. Dado que ejecutamos el módulo desde la línea de órdenes, __name__ es __main__, y por eso se ejecuta el pequeño código de prueba que imprime globals. |
| Puede obtener dinámicamente el valor de variables arbitrarias usando las funciones locals y globals, proporcionando el nombre de la variable en una cadena. Esto imita la funcionalidad de la función getattr, que le permite acceder a funciones arbitrarias de forma dinámica proporcionando el nombre de la función en una cadena. | |
Hay otra diferencia importante entre las funciones locals y globals que deberá aprender antes de que se pille los dedos con ella. Y se los pillará de todas maneras, pero al menos recordará haberlo aprendido.
def foo(arg): x = 1 print locals()locals()["x"] = 2
print "x=",x
z = 7 print "z=",z foo(3) globals()["z"] = 8
print "z=",z
![]()
<< Presentación de BaseHTMLProcessor.py |
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | |
Cadenas de formato basadas en diccionarios >> |