简体   繁体   中英

Pythonic way to assign default values

Consider this line:

some_value = lst.attr[idx]

There are two possible errors here, the attr might not exist, and the idx might be out of range.

Is there any elegant way to reduce this statement? Ideally, to something like this:

some_value = lst.attr[idx] or default_value

(Don't try that at home. That only works for properly defined expressions that evaluate to something.)

Sure I can do:

try:
    some_value = lst.attr[idx]
except:
    some_value = default_value

But what if I'm in the context of an assignment? For example:

print [x.attr[idx] for x in y]

What's the pythonic way to handle errors and assign default values in this case?

You need to decide what you are trying achieve here. The use of the word "error" is probably misleading.

If you are actually trying to handle the case where the wrong type of object is passed to your function then you don't want to handle that and should raise an exception.

If you are trying to allow your function to be used on a series of different types then that's not really an error and using a default value may be reasonable.

The simplest option is to test whether the attribute exists first. For example:

if hasattr(lst, "attr"):
    attr = lst.attr
else:
    attr = {}

I'm assuming the lst.attr is a dictionary, in which case you can handle the default value like so:

lst.attr.get(idx, default_value)

Never use a try / except statement where you don't specify what exception you are catching. You can end up masking much more than you intended to.

With your final piece of code I think you should not try and solve it in a single line. Readability counts. I'm not happy with the code below, but it would be improved if x , y and attr were replaced with more descriptive names.

attrs = [(x.attr if hasattr(x) else {}) for x in y]

print [attr.get(idx, default_value) for attr in attrs]

What's the pythonic way to handle errors and assign default values in this case?

>>> import this
...
Explicit is better than implicit.
...
Sparse is better than dense.
Readability counts.
...
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.

I have the feeling that the " Pythonic way to assign default values"* is either to handle exception - as you already mentioned in your question - either to write you own getters.

write a function and make it smart enough:

def get_attr_with_index_and_default(obj, attr_name, index, default):
    try:
        return getattr(obj, attr_name)[index]
    except (AttributeError, IndexError):
         return default

print [get_attr_with_index_and_default(x, 'attr', idx, some_default) for x in y]

if you control the class of x , you can use this as a method, or adapt it as aa descriptor, but imo this is not worth it and will result in obscure code and difficult to trace bugs.

Even if there exists one-liner, it would be really complicated. Eg this one still doesn't handle index problem:

some_value = getattr(lst, 'attr', {idx: default_value})[idx]

I would suggest to write some getter for your lst .

When there is 'attr' in object

class C(object):
    attr = "attr on class"
lst = C()
print lst.attr if hasattr(lst,'attr') else "default value"

When there is no attribute 'attr'

class C(object):
    #attr = "attr on class"
    pass
lst = C()
print lst.attr if hasattr(lst,'attr') else "default value"

There is no simple, elegant solution to your problem. If it must be done using a one-liner that can be used in list-comprehensions for example, then you could do the following:

# If lst.attr is a dict.
some_value = getattr(lst, 'attr', {}).get(idx, default_value)
# OR
some_value = lst.attr.get(idx, default_value) if hasattr(lst, 'attr') else default_value
# OR
some_value = lst.attr[idx] if hasattr(lst, 'attr') and idx in lst.attr else default_value

# If lst.attr is a sequence.
some_value = lst.attr[idx] if idx < len(getattr(lst, 'attr', ())) else default_value
# OR
some_value = lst.attr[idx] if hasattr(lst, 'attr') and idx < len(lst.attr) else default_value

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM