Pythonic方式分配默认值

时间:2011-11-30 10:42:55

标签: error-handling python

考虑这一行:

some_value = lst.attr[idx]

此处有两个可能的错误,attr可能不存在,idx可能超出范围。

有没有优雅的方法来减少这种说法?理想情况下,对于这样的事情:

some_value = lst.attr[idx] or default_value

(不要在家里尝试。只适用于评估为某种东西的正确定义的表达式。)

当然可以做到:

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

但是,如果我在作业的背景下怎么办?例如:

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

在这种情况下,处理错误和分配默认值的pythonic方法是什么?

6 个答案:

答案 0 :(得分:6)

你需要在这里决定你想要达到的目标。使用“错误”一词可能会产生误导。

如果您实际上正在尝试处理将错误类型的对象传递给您的函数的情况,那么您不想处理它并且应该引发异常。

如果您尝试允许在一系列不同类型上使用您的函数,那么这不是真正的错误,使用默认值可能是合理的。

最简单的选择是先测试属性是否存在。例如:

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

我假设lst.attr是一个字典,在这种情况下你可以像这样处理默认值:

lst.attr.get(idx, default_value)

永远不要使用try / except语句,而不指定要捕获的异常。你最终可能比你想要的更多地掩盖。

使用最后一段代码,我认为你不应该尝试在一行中解决它。可读性很重要。我对以下代码不满意,但如果xyattr被更具描述性的名称替换,则会有所改进。

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

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

答案 1 :(得分:4)

  

在这种情况下, pythonic 处理错误和分配默认值的方法是什么?

>>> 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.

我觉得 Pythonic 分配默认值的方式”*要么处理异常 - 正如您在问题中已经提到的那样 - 要么写你拥有吸气剂。

答案 2 :(得分:3)

编写一个函数并使其足够智能:

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]

如果您控制x的类,您可以将其用作方法,或者将其作为描述符进行修改,但是这不值得,并且会导致代码模糊并且难以跟踪错误。

答案 3 :(得分:2)

即使存在单行,也会非常复杂。例如。这个仍然没有处理索引问题:

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

我建议为你的lst写一些getter。

答案 4 :(得分:2)

当对象中有'attr'时

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

没有属性'attr'时

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

答案 5 :(得分:0)

对您的问题没有简单,优雅的解决方案。如果必须使用可以在列表推导中使用的单行程来完成,那么您可以执行以下操作:

# 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