Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/285.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 来自dict.fromkeys的不必要行为_Python - Fatal编程技术网

Python 来自dict.fromkeys的不必要行为

Python 来自dict.fromkeys的不必要行为,python,Python,我想使用dict.fromkeys初始化集合字典(在Python 2.6中),但结果结构的行为异常。更具体地说: >>>> x = {}.fromkeys(range(10), set([])) >>>> x {0: set([]), 1: set([]), 2: set([]), 3: set([]), 4: set([]), 5: set([]), 6: set([]), 7: set([]), 8: set([]), 9: set([])}

我想使用
dict.fromkeys
初始化集合字典(在Python 2.6中),但结果结构的行为异常。更具体地说:

>>>> x = {}.fromkeys(range(10), set([]))
>>>> x
{0: set([]), 1: set([]), 2: set([]), 3: set([]), 4: set([]), 5: set([]), 6: set([]), 7: set([]), 8: set([]), 9: set([])}
>>>> x[5].add(3)
>>>> x
{0: set([3]), 1: set([3]), 2: set([3]), 3: set([3]), 4: set([3]), 5: set([3]), 6: set([3]), 7: set([3]), 8: set([3]), 9: set([3])}

我显然不想在所有集合中添加3,只想在对应于
x[5]
的集合中添加3。当然,我可以通过初始化
x
而不使用
fromkeys
,来避免这个问题,但我想了解我在这里遗漏了什么。

dict.fromkeys的第二个参数只是一个值。您已经创建了一个字典,该字典的设置与每个键的值相同。想必您了解这种工作方式:

>>> a = set()
>>> b = a
>>> b.add(1)
>>> b
set([1])
>>> a
set([1])
你在那里看到了同样的行为;在您的情况下,
x[0]
x[1]
x[2]
(等)都是访问完全相同的
集合
对象的不同方式

对于字符串表示形式包含内存地址的对象,这更容易看到,您可以看到它们是相同的:

>>> dict.fromkeys(range(2), object())
{0: <object object at 0x1001da080>,
 1: <object object at 0x1001da080>}
dict.fromkeys(范围(2),对象()) {0: , 1: }
它以这种方式工作的原因是
set([])
创建了一个对象(set对象)。Fromkeys然后使用该特定对象创建其所有字典条目。考虑:

>>> x
{0: set([]), 1: set([]), 2: set([]), 3: set([]), 4: set([]), 5: set([]), 
6: set([]), 7: set([]), 8: set([]), 9: set([])}
>>> x[0] is x[1]
True
所有的布景都一样

因为来自
dictobject.c

while (_PyDict_Next(seq, &pos, &key, &oldvalue, &hash))
{
            Py_INCREF(key);
            Py_INCREF(value);
            if (insertdict(mp, key, hash, value))
                return NULL;
}

值是您的“set([]),它只计算一次,然后它们的结果对象引用计数增加并添加到字典中,它不会每次添加到dict中时都计算它。

您可以使用生成器表达式执行此操作:


#To do what you want:

import copy
s = set([])
x = {}
for n in range(0,5):
  x[n] = copy.deepcopy(s)
x[2].add(3)
print x

#Printing
#{0: set([]), 1: set([]), 2: set([3]), 3: set([]), 4: set([])}
x = dict( (i,set()) for i in range(10) )
在Python 3中,您可以使用字典理解:

x = { i : set() for i in range(10) }

在这两种情况下,表达式
set()
对每个元素求值,而不是求值一次并复制到每个元素

它们都是同一套。集合、列表、字典和任何其他对象都是引用类型,当您将它们指定给另一个变量时,只复制引用,而不复制实际对象
fromkeys
必须使用赋值将集合与每个键关联,但正如您所看到的,这不会复制集合。除了以不同的方式创建字典外,我不知道如何解决这个问题。不需要
deepcopy
x[n]=set()
为每个值创建一个新的集合。您应该真正比较标识:
x[0]是x[1]
+1,用于提供解决方案,即使在接受的答案很好地解释了它之后。如果我不想初始化集合,则x={I:[]对于范围(10)中的I会导致SyntaxError,而dict((I,[])对于范围(10)中的I)没有。值得指出的是,词典理解在Python2.7及更高版本中是有效的。