Search code examples
pythondictionaryfor-loopdictionary-comprehension

update dictionary in python from line data


I have a script where I read a file line by line and save some information to lists and dictionary. Namely, I store the keys (say ley1 and key2) to pass to the dictionary and a list to be stored as item in the dictionary.

It happens that I have to update a dictionary only if some conditions are met, i.e.:

myDict = {}
if mylist:
    myDict[key1][key2] = mylist

Of course this will raise a KeyError if key2 does not exist already. Therefore, I introduced the following function:

def updateDict2keys(myDict,mykey1,mykey2,myitems):
    """
    updates a dictionary by appending values at given keys (generating key2 if not given)
    input: key1, key2 and items to append
    output: dictionary orgnanized as {mykey1:{mykey2:myitems}}
    """
    try:
        myDict[mykey1][mykey2] = myitems
    except KeyError:
        myDict[mykey1] = {mykey2:myitems}
    # output
    return myDict

My question is: is it "safe" to call such a function in the main code inside a for loop like this?

with open(os.path.join(path+myfile)) as ntwkf:
    # read file
    rdlistcsv = csv.reader(ntwkf)
    rowslist  = [line for line in rdlistcsv]
ntwkJuncDict = {}
for idx,f in enumerate(rowslist): # loop over file lines
    if f:
        lineelmnt = f[0].split()[0]
    else:
        continue
    # flags
    isBranchName = True if lineelmnt=='definitions' else False
    isJunction = True if lineelmnt=='connections' else False
    # update dictionary
    if isBranchName:
        reachname = f[0].split()[2].replace("'","")
    if isJunction:
        usreach = f[0].split()[2].replace("'","")
        uschain = float(f[1].replace("'","").replace(" ",""))
        if usreach: 
            uslist = [usreach, uschain]
            todivide.append(uslist)
            ntwkJuncDict = updateDict2keys(ntwkJuncDict, reachname, 'upstream', uslist)

I must say, my code works pretty well, I am just asking myself (and yourselves of course!) if I am doing everything the python way and if there are smarter solutions.


Solution

  • Instead of accessing the primary key, use dict.setdefault with a default empty dict on it.

    def updateDict2keys(myDict,mykey1,mykey2,myitems):
        myDict.setdefault(mykey1, {})[mykey2] = myitems
        return myDict
    

    Note that your initial approach is also safe. Only lookup, not assignment, throws KeyError. In the statement myDict[mykey1][mykey2] = myitems, a KeyError can only be thrown of mykey1 is not set. Thus, setting it to an empty dict on a KeyError does not overwrite anything.