Как отличить и разделить `os.environ` на значения по умолчанию и дополнения

Можно ли разделить os.environ на переменные среды по умолчанию и переменные пользовательского дополнения?

Например, используя синтаксис наборов, представляющих key/ENV_VAR_NAME:

custom_addon_env_var_keys = set(os.environ.keys()) - set(os.environ.default.keys()) # is there this `os.environ.default` kinda thing?

Есть ли какой-то os.environ.default для получения чистых переменных среды после запуска программы (то есть исключения всех пользовательских ключей, которые я добавил с момента запуска программы)?

Я пытался просмотреть исходный код модуля os, environ инициализируется функцией _createenviron, но он был удален, как только был инициализирован environ, поэтому невозможно повторно инициализировать environ_2, выполнить работу и скопировать вся функция инициализации выглядит глупо.

Следующий код дает краткое описание ожидаемого поведения. Я использую это для переменных между файлами, поэтому сохранение исходной копии при запуске — это не то, что мне нужно:

import os

# I'm using this for cross file variables
# so it is impossible to save a original copy at start
ORIGINAL_ENV_COPY = os.environ.copy()

os.environ["MY_CUSTOM_ENV_KEY"] = "HelloWorld"

# the "ORIGINAL_ENV_COPY" should be a method of getting the original version of "os.environ"
custom_addon_env_var_keys = set(os.environ.keys()) - set(ORIGINAL_ENV_COPY.keys())

print(custom_addon_env_var_keys) # output: {"MY_CUSTOM_ENV_KEY"}

Редактировать

Прошу прощения, что не предоставил достаточно информации в посте:

У меня есть файл с именем environment.py, который будет инициализировать константы, и он будет упакован в двоичный исполняемый файл вместе с main.py, вот его часть:

import os

os.environ["TIMEZONE"] = "Asia/Taipei"

os.environ["PROJECT_NAME"] = "Project name"

os.environ["APP_USER_MODEL_ID"] = f"{os.environ['PROJECT_NAME']}.App.User.Model.Id"

os.environ["SERVER_URL"] = f"https://www.my.server.io/projects/{os.environ['PROJECT_NAME']}"
os.environ["STORAGE_URL"] = f"https://www.my.server.io/projects/{os.environ['PROJECT_NAME']}/Storage"
os.environ["MODULES_URL"] = f"https://www.my.server.io/projects/{os.environ['PROJECT_NAME']}/Modules"

os.environ["USER_AGENT"] = random.choice([
    "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36",
    "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36",
    "Mozilla/5.0 (Windows NT 10.0; WOW64) Gecko/20100101 Firefox/61.0",
    "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36",
    "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36",
    "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36",
    "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)",
    "Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.5; en-US; rv:1.9.2.15) Gecko/20110303 Firefox/3.6.15"
])

if getattr(sys, "frozen", False):
    sys.argv = [arg for arg in sys.argv if not arg.startswith("-")]
    os.environ["EXECUTABLE_ROOT"] = os.path.dirname(sys.executable)
else:
    os.environ["EXECUTABLE_ROOT"] = os.path.dirname(os.path.abspath(sys.modules["__main__"].__file__))

Зачем мне хранить переменные и константы в os.environ?

  1. Этот environment.py будет упакован в двоичный исполняемый файл вместе с main.py, и, следовательно, для всех остальных модулей они даже не знают, что существует даже файл с именем environment.py (поскольку теперь все, что осталось, это main.exe)
  2. Как видите, некоторые переменные, например. USER_AGENT, EXECUTABLE_ROOT занимает довольно много места, если не хранить, то будет много дублированных кодов.

Наконец, почему мне нужно настраивать добавление ключей env?

Поскольку я храню в нем переменные, при получении отчетов о сбоях мне нужна отладка, если проблема вызвана какой-либо из них.

Возьмем, к примеру, USER_AGENT: если один из них больше недоступен, я должен знать, какой из них выбран и вызвал ошибку, а затем удалить его из списка, вместо того, чтобы проверять их один за другим.

И есть много ключей переменных среды по умолчанию, и если я отправлю все в os.environ, это будет беспорядок, мне нужны только те переменные ключи, которые я добавил.

Ответ (спасибо @zondo)

Сохраните оригинал os.environ под os, используя setattr, и чтобы предотвратить повторный импорт, перезаписывающий исходное сохранение (упомянутое в комментарии от @wim), я добавил заявление if для его оценки.

import os

# if this is the first time running
# there won't be a "default_environ" attr
if not hasattr(os, "default_environ"):
    setattr(os, "default_environ", os.environ.copy())

# ... other variables

Что вы подразумеваете под «переменными файла»? Я не понимаю, почему ваш код в конце не работает.

Barmar 09.08.2024 21:06

