Python: 两个对象似乎引用了同一个变量,即使它们之间没有任何明确的联系
Python: Two objects seem to be referencing the same variable even though I do not have any explicit connection between them
我正在尝试根据我拥有的掩码更改一个八位位组。
假设我有 IP:194.216.35.54 和掩码 - 27,我需要更改第 4 个八位字节(从 0 开始计算时为 3)。我正在尝试更改 work_octets
变量中的值。但是,不知何故,network_octets
中的值也在发生变化。为什么会这样? network_octets
和 work_octets
都是两个不同的列表,它们是通过遍历值和切片 ip_dict_list
创建的。 network_octets
是怎么改变的 - 任何人都可以帮助我理解我在这里做错了什么吗?
注意:我可以深度复制并更改此行为,但我需要知道我在这里做错了什么。非常感谢这方面的任何解释。
代码:
octet = 3
ip_dict_list = dc(self.ip_dict_list) # looks like this: [{1: {128: 0, 64: 0, 2: 0, 4: 0, 1: 0, 16: 0, 32: 0, 8: 0}}, {2: {128: 0, 64: 0, 2: 0, 4: 0, 1: 0, 16: 0, 32: 0, 8: 0}}, {3: {128: 0, 64: 0, 2: 0, 4: 0, 1: 0, 16: 0, 32: 0, 8: 0}}, {4: {128: 0, 64: 0, 2: 0, 4: 0, 1: 0, 16: 0, 32: 0, 8: 0}}]
vals = [v for i in ip_dict_list for k, v in i.items()]
network_octets = vals[:octet]
work_octets = vals[octet:]
ip_list = ip.split('.')
iof = int(ip_list[octet]) # ip octet in focus (54)
for i in range(len(work_octets)):
for ob in self.bit_placement: # loop over the list [128, 64, 32, 16, 8, 4, 2, 1]
# 32 < 54
if ob <= iof:
print "Iof: {}, Ob: {}".format(iof, ob)
iof = iof - ob # 54-32 = 22; 22-16 = 6; 6-4: 2; 2-2 = 0 (done)
work_octets[i][ob] = 1 # {32: 1, 16: 0, 8: 0, 4: 0, 2: 0, 1:0 }
if iof == 0:
break
Iof: 54, Ob: 32
Iof: 22, Ob: 16
Iof: 6, Ob: 4
Iof: 2, Ob: 2
print work_octets # as expected
[{128: 0, 64: 0, 2: 1, 4: 1, 1: 0, 8: 0, 16: 1, 32: 1}]
Now network_octets also got changed and I expect it to remain the same - not as expected
print network_octets
[{128: 0, 64: 0, 2: 1, 4: 1, 1: 0, 8: 0, 16: 1, 32: 1}, {128: 0, 64: 0, 2: 1, 4: 1, 1: 0, 8: 0, 16: 1, 32: 1}, {128: 0, 64: 0, 2: 1, 4: 1, 1: 0, 8: 0, 16: 1, 32: 1}]
This should be unchanged and should look like this:
network_octets
[{128: 0, 64: 0, 2: 0, 4: 0, 1: 0, 8: 0, 16: 0, 32: 0}, {128: 0, 64: 0, 2: 0, 4: 0, 1: 0, 8: 0, 16: 0, 32: 0}, {128: 0, 64: 0, 2: 0, 4: 0, 1: 0, 8: 0, 16: 0, 32: 0}]
The variable vals is also changing after the for loop:
vals
[{128: 0, 64: 0, 2: 1, 4: 1, 1: 0, 8: 0, 16: 1, 32: 1}, {128: 0, 64: 0, 2: 1, 4: 1, 1: 0, 8: 0, 16: 1, 32: 1}, {128: 0, 64: 0, 2: 1, 4: 1, 1: 0, 8: 0, 16: 1, 32: 1}, {128: 0, 64: 0, 2: 1, 4: 1, 1: 0, 8: 0, 16: 1, 32: 1}]
我希望只有 work_octets 的 dict 元素的值发生变化,而 network_octets 和 vals 应该保持不变。但是所有的变量在 for 循环之后都被修改了
有很多代码,您的代码片段无法按原样执行,
所以要给出明确的答案有点困难。
不过,我认为问题在于您如何创建列表。
如果我正确理解了你的代码,
network_octets
和 work_octets
是两个字典列表。
但那些是相同的字典,所以即使你有不同的列表
(即 network_octets is work_octets
将是 False
),
他们的内容是一样的
(即 network_octets[0] is work_octets[0]
将是 True
)。
因此,当您分配 work_octets[i][ob]
时,
您还触摸了 network_octets[i]
中的词典。
您可以通过打印 ip_dict_list
来确认,
这也应该改变。
我们可以用一个更简单的例子来重现这个问题:
source = [{0: 10, 1: 20}, {0: 30, 1: 40}, {0: 50, 1: 60}]
l1 = source[:2]
l2 = source[:2]
# Prints 'True'
print(l1[0] is l2[0])
# Here we're effectively touching `l1[0][0]` *and* `l2[0][0]`
l1[0][0] = 100
# Prints '[{0: 100, 1: 20}, {0: 30, 1: 40}]'
print(l2)
您不一定需要深复制所有内容。
您可以只关注正在修改的对象。
例如,在我的示例中,它可以归结为以下内容:
# ...
l1[0] = dict(l1[0])
l1[0][0] = 100
# Prints '[{0: 100, 1: 20}, {0: 30, 1: 40}]'
print(l1)
# Prints '[{0: 10, 1: 20}, {0: 30, 1: 40}]'
print(l2)
在你的代码中要小心,因为评论表明你的列表实际上包含字典的字典。
因此,如果您只浅拷贝外部的,上述问题也将适用。
深拷贝肯定会更安全,但如果有任何问题,也会更昂贵。
您可以尝试 print-debug 和 is
(就像我在示例中所做的那样)或 id
以确保词典在您之前有所不同改变它们:
# Prints '4406947912 4406947912'
# Obviously the numbers could be different every time you run your code.
print(id(l1[0]), id(l2[0]))
我正在尝试根据我拥有的掩码更改一个八位位组。
假设我有 IP:194.216.35.54 和掩码 - 27,我需要更改第 4 个八位字节(从 0 开始计算时为 3)。我正在尝试更改 work_octets
变量中的值。但是,不知何故,network_octets
中的值也在发生变化。为什么会这样? network_octets
和 work_octets
都是两个不同的列表,它们是通过遍历值和切片 ip_dict_list
创建的。 network_octets
是怎么改变的 - 任何人都可以帮助我理解我在这里做错了什么吗?
注意:我可以深度复制并更改此行为,但我需要知道我在这里做错了什么。非常感谢这方面的任何解释。
代码:
octet = 3
ip_dict_list = dc(self.ip_dict_list) # looks like this: [{1: {128: 0, 64: 0, 2: 0, 4: 0, 1: 0, 16: 0, 32: 0, 8: 0}}, {2: {128: 0, 64: 0, 2: 0, 4: 0, 1: 0, 16: 0, 32: 0, 8: 0}}, {3: {128: 0, 64: 0, 2: 0, 4: 0, 1: 0, 16: 0, 32: 0, 8: 0}}, {4: {128: 0, 64: 0, 2: 0, 4: 0, 1: 0, 16: 0, 32: 0, 8: 0}}]
vals = [v for i in ip_dict_list for k, v in i.items()]
network_octets = vals[:octet]
work_octets = vals[octet:]
ip_list = ip.split('.')
iof = int(ip_list[octet]) # ip octet in focus (54)
for i in range(len(work_octets)):
for ob in self.bit_placement: # loop over the list [128, 64, 32, 16, 8, 4, 2, 1]
# 32 < 54
if ob <= iof:
print "Iof: {}, Ob: {}".format(iof, ob)
iof = iof - ob # 54-32 = 22; 22-16 = 6; 6-4: 2; 2-2 = 0 (done)
work_octets[i][ob] = 1 # {32: 1, 16: 0, 8: 0, 4: 0, 2: 0, 1:0 }
if iof == 0:
break
Iof: 54, Ob: 32
Iof: 22, Ob: 16
Iof: 6, Ob: 4
Iof: 2, Ob: 2
print work_octets # as expected
[{128: 0, 64: 0, 2: 1, 4: 1, 1: 0, 8: 0, 16: 1, 32: 1}]
Now network_octets also got changed and I expect it to remain the same - not as expected
print network_octets
[{128: 0, 64: 0, 2: 1, 4: 1, 1: 0, 8: 0, 16: 1, 32: 1}, {128: 0, 64: 0, 2: 1, 4: 1, 1: 0, 8: 0, 16: 1, 32: 1}, {128: 0, 64: 0, 2: 1, 4: 1, 1: 0, 8: 0, 16: 1, 32: 1}]
This should be unchanged and should look like this:
network_octets
[{128: 0, 64: 0, 2: 0, 4: 0, 1: 0, 8: 0, 16: 0, 32: 0}, {128: 0, 64: 0, 2: 0, 4: 0, 1: 0, 8: 0, 16: 0, 32: 0}, {128: 0, 64: 0, 2: 0, 4: 0, 1: 0, 8: 0, 16: 0, 32: 0}]
The variable vals is also changing after the for loop:
vals
[{128: 0, 64: 0, 2: 1, 4: 1, 1: 0, 8: 0, 16: 1, 32: 1}, {128: 0, 64: 0, 2: 1, 4: 1, 1: 0, 8: 0, 16: 1, 32: 1}, {128: 0, 64: 0, 2: 1, 4: 1, 1: 0, 8: 0, 16: 1, 32: 1}, {128: 0, 64: 0, 2: 1, 4: 1, 1: 0, 8: 0, 16: 1, 32: 1}]
我希望只有 work_octets 的 dict 元素的值发生变化,而 network_octets 和 vals 应该保持不变。但是所有的变量在 for 循环之后都被修改了
有很多代码,您的代码片段无法按原样执行, 所以要给出明确的答案有点困难。 不过,我认为问题在于您如何创建列表。
如果我正确理解了你的代码,
network_octets
和 work_octets
是两个字典列表。
但那些是相同的字典,所以即使你有不同的列表
(即 network_octets is work_octets
将是 False
),
他们的内容是一样的
(即 network_octets[0] is work_octets[0]
将是 True
)。
因此,当您分配 work_octets[i][ob]
时,
您还触摸了 network_octets[i]
中的词典。
您可以通过打印 ip_dict_list
来确认,
这也应该改变。
我们可以用一个更简单的例子来重现这个问题:
source = [{0: 10, 1: 20}, {0: 30, 1: 40}, {0: 50, 1: 60}]
l1 = source[:2]
l2 = source[:2]
# Prints 'True'
print(l1[0] is l2[0])
# Here we're effectively touching `l1[0][0]` *and* `l2[0][0]`
l1[0][0] = 100
# Prints '[{0: 100, 1: 20}, {0: 30, 1: 40}]'
print(l2)
您不一定需要深复制所有内容。 您可以只关注正在修改的对象。 例如,在我的示例中,它可以归结为以下内容:
# ...
l1[0] = dict(l1[0])
l1[0][0] = 100
# Prints '[{0: 100, 1: 20}, {0: 30, 1: 40}]'
print(l1)
# Prints '[{0: 10, 1: 20}, {0: 30, 1: 40}]'
print(l2)
在你的代码中要小心,因为评论表明你的列表实际上包含字典的字典。 因此,如果您只浅拷贝外部的,上述问题也将适用。 深拷贝肯定会更安全,但如果有任何问题,也会更昂贵。
您可以尝试 print-debug 和 is
(就像我在示例中所做的那样)或 id
以确保词典在您之前有所不同改变它们:
# Prints '4406947912 4406947912'
# Obviously the numbers could be different every time you run your code.
print(id(l1[0]), id(l2[0]))