0

My script is overriding values associated with keys/a key that hasn't been called.

I have a nested dictionary containing a hierarchy of keys like:

dict["species"]["type"]["reaction"]

This is a copy of another dictionary (dict_0 lets say) with the same structure. The copy will be updated continuously and the original stays the same for reference.

The values of the reactions start as small lists like ["e", "e", "p"] copied from the original dict_0, listing the left hand side of the reaction that the species is involved in.

For example:

dict_0["e"]["destruction"]["r_1"] = ["e", "e", "p"]
dict_0["p"]["destruction"]["r_1"] = ["e", "e", "p"]

because both e and p are involved in reaction r_1 and it is a process causing a net loss of e and p.

dict["e"]["destruction"]["r_1"] 

initially is the same as in dict_0 but the values in the list get updated with floats representing the density of that species, pulled from another dictionary called densities which is simply [species: density] as key, value.

The problem comes when I loop over the reaction key within a loop over the species key (setting the "type" key to "destruction" as this needs to happen first). I check if the reaction key is in a list of approved reaction identifiers then try to change the values for that reaction in the dict{} dictionary ONLY to densities provided by the densities dictionary. This is done by using the same keys to refer to the original dictionary dict_0{} each time where the ["e", "e", "p"] list always is and then using those as keys for the densities dictionary to update the densities in dict{}. This way you can always find the correct keys.

The problem itself is that when I override the initial copied ["e", "e", "p"] to [density_e, density_e, density_p] contained in dict["e"]["destruction"][reaction(e.g. "r_1")], it also overrides the equivalent values for dict["p"]["destruction"][reaction(e.g. "r_1")]

I have put in a ton of print statements to try to find the problem but cannot understand what is up. I have tried a simplified version in the console (non-nested) which behaves as expected - I thought maybe it was confusing the identical values. I can also change the values inside dict["e"]["destruction"][reaction(e.g. "r_1")] manually and the equivalent ['p'] values now do not change.

The code below isn't the whole thing but it is where the problem arises somewhere in the wad near the end where all the print statements are.

def dn_keys(diff_input,species_list,rates_names,densities_dict):

diff_input_new=copy.deepcopy(diff_input)
# Creates a new array from the master array and replaces the string values
# with floats using the dictionaries.
# print(diff_input_new)
# a = input("press to continue to density and rate population")
for species, value in diff_input_new.items():
    # for each species set of reactions:
    print("#####################")
    print("species = " + str(species))
    print("#####################")
    # a = input("press return to continue")
    # iterate over destructive processes first
    # key2 = "destruction"
    print("Destruction processes")
    print(str(diff_input_new[species]["destruction"]))
    for reaction, value in diff_input_new[species]["destruction"].items():
        if reaction in rates_names:

            print("Reaction found: " + str(reaction) +" for species: " + str(species))
            print("original entry: " + str(diff_input_new[species]["destruction"][reaction]))
            print(diff_input_new["e"]["destruction"][reaction])
            print(diff_input_new["p"]["destruction"][reaction])
            # for each species in the reaction:
            # print("array length = " + str(len(diff_input[species]["destruction"][reaction])))
            for i in range(len(diff_input[species]["destruction"][reaction])):
                # print(species)
                # if the rate hasn't been previously been added
                # find the densities and replace the dictionary entries appropriately
                print(i)   
                print("densities found for " + str(diff_input[species]["destruction"][reaction][i]) + ":") 
                print(densities_dict[diff_input[species]["destruction"][reaction][i]])
                print("--------")
                print(diff_input[species]["destruction"][reaction][i])
                print("in:")
                print(densities_dict.keys())
                print("---")
                print(diff_input_new[species]["destruction"][reaction][i])
                print("of")
                print(diff_input_new[species]["destruction"][reaction])
                diff_input_new[species]["destruction"][reaction][i] = densities_dict[diff_input[species]["destruction"][reaction][i]]
                print("converted to:")
                print(diff_input_new[species]["destruction"][reaction][i])
                print("---------------")
            diff_input_new["e"]["destruction"][reaction] = [1,1,1]

            print(diff_input_new["e"]["destruction"][reaction])
            print(diff_input_new["p"]["destruction"][reaction])

expected result: dict["e"]["destruction"][reaction] is updated independently of dict["p"]["destruction"][reaction]

actual result: both are updated together.

Thanks for your time

ratchet600
  • 69
  • 4
  • how do you copy ? to have 2 independent copies , you need to copy with copy.deepcopy. – John Doe Jan 15 '19 at 15:26
  • 1
    mandatory reading: https://nedbatchelder.com/text/names.html – bruno desthuilliers Jan 15 '19 at 15:31
  • 1
    Also please post a proper MCVE (https://stackoverflow.com/help/mcve). Chances are you'll find the issue by yourself while doing so FWIW. – bruno desthuilliers Jan 15 '19 at 15:33
  • Thanks, I'll have another dig with those resources first and probably reformat my question if necessary. I removed a lot of unnecessary bulk after posting. – ratchet600 Jan 15 '19 at 15:39
  • [how-to-clone-or-copy-a-list](https://stackoverflow.com/questions/2612802/how-to-clone-or-copy-a-list) – Patrick Artner Jan 15 '19 at 16:03
  • @ Patrick. Indeed, I didn't realize that was the root of the problem because of my lack of understanding of the name-value relationship. Otherwise I would have realized it was a duplicate issue. at least others who are in the same boat as me will now realize it is the same issue moving forward! – ratchet600 Jan 18 '19 at 09:24

1 Answers1

1

The problem was exactly as highlighted by bruno desthuillers which has deepened by basic understanding of python's name -value relationships.

Early in the code, the dictionary reactions entries are all declared as names for a single value - a list called species_lhs hence when I changed one instance it changed all of them.

ratchet600
  • 69
  • 4