Python – Acceso a las variables de entorno

Objetivo: mostrar cómo acceder con Python a las variables de entorno del sistema.

En ocasiones puede ser conveniente que nuestros programas o scripts conozcan cierta información sobre el entorno en el que se están ejecutando. Las variables de entorno constituyen un medio ampliamente utilizado para facilitar este tipo de comunicación.

Comencemos agregando algunas variables nuevas a nuestro entorno antes de ejecutar Python:

javier@menta ~ $ export BANDA="Jethro Tull" COMIDA="gazpacho"

Vamos a utilizar el intérprete interactivo de Python para ejecutar código un tanto manipulador y “pelota”, como si se tratase de un falso amigo que finge tus aficiones sólo para obtener algo de ti.

javier@menta ~ $ python3
Python 3.4.0 (default, Apr 11 2014, 13:05:11) 
[GCC 4.8.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 

Python dispone de un módulo que facilita el acceso a funciones del sistema operativo construyendo una abstracción independiente de la plataforma, favoreciendo así la portabilidad del código. Aunque no puede decirse que esto se consiga en el 100% de los casos, debemos admitir que los resultados son impresionantes. El módulo en cuestión es os, de modo que nuestra primera tarea consiste en traerlo a la palestra:

>>> import os

El hecho simple de importar os hace que tengamos inmediatamente a nuestra disposición un diccionario, os.environ, con una copia de todas las variables de entorno en forma de parejas clave:valor.

Por ejemplo, supongamos que queremos consultar cuál es nuestro directorio de usuario (variable HOME).:

>>> os.environ["HOME"]
'/home/javier'

Naturalmente, también tenemos a nuestra disposición las dos variables que creamos al comienzo:

>>> print("No hay nada mejor en la vida que escuchar un disco
 de {} mientras se saborea un buen {}, 
¿no crees?".format(os.environ["BANDA"], os.environ["COMIDA"]))

No hay nada mejor en la vida que escuchar un disco de Jethro Tull
 mientras se saborea un buen gazpacho, ¿no crees?
>>>

¿Cómo es posible, si son mi banda y comida favoritas!

En las raras ocasiones en las que tu aplicación quiera modificar el entorno, puede ser tentador (y recomendable) atacar directamente al diccionario. Por ejemplo:

>>>os.environ["BANDA"] = "Deep Purple"

Técnicamente hablando, este tipo de actuación sólo estará disponible en aquellas plataformas que permitan llamadas a la función putenv() (que es ejecutada automáticamente cuando se modifica os.environ). Naturalmente, estas alteraciones sólo estarán disponibles para el proceso actual y subprocesos derivados. No esperes que sobrevivan una vez haya finalizado tu aplicación Python.

Javier Montero Gabarró


Python – Acceso a las variables de entorno


El texto de este artículo se encuentra sometido a una licencia Creative Commons del tipo CC-BY-NC-ND (reconocimiento, no comercial, sin obra derivada, 3.0 unported)


El Club del Autodidacta


Consulta el índice completo de artículos relacionados con Python.

Python: Vida y muerte de una variable

Objetivo: entender el concepto de ámbito de una variable y la clasificación de estas en globales y locales.

En un principio el mundo era sencillo y nuestros programas simples:

# Ejemplo 1

a = 1
b = 2

print(a)
print(b)

>>> 
1
2

Nuestras variables nacían, correteaban a sus anchas por el programa y cambiaban de valor según el guión establecido.

Debemos decir que, en Python, al contrario de lo que sucede en otros lenguajes, las variables no se declaran. Se crean justo en el momento en el que reciben por asignación un valor por primera vez y, a partir de ese momento, ya pueden formar parte de una expresión. Se produce un error si una variable es utilizada antes de que realice esa asignación inicial.

Hay que matizar, además, que cuando empleamos el término variable estamos refiriéndonos en realidad a su nombre. En Python es importante diferenciar el nombre de una variable del objeto real al que referencia. Sabemos que una simple asignación, como a = 1, se ocupa de crear el objeto 1, si no existe ya, y de etiquetarlo bajo el nombre a. Es más, por cuestiones de economía, un mismo objeto puede estar etiquetado con varios nombres de variable, como muestra el ejemplo 2:

Ejemplo 2

>>> a = 1
>>> b = 1
>>> a is b
True

Las variables a y b referencian al mismo objeto. Si ahora cualquiera de ellas cambiara con una nueva asignación, este vínculo común, naturalmente, desaparecería y cada nombre etiquetaria a su respectivo objeto valor.

En este escenario de plácida convivencia introdujimos un nuevo nivel de complejidad y aparecieron las funciones, como cajas negras dispuestas a facilitarnos la reutilización del código.

# Ejemplo 3

def cajanegra():
    c = 3
    print(c)

a = 1
b = 2

print(a)
print(b)
cajanegra()

>>> 
1
2
3

Y desde ese momento empezó la jerarquización. Como sucede en nuestro mundo, en el que lo fácil o difícil que será la vida depende bastante del lugar de nacimiento, lo mismo ocurre con los nombres de variables. A las variables que residen fuera de toda función, como a y b en el ejemplo, se las demomina globales, mientras aquellas que son creadas en las funciones reciben el nombre de locales.

Las variables locales, al contrario que las globales, tienen una vida efímera. Solo existen durante el momento en el que es llamada la función. En el momento en el que esta concluye, desaparecen, pasando por el programa sin pena ni gloria.

Además, solo son visibles dentro de la función; para el resto del código son completamente inexistentes. En el ejemplo anterior, tratar de usar la variable c desde el cuerpo del programa principal ocasionaría un error.

La zona del programa en la que una variable puede ser utilizada es lo que se conoce como su ámbito. Decimos que el ámbito de una variable local está limitado al código de la función en la que está definida.

Para ilustrar este concepto con claridad, vamos a construir un escenario en el que supuestamente hay un conflicto de nombres entre una variable global y otra local:

# Ejemplo 4

def cajanegra():
    c = 3
    print('La variable c dentro de la función tiene por valor', c)

a = 1
b = 2
c = 5

print(a)
print(b)
cajanegra()
print('La variable c fuera de la función tiene por valor', c)

>>> 
1
2
La variable c dentro de la función tiene por valor 3
La variable c fuera de la función tiene por valor 5

Observa que no existe tal conflicto. No tiene nada que ver la variable c de dentro de la función a la variable c de fuera, a pesar de tener el mismo nombre. Residen en espacios de nombres diferentes. Pese al hecho de haber asignado el valor 3 a la variable dentro de la función, su valor fuera de ella no se ha visto afectado en absoluto.

Las variables locales no son solo las que están dentro del cuerpo de una función. También lo son los argumentos formales empleados en su declaración.

En el ejemplo 5, las variables x, y y c son todas locales:

# Ejemplo 5

def cajanegra(x, y):
    c = x + y
    print(c)

a = 1
b = 2
cajanegra(a, b)

>>> 
3

En el momento en el la función es invocada, x e y reciben su asignación; en este caso, el valor de las variables a y b, respectivamente.

Las variables globales tienen la particularidad de que también son visibles dentro de la función:

# Ejemplo 6

def cajanegra():
    c = 3
    print(a)
    print(b)
    print(c)

a = 1
b = 2
cajanegra()

>>> 
1
2
3

Sin embargo, todo intento de modificar una variable global desde dentro de una función mediante una nueva asignación fracasa, como podemos comprobar en el ejemplo 7:

# Ejemplo 7

def cajanegra():
    c = 3
    print(a)
    b = 5
    print('La variable b dentro de la función vale', b)
    print(c)

a = 1
b = 2
cajanegra()
print('La variable b fuera de la función sigue valiendo', b)

>>> 
1
La variable b dentro de la función vale 5
3
La variable b fuera de la función sigue valiendo 2

Lo importante a comprender es que, desde el preciso momento en el que una variable recibe una asignación dentro de una función, pasa a ser calificada como local. Cuando eso ocurre, la variable tiene una visibilidad limitada al cuerpo de la función y deja de ser considerada como global si ya existía el nombre en el ámbito exterior. Por eso, en el ejemplo, la variable a es global, mientras que b y c son locales.

Dentro de una función, la misma variable no puede ser en unos momentos global y en otros local. Si hay una asignación, aunque sea posterior a su uso como variable global, la variable será considerada local y se producirá un error:

# Ejemplo 8

def cajanegra():
    c = 3
    print(b)
    b = 5

a = 1
b = 2
cajanegra()

>>> 
Traceback (most recent call last):
  File "C:\Users\Javier\Dropbox\pythonprad\pruebas\probando.py", line 45, in <module>
    cajanegra()
  File "C:\Users\Javier\Dropbox\pythonprad\pruebas\probando.py", line 40, in cajanegra
    print(b)
UnboundLocalError: local variable 'b' referenced before assignment

El mensaje es concluyente: la variable b ha sido referenciada antes de haber recibido una asignación, algo prohibido en Python. Si no hubiese existido la asignación en la tercera línea del cuerpo de cajanegra(), b hubiese sido considerada una variable global y el codigo sería válido. Sin embargo, la asignación hace que b se trate como local, invalidando su rol global.

En numerosas ocasiones puede resultar conveniente no solo poder acceder a una variable global desde dentro de una función, sino poder cambiar su valor mediante una nueva asignación. Para lograr esto, hay que calificar la variable externa dentro de la función empleando la palabra global.

# Ejemplo 9

def cajanegra():
    c = 3
    global b
    b = 5
    print('Dentro de la función b vale', b)

a = 1
b = 2
cajanegra()
print('Fuera de la función b también vale', b)

>>> 
Dentro de la función b vale 5
Fuera de la función b también vale 5

Al calificar b como global dentro de la función estamos indicando que las asignaciones posteriores de esa variable se realizarán en un ámbito global en vez de local, modificando así el valor externo.

Hay que usar las variables globales con precaución. Permitir a las funciones que modifiquen nuestras variables externas es una práctica que puede dificultar la localización de errores cuando las cosas no funcionan como debieran. Sin embargo, son muy útiles para almacenar información de estado que luego podrá recuperarse al invocar nuevamente la función u otra diferente. En el ejemplo siguiente, utilizamos la variable global suma para retener el efecto de cada invocación a la función:

# Ejemplo 10

def sumar5():
    global suma
    suma = suma + 5
    print('La nueva suma es', suma)

suma = 0
sumar5()
sumar5()
sumar5()

>>> 
La nueva suma es 5
La nueva suma es 10
La nueva suma es 15

Cada invocación a sumar5() agrega cinco al valor de suma. La variable suma ha sido declarada como global dentro de la función para poder actualizar el valor externo, que será utilizado nuevamente al volver a llamar a la función.

Existe otro calificativo, además de global, con el que podemos etiquetar las variables dentro de una función. En el siguiente artículo lo presentaremos en sociedad.

Javier Montero Gabarró


Python: Vida y muerte de una variable


El texto de este artículo se encuentra sometido a una licencia Creative Commons del tipo CC-BY-NC-ND (reconocimiento, no comercial, sin obra derivada, 3.0 unported)


El Club del Autodidacta


Consulta el índice completo de artículos relacionados con Python.