Pergunta

Acesso do Python a variáveis ??de ambiente não reflete com precisão a visão do sistema operacional do ambiente de processos.

os.getenv e os.environ não funcionam como esperado em casos particulares.

Existe uma maneira de obter adequadamente o ambiente em execução processo?


Para demonstrar o que quero dizer, levar os dois programas mais ou menos equivalentes (o primeiro em C, o outro em 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)

Agora, se executar o programa C e anexar ao processo a correr com gdb e forçosamente mudar o ambiente sob o capô, fazendo algo parecido com isto:

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

então o programa C acima mencionado vai começar a vomitar "o meu valor", uma vez a cada 5 segundos. O programa python acima mencionado, no entanto, não vai.

Existe uma maneira de obter o programa python para a função como o programa C neste caso?

(Sim, eu percebo isso é muito obscuro e potencialmente prejudiciais ação a ser executada em um processo em execução)

Além disso, estou usando atualmente python 2.4, este pode ter sido corrigido em uma versão posterior do python.

Foi útil?

Solução

Essa é uma pergunta muito boa.

Acontece que os inicializa módulo os os.environ ao valor do posix .environ, que é definido em intérprete arranque. Em outras palavras, a biblioteca padrão não aparecer para fornecer acesso à getenv função.

Isso é um caso em que provavelmente seria seguro usar ctypes no Unix. Desde que você seria chamar uma função ultra-padrão libc.

Outras dicas

Você pode usar ctypes fazer isso muito simplesmente:

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

Outra possibilidade é usar APO, ou algum outro depurador python em vez disso, e mudança os.environ no nível python, ao invés do nível C. Aqui está uma receita pequena eu postei para interromper a execução processo de python e fornecer acesso a um console python ao receber um sinal. Alternativamente, se ater apenas um pdb.set_trace () em algum momento de seu código que você deseja interromper. Em ambos os casos, basta executar a declaração "import os; os.environ['SOME_VARIABLE']='my_value'" e você deve ser atualizado, tanto quanto python está em causa.

Eu não tenho certeza se isso também vai atualizar o ambiente C com setenv, por isso, se você tem módulos C usando getenv diretamente você pode ter que fazer mais algum trabalho para manter isso em sincronia.

Eu não acredito que muitos programas sempre esperar para ter seu ambiente modificado externamente, de modo a carregar uma cópia do ambiente passado na inicialização é equivalente. Você simplesmente tropeçou em uma escolha de implementação.

Se você está vendo todos os valores set-em-inicialização e putenv / setenv dentro de suas obras do programa, eu não acho que haja algo para se preocupar. Existem formas mais limpas longe para passar informações atualizadas para execução de executáveis.

Olhando para o código-fonte Python (2.4.5):

  • Módulos / posixmodule.c recebe o environ em convertenviron (), que é executado na inicialização (ver INITFUNC) e armazena o ambiente em um módulo específico da plataforma (nt, OS2 ou POSIX)

  • lib / aparência os.py em sys.builtin_module_names e as importações todos os símbolos de ambos posix, NT ou OS2

Então, sim, ele é decidido na inicialização. os.environ não vai ser útil aqui.

Se você realmente quer fazer isso, então a abordagem mais óbvia que vem à mente é a de criar o seu próprio módulo python baseada em C personalizado, com um getenv que sempre invoca a chamada de sistema.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top