我有一个复杂的多维可测对象(比如列表)。我想编写函数来访问由元组索引表示的元素的值。维度的数量本身是可变的。如果元素不存在,它也应该返回None
:
l = [[[1, 2],
[3, 4]],
[[5, 6],
[7, 8]]]
access(l, (0, 0, 0)) # prints 1
access(l, (0, 1, 1)) # prints 4
access(l, (1, 1)) # prints [7, 8]
access(l, (0, 1, 2)) # prints None
access(l, (0, 0, 0, 0)) # prints None
我如何实现这一目标?
答案 0 :(得分:2)
雅罗斯拉夫答案的另一种方法,在索引列表之前,你要求宽恕而不是许可:
def access(obj, indexes):
try:
return reduce(list.__getitem__, indexes, obj)
except Exception:
return None
这不是万无一失的;它会假设access
将按预期使用,如果有人决定尝试None
,您不介意回复access(1, 1)
。
答案 1 :(得分:2)
正如切普纳所暗示的那样,这并不是一件难事,但要小心一点。仅当异常为None
时才返回IndexError
,并且尝试的内容更具体。像
def access(obj, indexes):
a = obj
for i in indexes:
try:
a = a[i]
except IndexError:
return None
# except TypeError:
# when you try to index deeper than the object supports
# a is not constrained to be a scalar, it may still be dimensional
# if insufficient indexes were passed.
return a
如果在某些级别你有一个dict而不是列表,这将是有效的。即
x = access(obj, (3, 'default', 'range', 1))
将适用于适当的对象,如果一个或两个级别不是dict或者没有密钥,则会抛出异常。我使用了非常类似的内容来访问JSON.load
结果。您可能还希望在None
上返回KeyError
,这是与IndexError
相当的字典。
您可以添加isinstance(a, list)
或hasattr(a, '__iter__')
等测试,以便更加确定您正在为预期目标建立索引。
答案 2 :(得分:1)
您可以使用reduce()
执行此操作:
def access(obj, indexes):
return reduce(lambda subobj, index: subobj[index] if isinstance(subobj, list) and index < len(subobj) else None, indexes, obj)
或者正如@chepner指出的那样,您可以使用def
使其更具可读性:
def access(obj, indexes):
def _get_item(subobj, index):
if isinstance(subobj, list) and index < len(subobj):
return subobj[index]
return None
return reduce(_get_item, indexes, obj)