我经常看到这种模式以容错的方式浏览字典:
a.get('k1', {}).get('k2', {}).get('k3', '')
但是,如果中间对象是类实例而不是字典,则这是不可能的。是否有简洁的方法(如下):
a?.method1()?.method2()?.method3()...
扩展为:
if a is None:
return None
obj = a.method1()
if obj is None:
return None
obj = obj.method2()
if obj is None:
return None
obj = obj.method3()
return obj
我想有可能使用构建器模式的某些变体,但如果上述方法位于不受用户控制的API中,那么这是不可行的。
答案 0 :(得分:1)
最接近的等价物是使用getattr
并使用默认值:
>>> class A: pass
...
>>> a = A()
>>> getattr(getattr(getattr(a, 'k1', A()), 'k2', A()), 'k3', A())
<__main__.A object at 0x104a7de10>
然而,上面这个结构对我来说有很大的代码味道...为什么你不能依赖具有属性的对象?
虽然,如果你链接方法调用,那么你可能想要一个默认的callable,它返回一些方便的默认值,例如:
>>> def empty(): return A()
...
>>> getattr(getattr(getattr(a, 'k1', empty)(), 'k2', empty)(), 'k3', empty)()
<__main__.A object at 0x104a7dda0>
>>>
如果需要关注,则可以使用reduce
:
>>> def getter(obj, k):
... return getattr(obj, k, A())
...
>>> functools.reduce(getter, ('k1','k2','k3'), a)
<__main__.A object at 0x104a7dda0>
老实说,我会使用中间变量并显式调用方法并使用异常处理,这将是更多的Pythonic方式。
答案 1 :(得分:0)
使用eval让我活着,但我偶尔喜欢在有嵌套属性的情况下使用try ... eval。
try:
val = eval("obj.{a1}.{a2}.{a3}".format(a1=a1, a2=a2, a3=a3))
except AttributeError:
val = default
print('Attribute not found')
except Exception as e:
print('Something went wrong')
这看起来比多个getattr的imo好,我喜欢捕获AttributeErrors。此外,它非常强大,因为你可以做很多字符串操作来获得你想要的东西。我也觉得这与&#34;请求原谅&#34;滑稽特点。