在python中的os.environ上使用copy.deepcopy似乎是错误的

在python中的os.environ上使用copy.deepcopy似乎是错误的,python,environment-variables,deep-copy,Python,Environment Variables,Deep Copy,我可能只是错过了一些关于os.environ或copy.deepcopy如何工作的文档,但似乎copy.deepcopy在os.environ上不起作用。但是,如果我将os.environ重新构建成一本新词典,它就可以正常工作。下面是我的示例代码: import copy import os tcsh_loc = '/bin/tcsh' safe_dict = {} for key in os.environ.keys(): safe_dict[key] = os.environ[ke

我可能只是错过了一些关于os.environ或copy.deepcopy如何工作的文档,但似乎copy.deepcopy在os.environ上不起作用。但是,如果我将os.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
但我得到的是:

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'
赋值以某种方式“泄漏”到os.environ,可能是由于os.environ没有像我预期的那样得到深度复制


我假设这是某种已知的行为,但对我来说这似乎真的很奇怪,至少在使用os.spawnev()之类的东西时是不受欢迎的。我有一个笨拙的解决方法,但我很想了解发生了什么,以及是否有比for循环更优雅的解决方案…

os.environ
属于
os.\u environ
,而不是列表或字典。合乎逻辑的是,
os.\u Environ
实例的副本也会修改环境

请参阅
os.\u Environ.\uuuuuu setitem\uuuuuu()
函数。一旦使用
putenv()
并在
self.\u 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
导入操作系统
a=操作系统环境
b=dict(操作系统环境)
打印类型(a),打印类型(b)
# ->  
打印a['PWD',b['PWD']
#->/home/max/home/max
b['PWD']='/fooo'
打印a['PWD',b['PWD']
#->/home/max/fooo

这在Python2.6上,在3.2.2中也是一样的,这并不奇怪。你看过操作系统环境的类型吗?它不是一个列表什么的,它有自己的方法等等,所以很明显它会修改环境!我同意这是它自己的对象,但这不应该禁止复制制作对象的副本。另外,os.spawn*e()的文档显示,使用它就像是一个命令:
os.spawnvpe(os.P_WAIT,'cp',L,os.environ)
从它不禁止复制它,但是
os的实例通常会修改环境变量
copy.deepcopy
创建对象的真实副本,而不是其他类型(如
dict
list
)中的假副本。是的,
os.environ
的行为几乎与
dict
类似,但事实并非如此。它在修改shell环境时也会修改它。因此,os.\U环境对象是实际环境变量的前端,它的setter函数调用putenv(),这会影响“实际”环境,并且它在self.\U data()中还有一个缓存副本,它是另一个副本。这有点奇怪。为什么要保留两个env副本?您仍然要创建一个
os的实例副本。_Environ
os。_Environ
仍然修改环境,并且是
self。_data
被复制到一个新字典中,但是它仍然包含在
os的一个实例中。_Environ
os.Environ.copy
是这个的内置版本,我建议改为这样做。