以优雅的方式编写业务规则链接可能不存在的属性

时间:2011-12-10 15:27:45

标签: python business-rules

看看这段代码:

>>> class c(object):
...    pass
... 
>>> a=c()
>>> if a.b.c:
...    print 'hello'
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'c' object has no attribute 'b'

安静!这不是问题。请继续阅读:

当有人开发企业软件时(例如django)必须编写业务规则。 此规则类似于

if invoice.customer.adress.country in ...:
    invoice.makeSomeSpecialOffer()

但有时候,表达中涉及的一个对象不存在。然后,避免错误我可以将句子重写为:

if invoice.customer and
   invoice.customer.adress and
   invoice.customer.adress.country and
   invoice.customer.adress.country in ...

这不太可读! (你也可以尝试使用hasattr,但也不太可读)。

我的工作周围是if if statement in try,但有一种更优雅或pythatonic方式来避免这种错误?你喜欢哪种技术?

2 个答案:

答案 0 :(得分:2)

要检查链式属性,以下函数可能有所帮助:

def get_chainedattr(parobj, *args):
    try:        
        ret = parobj
        for arg in args:
            ret = getattr(ret, arg)   
        return ret
    except AttributeError:
        return None

我不确定它是否更具可读性,但通过使用此功能,您的示例可以写为:

if get_chainedattr(invoice, "customer", "adress", "country") in ...:
   invoice.makeSomeSpecialOffer()

答案 1 :(得分:1)

  

这不太可读! (你也可以尝试使用hasattr但是更少   可读的)。

另一个选项是封装在try'except块中。

try:
    if invoice.customer.adress.country in ...:
        invoice.makeSomeSpecialOffer()
except AttributeError:
    None

您可以进行像hasattr这样的主动检查,也可以像try-except那样进行反应性检查。可读性是一种感知,并且这种方法都是可行的。