Использование копирования.deepcopy на os.environ в python выглядит сломанным


Я, вероятно, просто пропустил какую-то часть документации о том, как работает ОС.environ или копия.deepcopy работает, но похоже, что копия.deepcopy не работает на ОС.окружающая среда. Но если я реконструирую ОС.environ в новый словарь, он прекрасно работает. Вот мой пример кода:

import copy
import os

tcsh_loc = '/bin/tcsh'
safe_dict = {}
for key in os.environ.keys():
    safe_dict[key] = os.environ[key]

safe_dict['SAFE_ENV'] = 'non-leaked-var'
os.spawnv(os.P_WAIT, tcsh_loc, [tcsh_loc, '-c', 'echo $SAFE_ENV'])
os.spawnve(os.P_WAIT, tcsh_loc, [tcsh_loc, '-c', 'echo $SAFE_ENV'], safe_dict)

unsafe_dict = copy.deepcopy(os.environ)
unsafe_dict['UNSAFE_ENV'] = 'leaked-var'
os.spawnv(os.P_WAIT, tcsh_loc, [tcsh_loc, '-c', 'echo $UNSAFE_ENV'])
os.spawnve(os.P_WAIT, tcsh_loc, [tcsh_loc, '-c', 'echo $UNSAFE_ENV'], unsafe_dict)

То, что я ожидаю получить, это:

SAFE_ENV: Undefined variable.
non-leaked-var
UNSAFE_ENV: Undefined variable.
leaked-var

Но то, что я получаю, это:

SAFE_ENV: Undefined variable.
non-leaked-var
leaked-var
leaked-var

, что подразумевает, что каким-то образом назначение unsafe_dict['UNSAFE_ENV'] = 'leaked-var' каким-то образом "просачивается" в ОС.environ, предположительно от os.environ не получает deepcopied как я и ожидал.

Я предполагаю, что это какое-то известное поведение, но оно кажется мне действительно странным и нежелательным, по крайней мере, с точки зрения использования таких вещей, как ОС.спавнев(). У меня есть неуклюжий обходной путь, но мне было бы интересно понять, что происходит, и есть ли более элегантное решение, чем цикл for...
2 3

2 ответа:

os.environ имеет тип os._Environ, а не список или словарь. Логично, что копия экземпляра os._Environ также изменит среду.

См os._Environ.__setitem__() функции. Он хранит значения в 2 местах , один раз используя putenv() и один, чтобы назначить ключ в словаре self._data.

def __setitem__(self, key, value):
    key = self.encodekey(key)
    value = self.encodevalue(value)
    self.putenv(key, value)
    self._data[key] = value

Вы можете восстановить его проще: просто используйте dict(os.environ).

Простой тест:

import os
a=os.environ
b=dict(os.environ)

print type(a), type(b)
# -> <type 'instance'> <type 'dict'>

print a['PWD'], b['PWD']
# -> /home/max /home/max

b['PWD']='/fooo'
print a['PWD'], b['PWD']
# -> /home/max /fooo