在Python中,是否有更简洁的方法来链接空列表检查?

3

我有一个相当复杂的对象(反序列化的json,所以我对它没有太多控制),我需要检查它是否存在并迭代相当深的元素,所以现在我的代码像这样:

if a.get("key") and a["key"][0] and a["key"][0][0] :
    for b in a["key"][0][0] :
        #Do something

这样做虽然可以实现,但是看起来比较丑陋。似乎有更加优雅的方法来解决这个问题,那么什么是更加优雅的解决方案呢?

3个回答

14
try:
  bs = a["key"][0][0]
# Note: the syntax for catching exceptions is different in old versions
# of Python. Use whichever one of these lines is appropriate to your version.
except KeyError, IndexError, TypeError:   # Python 3
except (KeyError, IndexError, TypeError): # Python 2
  bs = []
for b in bs:

如果您不介意更长的代码行,那么您可以将其封装成一个函数:

def maybe_list(f):
  try:
    return f()
  except KeyError, IndexError, TypeError:
    return []

for b in maybe_list(lambda: a["key"][0][0]):

2
好的,忘记了Python的哲学是宁愿请求原谅也不要征得许可。我来自.NET,那里你尽可能避免抛出异常,这需要一些时间来适应。 - Davy8
1
你的代码出现了错误:请将 except KeyError, IndexError: 改为 except (KeyError, IndexError):。否则它只会捕获 KeyError 并将其存储在 IndexError 变量中。 - Denis Otkidach
此外,您需要捕获 TypeError,如果 bs['key'] 包含的内容不是序列,则会抛出该异常。 - Robert Rossney
1
@Denis:这取决于你使用的Python版本。我会添加两个版本。@Robert:谢谢。 - John Millikin

3
我会编写一个自定义的索引器函数,代码如下:
def safe_indexer(obj, *indices):
    for idx in indices:
        if not obj: break

        if hasattr(obj, "get"):
            obj = obj.get(idx)
        else:
            obj = obj[idx]

    return obj

使用方法:

a = {"key": {0: {0: "foo"} } };
print safe_indexer(a, "key", 0, 0)
print safe_indexer(a, "bad", 0, 0)

输出:

foo
None

嗯,我喜欢这个。如果我发现我经常遇到这种模式,我可能会使用它。但现在我只需要一个一次性的东西,所以John的更简单。 - Davy8
快速问题,我是Python新手,索引前面的*是什么意思? - Davy8
1
这意味着它是一个参数列表。换句话说,所有后续的参数都被合并成一个名为“indices”的列表。这样,您就不必显式地传递一个列表。相反,只需直接使用这些索引作为参数传递给safe_indexer即可。 - recursive
1
@Davy8 在索引前面的星号*将索引定义为序列类型参数,其中包含在调用函数时所有“额外的位置参数”。例如,在safe_indexer(a,“key”,0,1)的情况下,由于a是“obj”参数,因此会出现以下元组(“key”,0,0),并且有3个额外的位置参数。类似的表示法,带有两个星号,用于以字典形式传递的关键字参数。请参见http://docs.python.org/reference/compound_stmts.html#function-definitions 这是Python的一个非常有用的功能。 - mjv
值得注意的是,上述方法无法解决您的原始问题(list()没有.get()方法)。尽管如此,与try/except版本相比,我更倾向于编写类似以下代码的解决方案。 - James Antill
@James:如果对象没有get方法,那么可以使用subscription。这是可行的。 - recursive

2

这个怎么样:

try:
    for b in a['key'][0][0]:
        # do stuff.
except KeyError, TypeError, IndexError:
    # respond appropriately.

这将会捕获“做事情”的内部异常,而不仅仅是在找到列表时。 - John Millikin
它们应该在do stuff块内使用自己的try/except语句进行处理。 - Peter
除非您不想处理它们。 - recursive
+1 因为它比我之前使用的更好,但接受 John 的答案因为它更容易抽象化。 - Davy8
except KeyError, TypeError, IndexError: -> except (KeyError, TypeError, IndexError) - Denis Otkidach

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