Is there a more Pythonic way to combine an Else: statement and an Except:?

Question:

I have a piece of code that searches AutoCAD for text boxes that contain certain keywords (eg. "overall_weight" in this case) and replaces it with a value from a dictionary. However, sometimes the dictionary key is assigned to an empty string and sometimes, the key doesn’t exist altogether. In these cases, the "overall_weight" keywords should be replaced with "N/A". I was wondering if there was a more pythonic way to combine the KeyError exception and the else to both go to nObject.TextString = "N/A" so its not typed twice.

if nObject.TextString == "overall_weight":
    try:
        if self.var.jobDetails["Overall Weight"]:
            nObject.TextString = self.var.jobDetails["Overall Weight"]
        else:
            nObject.TextString = "N/A"
    except KeyError:
        nObject.TextString = "N/A"

Edit: For clarification for future visitors, there are only 3 cases I need to take care of and the correct answer takes care of all 3 cases without any extra padding.

  1. dict[key] exists and points to a non-empty string. TextString replaced with the value assigned to dict[key].

  2. dict[key] exists and points to a empty string. TextString replaced with "N/A".

  3. dict[key] doesn’t exist. TextString replaced with "N/A".

Asked By: RBuntu

||

Answers:

Use .get() with a default argument of "N/A" which will be used if the key does not exist:

nObject.TextString = self.var.jobDetails.get("Overall Weight", "N/A")

Update

If empty strings need to be handled, simply modify as follows:

nObject.TextString = self.var.jobDetails.get("Overall Weight") or "N/A"

This will set nObject.TextString to “N/A” if a KeyError is raised, or if the value is retrieved is empty: '', [], etc.

Answered By: elethan

Use get() function for dictionaries. It will return None if the key doesn’t exist or if you specify a second value, it will set that as the default. Then your syntax will look like:

nObject.TextString = self.var.jobDetails.get('Overall Weight', 'N/A')
Answered By: notorious.no

I think this is a good case for setting the default value in advance

if nObject.TextString == "overall_weight":
    nObject.TextString = "N/A"
    try:
        if self.var.jobDetails["Overall Weight"]:
            nObject.TextString = self.var.jobDetails["Overall Weight"]
    except KeyError:
        pass

RADICAL RETHINK

Ditch that first answer (just keeping it because it got an upvote). If you really want to go pythonic, (and you always want to set a value on TextString) replace the whole thing with

nObject.TextString = (nObject.TextString == "overall_weight"
    and self.var.jobDetails.get("Overall Weight")
    or "N/A")

Python and and or operations return their last calculated value, not True/False and you can use that to walk through the combinations.

Answered By: tdelaney

Use dict.get() which will return the value associated with the given key if it exists otherwise None. (Note that '' and None are both falsey values.) If s is true then assign it to nObject.TextString otherwise give it a value of "N/A".

if nObject.TextString == "overall_weight":
    nObject.TextString = self.var.jobDetails.get("Overall Weight") or "N/A"
Answered By: pzp

How about with:

key = 'Overall Weight'

with n_object.text_string = self.var.job_details[key]:
    if self.var.job_details[key] is None 
    or if self.var.job_details[key] is '' 
    or if KeyError:
        n_object.text_string = 'N/A'
Answered By: noumenal

The Zen of Python says “Explicit is better than implicit.” I have found this to be very true in my own experience. When I write a piece of code I think to my self, “Will I understand what this means a year from now?” If the answer is “no” then it needs to be re-written or documented. The accepted answer relies on remembering the implementation of dict.get to know how it will handle the corner cases. Since the OP has 3 clear criteria, I would instead document them clearly in an if statement.

if nObject.TextString == "overall_weight" and 
    "Overall Weight" in self.var.jobDetails and 
    self.var.jobDetails["Overall Weight"] != "":
    nObject.TextString = self.var.jobDetails["Overall Weight"]
else:
    nObject.TextString = "N/A"

It’s certainly more verbose… but that’s a good thing. There is no question when reading this what the behavior will be.

Answered By: intrepidhero
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.