Updating a dict with dict values This code works and does exactly what I want it to, but I feel that it is inelegant.  It seems like there should be a way to use get() and/or setdefault(), for example.  All comments and suggestions are appreciated!

Here is a function that builds a dict.  The dict's values are also dicts.  Some of the values are empty dicts {} and some are dicts that have a {key:value} pair.

def my_function(my_string, my_key):

    d = {}

    for i in range(3):
        d['test' + str(i)] = {}

    d['test3'] = {'a_key': 'a_value'}

    # d = { 'test0': {}, 'test1': {}, 'test2': {}, 'test3': {'a_key': 'a_value'} }

    if my_string != '':
        d[my_key] = {my_string: None}

    else:
        # check if d[my_key] exists
        try:
            # d[my_key] exists and it is not empty, don't overwrite
            if d[my_key]:
                pass
            # d[my_key] exists, but it is empty, write NULL
            else:
                my_string = 'NULL'
                d[my_key] = {my_string: None}

        # d[my_key] did not exist, create it and write NULL
        except KeyError:
            my_string = 'NULL'
            d[my_key] = {my_string: None}

    return d


# my_string not blank, my_key is new
f = my_function('hello', 'test4')
print(f)

# my_string not blank, my_key exists
f = my_function('hello', 'test0')
print(f)

# my_string blank, my_key exists and its value is not empty
f = my_function('', 'test3')
print(f)

# my_string blank, my_key exists and its value is empty
f = my_function('', 'test0')
print(f)

# my_string blank, my_key is new
f = my_function('', 'test4')
print(f)


Typical (and desired) output:

{'test2': {}, 'test3': {'a_key': 'a_value'}, 'test0': {}, 'test1': {}, 'test4': {'hello': None}}
{'test2': {}, 'test3': {'a_key': 'a_value'}, 'test0': {'hello': None}, 'test1': {}}
{'test2': {}, 'test3': {'a_key': 'a_value'}, 'test0': {}, 'test1': {}}
{'test2': {}, 'test3': {'a_key': 'a_value'}, 'test0': {'NULL': None}, 'test1': {}}
{'test2': {}, 'test3': {'a_key': 'a_value'}, 'test0': {}, 'test1': {}, 'test4': {'NULL': None}}
Tests

It's a good thing you've provided tests and expected output so that one can check the behavior, it is even better if one can run the tests without having to check that the output is correct. Only a tiny bit of reorganisation is required to get :

# my_string not blank, my_key is new
assert my_function('hello', 'test4') == {'test2': {}, 'test3': {'a_key': 'a_value'}, 'test0': {}, 'test1': {}, 'test4': {'hello': None}}

# my_string not blank, my_key exists
assert my_function('hello', 'test0') == {'test2': {}, 'test3': {'a_key': 'a_value'}, 'test0': {'hello': None}, 'test1': {}}

# my_string blank, my_key exists and its value is not empty
assert my_function('', 'test3') == {'test2': {}, 'test3': {'a_key': 'a_value'}, 'test0': {}, 'test1': {}}

# my_string blank, my_key exists and its value is empty
assert my_function('', 'test0') == {'test2': {}, 'test3': {'a_key': 'a_value'}, 'test0': {'NULL': None}, 'test1': {}}

# my_string blank, my_key is new
assert my_function('', 'test4') == {'test2': {}, 'test3': {'a_key': 'a_value'}, 'test0': {}, 'test1': {}, 'test4': {'NULL': None}}

# New test from Sjoerd Job Postmus's comment
assert my_function('something not empty', 'test3') == {'test1': {}, 'test0': {}, 'test3': {'something not empty': None}, 'test2': {}}


Improvements

if my_string != '': could be rewritten more concisely : if my_string:.

Also, you could use get to retrievement elements in a "safe" way.

Thus, the code becomes :

if my_string:
    d[my_key] = {my_string: None}
else:
    if not d.get(my_key):
        d[my_key] = {'NULL': None}
return d


Also, your dict initialisation could be done with a dictionnary comprehension. Then, your whole function would become:

def my_function(my_string, my_key):
    d = {'test' + str(i): {} for i in range(3)}
    d['test3'] = {'a_key': 'a_value'}

    if my_string:
        d[my_key] = {my_string: None}
    elif not d.get(my_key):
        d[my_key] = {'NULL': None}
    return d




Is this as simple as it can be ? Not quite ? The check for d.get(my_key) is actually to distinguish "test3" from the other values. It could be easier to just do the obvious thing instead of trying to retrieve stuff from the dict :

def my_function(my_string, my_key):
    d = {'test' + str(i): {} for i in range(3)}
    d['test3'] = {'a_key': 'a_value'}
    if my_string:
        d[my_key] = {my_string: None}
    elif my_key != 'test3':
        d[my_key] = {'NULL': None}
    return d