¿Por qué se anulan los valores del diccionario al final de este bucle?

Tengo un diccionario de paradas de transporte público llamado paradas. Quiero duplicar los que son transferencias (tienen más de una línea) para que haya una parada duplicada en las paradas para cada una de esas líneas adicionales. Inicialmente almaceno esos duplicados en un diccionario llamado duplicados. Sin embargo, después de asignar el nombre de la línea correspondiente a cada parada duplicada, todos se anulan por la última línea en la lista original de líneas de la parada original. Así que termino con un montón de paradas duplicadas, todas con la misma línea en lugar de una parada para cada línea. ¿Qué está anulando estos valores? El archivo l_stops.csv está en Dropbox y bpaste .

import csv import random def stop_coords(): with open('l_stops.csv', 'rb') as csvfile: stop_reader = csv.reader(csvfile, delimiter=',', quotechar='"') stops = {} for row in stop_reader: map_id = row[5] lines = set() if row[7] == 'true': lines.add('Red') if row[8] == 'true': lines.add('Blue') if row[9] == 'true': lines.add('Green') if row[10] == 'true': lines.add('Brown') if row[11] == 'true': lines.add('Purple') if row[13] == 'true': lines.add('Yellow') if row[14] == 'true': lines.add('Pink') if row[15] == 'true': lines.add('Orange') if map_id not in stops: stop_name = row[2].partition('(')[0].rstrip(' ') lat = float(row[16].lstrip('"(').rpartition(',')[0]) lng = float(row[16].lstrip('"(').rpartition(',')[2].strip(' )"')) stop = {} stop['name'] = stop_name stop['lat'] = lat stop['lng'] = lng stop['x'] = lng stop['y'] = lat stop['lines'] = lines stops[map_id] = stop stop['duplicateStops'] = [] elif stops[map_id]['lines'] != lines: stops[map_id]['lines'] = stops[map_id]['lines'].union(lines) for item in stops: stops[item]['lines'] = list(stops[item]['lines']) # Add duplicate stops for stops that are transfers (shared by multiple lines) duplicates = {} # the dictionary that will hold the duplicates and be added to the stops dictionary after all duplicate stops have been processed for item in stops: num_lines = len(stops[item]['lines']) if num_lines > 1: # if a stop has more than one line original_lines = stops[item]['lines'] stops[item]['lines'] = original_lines[0] equivalent_map_ids = [item] # Make a list of different map_ids that represent the same stop (but on different lines). The first map_id in the list will be the "original" one. for i in range(num_lines - 1): # for each line after the first one # Create a new map_id and make sure it doesn't conflict with an existing map_id while True: new_map_id = str(random.randint(10000, 99999)) if new_map_id not in stops and new_map_id not in duplicates: break duplicates[new_map_id] = stops[item] # duplicate the stop equivalent_map_ids.append(new_map_id) # add the new map_id to the list of equivalent map_ids # Set the duplicateStops value of everyone in equivalent_map_ids's to the other stops' map_ids # The first map_id in equivalent_map_ids is the original one that's in the stops dictionary, so set its duplicateStops value to the rest of the list stops[item]['duplicateStops'] = equivalent_map_ids[1:] # For the rest of the map_ids in equivalent_map_ids j = 1 for duplicate_stop in stops[item]['duplicateStops']: duplicates[duplicate_stop]['lines'] = original_lines[j] duplicates[duplicate_stop]['duplicateStops'] = equivalent_map_ids[:j] + equivalent_map_ids[(j + 1):] # this line also changes stops[item]['duplicateStops'], not sure how j+= 1 # somehow by this point all duplicates have the same line (the last line in the original 'lines' list) for stop in stops[item]['duplicateStops']: print duplicates[stop]['name'] print duplicates[stop]['lines'] for item in duplicates: print item print duplicates[item]['name'] print duplicates[item]['lines'] stops.update(duplicates) stops['none'] = {'name' : 'none', 'lat' : 0, 'lng' : 0, 'x' : 0, 'y' : 0, 'lines' : ['none']} 

Durante la depuración, descubrí que al reasignar duplicados [duplicate_stop] [‘duplicateStops’] también se reasignan las paradas [item] [‘duplicateStops’]. ¿Cómo es eso posible? Los duplicados y las paradas son dos diccionarios separados.

Luego, duplicates[duplicate_stop] y stops[item] ambos nombran el mismo objeto, y mutando el objeto, bueno, cambia el objeto. Los objetos no se copian / clonan / duplican automáticamente en una asignación o cuando se usan como argumentos de función.

La línea problemática es más probable

 duplicates[new_map_id] = stops[item] # duplicate the stop 

.. y el comentario es incorrecto porque no hay duplicación que ocurra.


La pregunta ¿ Comprensión de dict.copy () – superficial o profunda? puede ser útil; por lo menos muestra cómo hacer una copia real.