Best practice for returning unknown data type from a dict?

Python 3.12 on Windows 10 Pro. I’m still fairly new to Python and have not seen this covered in my tutorial.

I’m not finding much at all after a Google search.

I have a function which checks to see if a dictionary key exists. And if it doesn’t, it returns a blank string ''. But sometimes the value in the dict can be a string, float, or int. Or the key may not exist at all, which is where I’m having trouble.

Let’s make an example program.

#######################################################
def getdictval(mydict,key):
    r'''If key exists, then return data, else return blank
    string.
    In:  dictionary; key to dict.
    Out: Value from dict. 
    '''
    procname = str(inspect.stack()[0][3]) + ":"
    val = '' # Default value is blank string.
    if key in mydict: 
        val = mydict[key]
    return val
#######################################################

mydict = {'firstname': 'John', 'age': 32, 'score': 83.4}

print(getdictval(mydict,'firstname')) # This works.

# Key does not exist but I'm expecting a number, so I get an error because empty string '' is returned.
num = getdictval(mydict,'myfloat')
# Error below: TypeError: '>' not supported between instances of 'str' and 'int'
#if num > 0.0: 
#    print("It is more than zero.")
    
# If I do this I get another error. Error below.
# ValueError: could not convert string to float: ''
if float(num) > 0.0: 
    print("It is more than zero.")
  1. What are ways for me to deal with this?
  2. Should I pass the type of variable I want returned into the getdictval() function as parameter 3? I may expect to return a str, float, or int.

My idea to pass the data type I want:

def getdictval(mydict,key,dtype):
    # Init default value.
    val = '' # Default value returned is blank string.
    if dtype == 'float': 
        val = mydict.get(key,0.0)
    elif dtype == 'int': 
        val = mydict.get(key,0)
    elif dtype == 'str': 
        val = mydict.get(key,'')
    else: 
        sys.exit(procname,"ERROR: Invalid data type param 3:",dtype)
... more stuff here

# Calling the function.
myfloat = getdictval(mydict, 'doesnotexist', 'float')

Thank you.

One point I would make is that dict is a reserved word for the dictionary type, so shouldn’t be used as the name of a variable.

Pass the actual type instead of a string. Functions are first-class objects in Python, so you can just pass them around, and then getdictval can call it to create the “default” value instead of needing any conditional logic:

def getdictval(dict,key,dtype):
    return dict.get(key, dtype())

Better yet, use collections.defaultdict, which wraps this for you already.

The only “reserved words” in Python are the keywords that are part of the language grammar (i.e., things that would cause a syntax error if misused). dict is a built-in name, meaning that a value is pre-assigned in the widest possible scope. It is possible to shadow this with proper understanding, although it may still be considered poor style. Everyone should have a proper understanding of this regardless, so:

Thanks I think I fixed all the instances of dict variable.

I’m looking into the mydict.setdefault() function. My issues is a bit more complicated since this is actually a dict of dicts. I will have to be careful to figure out exactly where to set the defaults for what I call the “subdict”.

The data looks a bit like this:

empdata['smijo']['fullname'] = 'SMIJO/ Smith, John'
empdata['smijo']['ethours'] = 3.4 # This will be a float.
empdata['smijo']['units'] = 750 # Will be an int.

subdict = empdata['smijo']
ethours = getdictval(subdict, 'ethours')
... etc

I’m finding Python to be really helpful! I just have to find out more about the functions related to dicts.

Yes, it is a name that denotes the built-in dictionary type - I wrote that “dict is a reserved word for the dictionary type”, not that dict is a reserved word of the language. I could have expressed it better, but I was describing it in the sense you have described.

I think the names of built-ins, like dict, set, list etc. should be treated as if they were reserved words - I have never seen production code where these were used interchangeably to denote user-defined variables.

P. S. I’ve just tried to find - unsuccessfully - prominent examples where built-ins names were used as variables, or people advocating for that. Which is why I think with “proper understanding” shadowing built-ins is never a good idea.

1 Like

Have you looked at the stdlib collections.defaultdict class? Perhaps not completely what you want, but it’s good to know it’s there:

from collections import defaultdict
dd = defaultdict(str)

>>> a in dd
False
>>> dd['a']
''

Can be nested:

dd = defaultdict(lambda: defaultdict(str))

>>> 'a' in dd
False
>>> dd['a']['b']
''

Your method looks more like get with an empty string as a default than it does setdefault.

mydict = {'firstname': 'John', 'age': 32, 'score': 83.4}

print(mydict.get('firstname', ''))

num = mydict.get('myfloat', 0)
if num > 0: 
    print("It is more than zero.")