为什么这个分配的对象与原始对象共享相同的内存空间?

时间:2014-09-04 16:15:06

标签: python memory itertools

在python中,我在使用itertools groupby模块时遇到了这种奇怪的现象。

在python中,变量赋值意味着为新变量分配自己的内存而不是指向原始内存的指针(根据我的理解,如果这不正确请告诉我):

y = 7
x = y    
y = 9

x will still be 7

然而,当我使用groupby模块时,我正在使用此模块将具有相同密钥的项目分组到一个组中。我想要两个小组,因为重复原始小组是没用的,因为内存已经被修改。例如:

for key, group in groupby(rows, lambda x: x[0]):

    data = [thing[1] for thing in group] #accesses 1st attribute of element
    data2 = [thing[2] for thing in group] # would yield [] as group is empty

所以我尝试了这个:

for key, group in groupby(rows, lambda x: x[0]):
    #create a copy of group to reiterate over
    toup = group

    print toup #<itertools._grouper object at 0x1039a8850>
    print group #<itertools._grouper object at 0x1039a8850>

    data = [thing[1] for thing in group] #accesses 1st attribute of element
    data2 = [thing[2] for thing in toup]

data2应该访问第二项但产生[],因为它们共享相同的内存

我的问题是为什么会发生这种情况?不应该将组分配给toup意味着toup会在不同的十六进制地址位置拥有一组内存吗?

我还能做些什么来规避这个问题,所以我不必编写两个groupby迭代?

2 个答案:

答案 0 :(得分:3)

你说:

  

在python中,变量赋值意味着分配新变量   拥有内存而不是指向原始内存的指针(来自我的   了解这是不正确请告诉我):

这是不正确的。 Python名称可以具有(在时间上)类似于C变量的方面,并且还可以具有(有时)类似于C指针的方面。试着说他们就像一个或另一个只是令人困惑。唐&#39;吨。将它们视为Python的独特和惯用语。

Python&#39;变量&#39;应该更多地被视为名称。多个可能引用相同的内存位置,即使您不打算这样做。

示例:

>>> y=7
>>> x=7
>>> x is y
True
>>> id(x)
140316099265400
>>> id(y)
140316099265400

并且(由于interning,以下可能为真。请参阅PEP 237关于短整数的实习,但这是一个实现细节:

>>> x=9
>>> y=5+4
>>> x is y
True

Python is运算符通过比较它们的内存地址返回True,如果它们是相同的对象。 id函数返回该地址。

考虑作为最后一个例子:

>>> li1=[1,2,3]
>>> li2=[1,2,3]
>>> li1==li2
True
>>> li1 is li2
False

即使li1 == li2,它们也必须是单独的列表,否则两者都会改变,如下例所示:

>>> li1=[1,2,3]
>>> li2=li1
>>> li1.append(4)
>>> li2
[1, 2, 3, 4]
>>> li1==li2
True
>>> li1 is li2
True

(请务必了解所有Python程序员迟早会做出的另一个classic mistake。这是由多个引用单个可变对象引起的,然后期望一个引用像单个对象一样。)

正如jonrsharpe在评论中指出的那样,请阅读Ned Batchelders优秀Facts and myths about Python Names and ValuesHow to Think Like a Pythonista以获取更详细的概述。

答案 1 :(得分:0)

  

在python中,变量赋值意味着为新变量分配自己的内存而不是指向原始内存的指针

Python具有可变性(例如列表,迭代器,几乎所有内容)和不可变对象(例如整数和字符串)。在任何一种情况下,赋值都不会复制对象。对于不可变对象,对它们的所有操作都会产生一个新实例,因此您不会遇到像修改类型一样“修改”整数或字符串的问题。

  

我的问题是为什么会发生这种情况?不应该将组分配给toup意味着toup会在不同的十六进制地址位置有一个组内存的副本吗?

两个变量都将指向同一个对象。当你迭代一个并耗尽迭代器时,迭代第二个变量会给你一个空序列。