Если вы сохраните копию среды перед импортом чего-либо еще, кажется, все будет в порядке.

Barmar 09.08.2024 21:07

Никаких «значений по умолчанию» нет, есть только значения, присутствующие при запуске, которые были помещены туда родителем, и значения, которые вы добавляете самостоятельно в ходе выполнения. Окружающая среда сама не отслеживает эти изменения. Вам придется сделать копию os.environ при запуске и самостоятельно отслеживать последующие изменения.

chepner 09.08.2024 21:07

В Linux исходное окружение находится в /proc/{pid}/environ. Вы могли бы разобрать это.

tdelaney 09.08.2024 21:18

Я не понимаю following code gives a brief-view of the expecting behavior в чем разница с ожидаемым поведением?

KamilCuk 09.08.2024 21:24

Что не так с вашим кодом, показанным в вопросе? Поместите это ORIGINAL_ENV_COPY в файл usercustomize или sitecustomize, и все готово.

wim 09.08.2024 21:34

Исключите все пользовательские ключи, которые я добавил с момента запуска программы. Сохраните копию среды при первом запуске программы. В чем сложность?

John Gordon 09.08.2024 21:54

Часть «переменные файлов», например: имя проекта, корневой путь исполняемого файла. Я храню их все в «os.environ», поэтому в других модулях, кроме «main.py», я могу просто «импортировать ОС» и получить к ним доступ, вместо того, чтобы писать строки кода, взять «исполняемый корень» path» в качестве примера, мне нужно определить, является ли программа замороженным двоичным файлом или все еще скриптом Python, и для этого потребуется if-else... до 4 строк кода, но сохранение его в «os.environ ", я могу легко получить перекрестный доступ к этой переменной.

Head Cracked 09.08.2024 23:47

Приношу извинения, было бы точнее, если бы я сказал «межфайловые константы», будет «environment.py», и он будет импортирован только через «main.py», так как я заморозлю «main.py». в двоичный исполняемый файл, но оставьте остальную часть ".py", чтобы я мог редактировать логику, думать о "main.py" как о средстве запуска, и так, поскольку "environment.py" упакован вместе с "main.py" в двоичный формат, все остальные модули больше не смогут его импортировать, поэтому мне нужно инициализировать «межфайловые константы» при запуске, а затем получить к ним доступ через «os.environ».

Head Cracked 09.08.2024 23:56

Почему для этого требуется отличать исходную среду от дополнений?

Barmar 10.08.2024 00:14

В последней части моего редактирования, публикуя отчет о сбое, я должен проверить, не вызвана ли ошибка одной из переменных, например, устаревшей API_KEY или опцией USER_AGENT, которая больше не поддерживается. Публикация всего os.environ, очевидно, дает множество переменных среды по умолчанию, которые мне не нужно проверять.

Head Cracked 10.08.2024 00:19
Почему в 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 может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
11
51
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Можно ли разделить os.environ на переменные среды по умолчанию и пользовательские переменные дополнения?

Нет.

Есть ли какой-то os.environ.default для получения чистых переменных среды? после запуска программы?

В Linux есть /proc/pid/environ. Вы можете получить исходную среду с чем-то следующим:

original = dict(tuple(x.split(" = ", 1)) for x in open(f"/proc/{os.getpid()}/environ").read().split("\x00") if x)
Ответ принят как подходящий

Модули Python импортируются только один раз в один и тот же экземпляр программы. Неважно, сколько разных файлов вы что-то импортируете, первый раз импортируется — это единственный раз, когда он запускается, а все остальное использует его повторно. Есть два способа воспользоваться этим.

Во-первых, более простой способ: выбрать файл и установить все, что вы хотите. Например, startup.py:

import os

environ = os.environ.copy()
# other settings you want

И тогда все ваши остальные файлы смогут использовать:

import os
import startup

new_vars = set(os.environ) - set(startup.environ)

Второй способ на самом деле больше похож на хак, и он мне не нравится, но если бы вы занимались только окружением, было бы проще. И это только это:

import os

os.startup_environ = os.environ.copy()

Опять же, поскольку импорт операционной системы будет одинаковым для всех, эта переменная будет доступна везде.

Модули Python импортируются только один раз в пределах одного экземпляра программы, что не совсем точно. Они кэшируются в sys.modules. Есть несколько способов пропустить кеш (__name__ == "__main__" или нет, динамический импорт с помощью __import__ или importlib.import_module, аннулирование кеша с помощью sys.modules.pop(...), многопроцессорная обработка, при которой каждый рабочий может импортировать модуль независимо...)

wim 09.08.2024 22:41

Я отредактировал сообщение, чтобы дать более подробную информацию, поскольку для других файлов environment.py не будет, первый метод не сработает, но третий может решить проблему, спасибо.

Head Cracked 10.08.2024 00:17

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