Pregunta

El acceso de Python a las variables de entorno no refleja con precisión la visión del entorno de procesos del sistema operativo.

os.getenv y os.environ no funcionan como se esperaba en casos particulares.

¿Hay alguna forma de obtener correctamente el entorno del proceso en ejecución?


Para demostrar lo que quiero decir, toma los dos programas aproximadamente equivalentes (el primero en C, el otro en python):

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[]){
    char *env;
    for(;;){
        env = getenv("SOME_VARIABLE");
        if(env)
            puts(env);
        sleep(5);
    }
}

import os
import time
while True:
    env = os.getenv("SOME_VARIABLE")
    if env is not None:
        print env
    time.sleep(5)

Ahora, si ejecutamos el programa C y adjuntamos al proceso en ejecución con gdb y cambiamos el entorno bajo la fuerza forzosamente haciendo algo como esto:

(gdb) print setenv("SOME_VARIABLE", "my value", 1)
[Switching to Thread -1208600896 (LWP 16163)]
$1 = 0
(gdb) print (char *)getenv("SOME_VARIABLE")
$2 = 0x8293126 "my value"

entonces el programa C ya mencionado comenzará a emitir " mi valor " una vez cada 5 segundos. Sin embargo, el programa python mencionado anteriormente no lo hará.

¿Hay alguna manera de hacer que el programa python funcione como el programa C en este caso?

(Sí, me doy cuenta de que esta es una acción muy oscura y potencialmente dañina para realizar en un proceso en ejecución)

Además, actualmente estoy usando python 2.4, esto puede haberse solucionado en una versión posterior de python.

¿Fue útil?

Solución

Esa es una muy buena pregunta.

Resulta que el módulo os inicializa os.environ al valor de posix .environ , que se establece en el inicio del intérprete. En otras palabras, la biblioteca estándar no parece proporcionar acceso a getenv función.

Ese es un caso en el que probablemente sería seguro utilizar ctypes en unix. Ya que llamarías a una función libc ultra estándar.

Otros consejos

Puede usar ctypes para hacer esto simplemente:

>>> from ctypes import CDLL, c_char_p
>>> getenv = CDLL("libc.so.6").getenv
>>> getenv.restype = c_char_p
>>> getenv("HOME")
'/home/glyph'

No creo que muchos programas NUNCA esperen que su entorno sea modificado externamente, por lo que cargar una copia del entorno pasado al inicio es equivalente. Simplemente te has topado con una opción de implementación.

Si está viendo todos los valores establecidos en el inicio y putenv / setenv desde su programa funciona, no creo que haya nada de qué preocuparse. Hay formas mucho más claras de pasar información actualizada a los ejecutables en ejecución.

Mirando el código fuente de Python (2.4.5):

  • Módulos / posixmodule.c obtiene el entorno en convertenviron (), que se ejecuta en el inicio (ver INITFUNC) y almacena el entorno en un módulo específico de la plataforma (nt, os2 o posix)

  • Lib / os.py examina sys.builtin_module_names e importa todos los símbolos de posix, nt u os2

Entonces sí, se decide al inicio. os.environ no va a ser útil aquí.

Si realmente desea hacer esto, entonces el enfoque más obvio que se le viene a la mente es crear su propio módulo de Python personalizado basado en C, con un getenv que siempre invoca la llamada al sistema.

scroll top