Можно ли разделить 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
?environment.py
будет упакован в двоичный исполняемый файл вместе с main.py
, и, следовательно, для всех остальных модулей они даже не знают, что существует даже файл с именем environment.py
(поскольку теперь все, что осталось, это main.exe
)USER_AGENT
, EXECUTABLE_ROOT
занимает довольно много места, если не хранить, то будет много дублированных кодов.Поскольку я храню в нем переменные, при получении отчетов о сбоях мне нужна отладка, если проблема вызвана какой-либо из них.
Возьмем, к примеру, USER_AGENT
: если один из них больше недоступен, я должен знать, какой из них выбран и вызвал ошибку, а затем удалить его из списка, вместо того, чтобы проверять их один за другим.
И есть много ключей переменных среды по умолчанию, и если я отправлю все в os.environ
, это будет беспорядок, мне нужны только те переменные ключи, которые я добавил.
Сохраните оригинал 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
Если вы сохраните копию среды перед импортом чего-либо еще, кажется, все будет в порядке.
Никаких «значений по умолчанию» нет, есть только значения, присутствующие при запуске, которые были помещены туда родителем, и значения, которые вы добавляете самостоятельно в ходе выполнения. Окружающая среда сама не отслеживает эти изменения. Вам придется сделать копию os.environ
при запуске и самостоятельно отслеживать последующие изменения.
В Linux исходное окружение находится в /proc/{pid}/environ
. Вы могли бы разобрать это.
Я не понимаю following code gives a brief-view of the expecting behavior
в чем разница с ожидаемым поведением?
Что не так с вашим кодом, показанным в вопросе? Поместите это ORIGINAL_ENV_COPY
в файл usercustomize или sitecustomize, и все готово.
Исключите все пользовательские ключи, которые я добавил с момента запуска программы. Сохраните копию среды при первом запуске программы. В чем сложность?
Часть «переменные файлов», например: имя проекта, корневой путь исполняемого файла. Я храню их все в «os.environ», поэтому в других модулях, кроме «main.py», я могу просто «импортировать ОС» и получить к ним доступ, вместо того, чтобы писать строки кода, взять «исполняемый корень» path» в качестве примера, мне нужно определить, является ли программа замороженным двоичным файлом или все еще скриптом Python, и для этого потребуется if-else... до 4 строк кода, но сохранение его в «os.environ ", я могу легко получить перекрестный доступ к этой переменной.
Приношу извинения, было бы точнее, если бы я сказал «межфайловые константы», будет «environment.py», и он будет импортирован только через «main.py», так как я заморозлю «main.py». в двоичный исполняемый файл, но оставьте остальную часть ".py", чтобы я мог редактировать логику, думать о "main.py" как о средстве запуска, и так, поскольку "environment.py" упакован вместе с "main.py" в двоичный формат, все остальные модули больше не смогут его импортировать, поэтому мне нужно инициализировать «межфайловые константы» при запуске, а затем получить к ним доступ через «os.environ».
Почему для этого требуется отличать исходную среду от дополнений?
В последней части моего редактирования, публикуя отчет о сбое, я должен проверить, не вызвана ли ошибка одной из переменных, например, устаревшей API_KEY
или опцией USER_AGENT
, которая больше не поддерживается. Публикация всего os.environ
, очевидно, дает множество переменных среды по умолчанию, которые мне не нужно проверять.
Можно ли разделить 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(...)
, многопроцессорная обработка, при которой каждый рабочий может импортировать модуль независимо...)
Я отредактировал сообщение, чтобы дать более подробную информацию, поскольку для других файлов environment.py
не будет, первый метод не сработает, но третий может решить проблему, спасибо.
Что вы подразумеваете под «переменными файла»? Я не понимаю, почему ваш код в конце не работает.