问题
I have a problem when adding value inside the nested dictionary using the same keys and the value is always shown the same value, The fact is, i want update the value event the keys is same. This algorithm is the basic of Artificial Fish Swarm Algorithm
# example >> fish_template = {0:{'weight':3.1,'visual':2,'step':1},1:'weight':3,'visual':4,'step':2}}
fish = {}
fish_value = {}
weight = [3.1, 3, 4.1, 10]
visual = [2, 4, 10, 3]
step = [1, 2, 5, 1.5]
len_fish = 4
for i in range(0,len_fish):
for w, v, s in zip(weight, visual, step):
fish_value["weight"] = w
fish_value["visual"] = v
fish_value["step"] = s
fish[i] = fish_value
print("show fish",fish)
I expect the result to be like fish_template, but it isn't. The values for the keys 'weight', 'visual', 'step' are always the same with values of 0, 1, 2, and 3. Any solution?
回答1:
The issue is with fish[i]
, you simply created a dict
with the same element: fish_value
. Python does not generate a new memory for the same variable name, so all your dict keys point to the same value=fish_value
, which gets overwritten and all your dict values take the last state of fish_value
. To overcome this, you can do the following:
fish = {}
weight = [3.1, 3, 4.1, 10]
visual = [2, 4, 10, 3]
step = [1, 2, 5, 1.5]
len_fish = 4
for i in range(0, len_fish):
fish[i]= {"weight": weight[i], "visual": visual[i], "step": step[i]}
print("show fish", fish)
As @Error mentioned, the for loop can be replaced by this one-liner:
fish = dict((i, {"weight": weight[i], "visual": visual[i], "step": step[i]}) for i in range(len_fish))
回答2:
Not sure I fully understand what you're trying to do here, but the problem is the last line of your inner for loop. You're looping over i
in the main loop, then then inner loop is setting fish[i]
multiple times. As a result all your fish_value will look identical.
回答3:
Because of aliasing; the line fish[i] = fish_value
is bad practice, fish_value
gets overwritten each time you loop; then fish[i] = fish_value
just assigns a shallow copy into fish[i]
, which is not what you want.
But really you can avoid the loop with a dict comprehension.
Anyway, better coding practice is to declare your own Fish
class with members weight, visual, step
, as below. Note how:
- we use
zip()
function to combine the separatew,v,s
lists into a tuple-of-list. - Then the syntax
*wvs
unpacks each tuple into three separate values ('weight', 'visual', 'step'). This is called tuple unpacking, it saves you needing another loop, or indexing. - a custom
__repr__()
method (with optional ASCII art) makes each object user-legible. (Strictly we should be overriding__str__
rather than__repr__
, but this works)
Code:
class Fish():
def __init__(self, weight=None, visual=None, step=None):
self.weight = weight
self.visual = visual
self.step = step
def __repr__(self):
"""Custom fishy __repr__ method, with ASCII picture"""
return f'<º)))< 🐟 [ Weight: {self.weight}, visual: {self.visual}, step: {self.step} ]'
# define whatever other methods you need on 'Fish' object...
# Now create several Fish'es...
swarm = [ Fish(*wvs) for wvs in zip([3.1, 3, 4.1, 10], [2, 4, 10, 3], [1, 2, 5, 1.5]) ]
# zip() function combines the lists into a tuple-of-list. `*wvs` unpacks each tuple into three separate values ('weight', 'visual', 'step')
# See what we created...
>>> swarm
[<º)))< 🐟 [ Weight: 3.1, visual: 2, step: 1 ], <º)))< 🐟 [ Weight: 3, visual: 4, step: 2 ], <º)))< 🐟 [ Weight: 4.1, visual: 10, step: 5 ], <º)))< 🐟 [ Weight: 10, visual: 3, step: 1.5 ]]
# ... or for prettier output...
>>> for f in swarm: print(f)
<º)))< 🐟 [ Weight: 3.1, visual: 2, step: 1 ]
<º)))< 🐟 [ Weight: 3, visual: 4, step: 2 ]
<º)))< 🐟 [ Weight: 4.1, visual: 10, step: 5 ]
<º)))< 🐟 [ Weight: 10, visual: 3, step: 1.5 ]
来源:https://stackoverflow.com/questions/55885842/custom-dictionary