如何链接可能在Python中返回None的属性查找?


问题内容

我的问题是一个一般的问题,当中间一个可能返回时,如何链接一系列属性查找None,但是由于我在尝试使用Beautiful
Soup时遇到了这个问题,因此我将在这种情况下提出该问题。

Beautiful
Soup解析HTML文档并返回一个对象,该对象可用于访问该文档的结构化内容。例如,如果解析的文档在变量中soup,则可以使用以下命令获取其标题:

title = soup.head.title.string

我的问题是,如果文档没有标题,则soup.head.title返回None,随后的string查找将引发异常。我可以将链分解为:

x = soup.head
x = x.title if x else None
title = x.string if x else None

但是在我看来,这是冗长且难以阅读的。

我可以写:

title = soup.head and soup.head.title and soup.title.head.string

但这是冗长且低效的。

如果可以想到的一种解决方案(我认为是可行的)将是创建一个对象(称为nil),该对象None将为任何属性查找返回。这可以让我写:

title = ((soup.head or nil).title or nil).string

但这很丑。有没有更好的办法?


问题答案:

您可能可以使用reduce此功能:

>>> class Foo(object): pass
... 
>>> a = Foo()
>>> a.foo = Foo()
>>> a.foo.bar = Foo()
>>> a.foo.bar.baz = Foo()
>>> a.foo.bar.baz.qux = Foo()
>>> 
>>> reduce(lambda x,y:getattr(x,y,''),['foo','bar','baz','qux'],a)
<__main__.Foo object at 0xec2f0>
>>> reduce(lambda x,y:getattr(x,y,''),['foo','bar','baz','qux','quince'],a)
''

在python3.x中,我认为它reduce已移至functools:(


我想您也可以使用更简单的功能来做到这一点:

def attr_getter(item,attributes)
    for a in attributes:
        try:
            item = getattr(item,a)
        except AttributeError:
            return None #or whatever on error
    return item

最后,我想 最好的 方法是:

try:
   title = foo.bar.baz.qux
except AttributeError:
   title = None