如何为属性返回默认值?

60

我有一个对象myobject,它可能返回None。如果它返回None,它将不会返回属性id

a = myobject.id
当myobject为None时,上述语句会导致AttributeError
AttributeError: 'NoneType' object has no attribute 'id'

如果 myobject 是 None,则我希望 a 等于 None。我该如何在一行语句中避免此异常,例如:

a = default(myobject.id, None)
7个回答

137
你应该使用getattr包装器来获取id的值,而不是直接检索它。
a = getattr(myobject, 'id', None)
这就像是说“我想从对象myobject中检索属性id,但如果对象myobject中没有属性id,则返回None。” 但它执行得更有效率。
一些对象还支持以下形式的getattr访问:
a = myobject.getattr('id', None)

根据OP的要求,'deep getattr'函数:

def deepgetattr(obj, attr):
    """Recurses through an attribute chain to get the ultimate value."""
    return reduce(getattr, attr.split('.'), obj)
# usage: 
print deepgetattr(universe, 'galaxy.solarsystem.planet.name')

简单解释:

Reduce就像是一个原地递归函数。在这种情况下,它从obj(宇宙)开始,然后使用getattr逐级递归访问每个属性,因此在您的问题中,它会像这样:

a = getattr(getattr(myobject, 'id', None), 'number', None)


1
+1,这可能是最好的想法,不知道为什么我没想到。 - Gareth Latty
哈,谢谢,我要利用你的认可来进行无耻的自我推销。:P - Inbar Rose
@Inbar Rose 如果我想以同样的方式获取属性的属性,例如 a = myobject.id.number,该怎么办? - alwbtc
getattr(myobject.id, "number", None) 怎么样? - alwbtc

11

最简单的方法是使用三元运算符:

a = myobject.id if myobject is not None else None
三目运算符会在中间值为 true 时返回第一个表达式,否则返回后一个表达式。
请注意,您也可以使用异常来实现相同的效果:
try:
    a = myobject.id
except AttributeError:
    a = None

这符合Pythonic理念,即宁愿问后边的原谅也不要先行征得同意 - 具体情况具体分析。


它的评估速度快吗?我有30000个对象要进行此检查。 - alwbtc
尝试并查看。查看 timeit 模块。如果您认为很可能有大量的值是 None,则第一种方法可能会更快,否则使用第二种方法。 - Gareth Latty
好的,None值并不多。所以我将使用第二种方法。但我也想要由一行代码组成的代码。你不觉得一行语句更好吗? - alwbtc
3
不,可读性更好的代码更优秀。 - Tim Pietzcker
1
@alwbtc 一行代码并不代表什么,事实上,大多数情况下将复杂的东西压缩到一行反而是一个不好的迹象。首先要考虑可读性,然后是性能,最后才是简洁性。 - Gareth Latty
1
@alwbtc 我的回答提供了一个一行代码的解决方案,易读且高效,并且已经得到Lattyware的认可... :P 你可以看一下。 - Inbar Rose

7
在我的对象类中,您可以使用 override。
class Foo(object):
   def __getattribute__(self, name):
      if not name in self;
        return None;
      else:
        # Default behaviour
        return object.__getattribute__(self, name)

1
你的代码出现了 TypeError: argument of type 'Foo' is not iterable 错误。 - normanius

4
如果你想解决类的定义中出现的问题,例如 myobject 类(就像在 Black Diamond's answer 中所示),你可以简单地定义__getattr__函数来返回None
class Myobject:
    def __getattr__(self, name):
        return None

这个方法可行是因为当试图访问不存在的属性时,只有__getattr__才会被调用,而无论属性的名称如何,__getattribute__总是首先被调用。 (另请参阅此SO帖子。)
尝试一下:
myobject = Myobject()
print myobject.id 
myobject.id = 7
print myobject.id

3

Help on built-in function getattr in module builtins:

getattr(...)
    getattr(object, name[, default]) -> value

Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y. When a default argument is given, it is returned when the attribute doesn't exist; without it, an exception is raised in that case.

以下应该有效:

a = getattr(myobject, 'id', None)

0
try:
    a = myobject.id
except AttributeError:
    a = None

这样也可以工作,并且在我看来更清晰


我不是Python专家,但在我处理过的大多数编程语言中,“except”语句的执行成本都较低且影响不大。在像这样简单的情况下,我推荐使用“getattr”方法(假设这比较省时)。有些人能否进一步介绍一下“getattr”方法? - Gauthier Boaglio
过早的优化,好孩子,过早的优化。 - hd1
2
这不是过早优化。通常认为,使用异常来处理正常行为是不好的风格。 - francoisr
Python的异常并不是那么昂贵,这也是在解释器源代码中展示的方式。 - hd1

0
a=myobect.id if myobject else None

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接