Переменные среды в Python в Linux

Доступ Python к переменным среды не точно отражает взгляд операционной системы на среду процессов.

os.getenv и os.environ не работают должным образом в определенных случаях.

Есть ли способ правильно получить среду запущенного процесса?


Чтобы продемонстрировать, что я имею в виду, возьмем две примерно эквивалентные программы (первая на C, другая на 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)

Теперь, если мы запустим программу на C, подключимся к запущенному процессу с помощью gdb и принудительно изменим внутреннюю среду, выполнив что-то вроде этого:

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

тогда вышеупомянутая программа на языке C начнет выдавать «мое значение» каждые 5 секунд. Однако вышеупомянутая программа на Python не работает.

Есть ли способ заставить программу Python работать как программа C в этом случае?

(Да, я понимаю, что это очень непонятное и потенциально опасное действие для выполняемого процесса)

Кроме того, в настоящее время я использую python 2.4, возможно, это было исправлено в более поздней версии python.

Как бы то ни было, это не является неожиданностью: ссылка на библиотеку для модуля os подчеркивает проблему.

bobince 25.10.2008 02:35
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
13
1
33 574
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Посмотрим на исходный код Python (2.4.5):

  • Modules / posixmodule.c получает среду в convertenviron (), которая запускается при запуске (см. INITFUNC), и сохраняет среду в модуле, зависящем от платформы (nt, os2 или posix).

  • Lib / os.py просматривает sys.builtin_module_names и импортирует все символы из posix, nt или os2.

Так что да, это решается при запуске. os.environ здесь не поможет.

Если вы действительно хотите это сделать, то наиболее очевидный подход, который приходит на ум, - это создать свой собственный модуль python на основе C с getenv, который всегда вызывает системный вызов.

Или я мог бы использовать модуль ctypes, но теперь это просто портит удовольствие, не так ли?

Sufian 25.10.2008 02:18
Ответ принят как подходящий

Это очень хороший вопрос.

Оказывается, модуль os инициализирует os.environ значением posix.environ, которое устанавливается при запуске интерпретатора. Другими словами, стандартная библиотека не предоставляет доступа к функции getenv.

В этом случае, вероятно, было бы безопасно использовать ctypes в unix. Поскольку вы вызываете сверхстандартную функцию libc.

Я не верю, что многие программы КОГДА-ЛИБО ожидают, что их среда будет изменена извне, поэтому загрузка копии переданной среды при запуске эквивалентна. Вы просто наткнулись на выбор реализации.

Если вы видите, что все значения, установленные при запуске, и putenv / setenv изнутри вашей программы работают, я не думаю, что есть о чем беспокоиться. Есть гораздо более чистые способы передать обновленную информацию работающим исполняемым файлам.

Другая возможность - использовать вместо этого pdb или какой-либо другой отладчик python и изменить os.environ на уровне python, а не на уровне C. Вот - небольшой рецепт, который я опубликовал, чтобы прервать запущенный процесс Python и предоставить доступ к консоли Python при получении сигнала. В качестве альтернативы, просто вставьте pdb.set_trace () в какой-то момент вашего кода, который вы хотите прервать. В любом случае просто запустите оператор «import os; os.environ['SOME_VARIABLE']='my_value'», и вы должны быть обновлены в отношении Python.

Я не уверен, что это также обновит среду C с помощью setenv, поэтому, если у вас есть модули C, использующие getenv напрямую, вам, возможно, придется проделать еще немного работы, чтобы синхронизировать это.

Вы можете использовать ctypes, чтобы сделать это довольно просто:

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

Другие вопросы по теме