List on python appending always the same value [duplicate]

半腔热情 提交于 2019-12-13 03:26:53

问题


I have the following code inside a while loop.

if gender == 0 and len(men) < 51 :
    height = float((random.uniform(1.3, 1.9) + (random.randint(10, 20)/100.)).__format__('.2f'))
    weight = float((random.uniform(45, 100) * height).__format__('.2f'))
    attr['height'] = height 
    attr['weight'] = weight

    men.append(attr)

So this code always gives some random height and random weight. But outsite de loop (when it is finished). If I do print men, I get the following result:

[{'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}, {'weight': 76.64, 'height': 1.75}]

Its always the same thing. But, if I instead of using attr[height] = height; attr['weight] = weight and use men.append(height); men.append(weight) I get the following result:

print men [1.91, 145.95, 1.64, 95.66, 2.0, 159.94, 1.74, 143.36, 1.68, 97.99, 1.6, 90.11, 1.63, 116.2, 1.56, 96.8, 2.04, 198.56, 1.56, 145.96, 1.44, 67.57, 1.83, 94.97, 1.85, 175.69, 1.84, 101.84, 1.54, 135.0, 1.41, 101.23, 1.92, 167.59, 1.74, 142.55, 1.49, 129.07, 1.83, 161.28, 1.59, 97.16, 1.46, 134.53, 2.03, 158.72, 2.05, 184.43, 1.97, 162.81]

If I print attr inside the loop it always has a different value ( its what I want). But when I append it to my list, the values of my list are always the same. What am I doing wrong?


回答1:


A simplified example of your code currently to explain more fully why your results are the way they are:

all_items = []
new_item = {}
for i in range(0,5):
    new_item['a'] = i
    new_item['b'] = i

    all_items.append(new_item)
    print new_item
    print hex(id(new_item))  # print memory address of new_item

print all_items

Notice the memory address for your object is the same each time you go through your loop. This means that your object being added is the same, each time. So when you print the final list, you are printing the coordinates of the same object at every location in the loop.

Each time you go through the loop, the values are being updated - imagine you are painting over the same wall every day. The first day, it might be blue. The next day, you repaint the same wall (or object) and then it's green. The last day you paint it orange and it's orange - the same wall is always orange now. Your references to the attr object are like saying you have the same wall.

Even though you looked at the wall after painting it, the color changed. But afterwards it is a orange wall - even if you look at it 5 times.

When we make the object as a new object in each iteration, notice two things happen:

  1. the memory address changes
  2. the values persist as unique values

This is similar to painting different walls. After you finish painting the last one, each of the previous walls is still painted the color you first painted it.

You can see this in the following, where each object is created each iteration:

all_items = []
for i in range(0,5):
    new_item = {}
    new_item['a'] = i
    new_item['b'] = i

    all_items.append(new_item)
    print hex(id(new_item))


 print all_items

You can also do in a different way, such as:

all_items = []
for i in range(0,5):
    new_item = {'a': i, 'b': i}
    all_items.append(new_item)
    print hex(id(new_item))    
print all_items

or even in one step:

all_items = []
for i in range(0,5):
    all_items.append({'a': i, 'b': i})

print all_items

Either of the following will therefore work:

attr = {}
attr['height'] = height 
attr['weight'] = weight

men.append(attr)

or:

men.append({'height': height, 'weight': weight})



回答2:


You are adding the same attr dictionary to the list several times. The following lines will only mutate the attr dictionary instead of creating a new one:

attr['height'] = height 
attr['weight'] = weight

You should create a new dict each time, such as:

attr = {'height': height, 'weight': weight}



回答3:


To avoid the ambiguity involved in re-initializing (a step you missed) a variable in a loop and appending it to a list, Python allows you to be much more succinct.

height = float((random.uniform(1.3, 1.9) + (random.randint(10, 20)/100.)).__format__('.2f'))
men.append({
    'height': height,
    'weight': float((random.uniform(45, 100) * height).__format__('.2f')),
})



回答4:


Your problem is that you are mutating a dict and appending that same dict over and over. You should create a new dict each time

It's also much clearer to use round instead of convert to str and back to float

if gender == 0 and len(men) < 51 :
    height = round(random.uniform(1.3, 1.9) + (random.randint(10, 20)/100.), 2)
    weight = round(random.uniform(45, 100) * height, 2)
    men.append({'height' : height, 'weight', weight})



回答5:


you should Use the definition of dictionary inside the for loop instead of outside the for loop

for i in range(0, 10):
    attr = {}
    if gender == 0 and len(men) < 51 :
        height = float((random.uniform(1.3, 1.9) + (random.randint(10,20)/100.)).__format__('.2f'))
        weight = float((random.uniform(45, 100) * height).__format__('.2f'))
        attr['height'] = height 
        attr['weight'] = weight

        men.append(attr)

This gives me following output:

[{'weight': 126.75, 'height': 1.76}, {'weight': 155.35, 'height': 1.91}, {'weight': 169.2, 'height': 1.87}, {'weight': 135.54, 'height': 1.45}, {'weight': 98.58, 'height': 1.98}, {'weight': 133.73, 'height': 1.44}, {'weight': 149.48, 'height': 1.87}, {'weight': 121.93, 'height': 1.46}, {'weight': 160.09, 'height': 1.93}, {'weight': 115.62, 'height': 1.56}]




回答6:


I don't think you are doing anything wrong. You only need to check your indentation to make sure the line for men.append(attr) is inside the if statement cuz as you overwrite the attr, you can then append using men.append(attr)



来源:https://stackoverflow.com/questions/57580950/code-keeps-overwriting-entries-in-array-when-using-append-to-try-to-add-new-e

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!