Domanda

L'accesso di Python alle variabili di ambiente non riflette accuratamente la visione del sistema operativo dell'ambiente di processi.

os.getenv e os.environ non funzionano come previsto in casi particolari.

Esiste un modo per ottenere correttamente l'ambiente del processo in esecuzione?


Per dimostrare cosa intendo, prendi i due programmi approssimativamente equivalenti (il primo in C, l'altro in 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)

Ora, se eseguiamo il programma C e ci colleghiamo al processo in esecuzione con gdb e cambiamo forzatamente l'ambiente sotto il cofano facendo qualcosa del genere:

(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"

allora il suddetto programma C inizierà a sputare "il mio valore" una volta ogni 5 secondi. Il suddetto programma Python, tuttavia, non lo farà.

C'è un modo per far funzionare il programma Python come il programma C in questo caso?

(Sì, mi rendo conto che si tratta di un'azione molto oscura e potenzialmente dannosa da eseguire in un processo in esecuzione)

Inoltre, attualmente sto usando Python 2.4, questo potrebbe essere stato corretto in una versione successiva di Python.

È stato utile?

Soluzione

Questa è un'ottima domanda.

Si scopre che il modulo os inizializza os.environ sul valore di posix .environ , impostato all'avvio dell'interprete. In altre parole, la libreria standard non sembra fornire l'accesso a getenv funzione.

Questo è un caso in cui probabilmente sarebbe sicuro usare ctypes su unix. Dal momento che chiameresti una funzione libc ultra standard.

Altri suggerimenti

Puoi usare ctypes per farlo semplicemente:

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

Un'altra possibilità è usare pdb, o qualche altro debugger python, e cambiare os.environ a livello di python, piuttosto che a livello C. Ecco una piccola ricetta che ho pubblicato per interrompere una corsa processo Python e fornire accesso a una console Python alla ricezione di un segnale. In alternativa, basta attaccare un pdb.set_trace () ad un certo punto del codice che si desidera interrompere. In entrambi i casi, esegui semplicemente l'istruzione " import os; os.environ [ 'SOME_VARIABLE'] 'my_value' = " e dovresti essere aggiornato per quanto riguarda python.

Non sono sicuro se questo aggiornerà anche l'ambiente C con setenv, quindi se hai moduli C che utilizzano direttamente getenv potresti dover fare un po 'di lavoro in più per mantenerlo sincronizzato.

Non credo che molti programmi MAI prevedano di modificare il proprio ambiente esternamente, quindi caricare una copia dell'ambiente passato all'avvio è equivalente. Ti sei semplicemente imbattuto in una scelta di implementazione.

Se vedi tutti i valori di set-at-startup e putenv / setenv all'interno del tuo programma funziona, non penso che ci sia nulla di cui preoccuparti. Esistono modi molto più chiari per trasmettere informazioni aggiornate all'esecuzione di eseguibili.

Guardando il codice sorgente di Python (2.4.5):

  • Modules / posixmodule.c ottiene l'ambiente in convertenviron () che viene eseguito all'avvio (vedi INITFUNC) e memorizza l'ambiente in un modulo specifico della piattaforma (nt, os2 o posix)

  • Lib / os.py guarda sys.builtin_module_names e importa tutti i simboli da posix, nt o os2

Quindi sì, viene deciso all'avvio. os.environ non sarà utile qui.

Se vuoi davvero farlo, l'approccio più ovvio che mi viene in mente è quello di creare il tuo modulo python basato su C personalizzato, con un getenv che invoca sempre la chiamata di sistema.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top