0

Take a look to this code:

>>> 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'

Quiet! this is not the question. Please, continue reading:

When someone develops enterprise software (with django for example) must write business rules. This rules looks like

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

But some times, one of the objects involveds on expression don't exists. Then, to avoid errors I sould rewrite sentence as:

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

This is less readable! (also you can try with hasattr but is alse less readable).

My work arround is enclose if statement into a try, but there is a more elegant or pythatonic way to avoid this kind of errors? Which is your favorite technique?

dani herrera
  • 48,760
  • 8
  • 117
  • 177
  • This may be a duplicate of http://stackoverflow.com/questions/610883/how-to-know-if-an-object-has-an-attribute-in-python – ditkin Dec 10 '11 at 15:36
  • @ditkin, thanks about this link!. But my question is not to know if a object has an attribute, is how to write code in an elegant way chaining possible missing attributes. I have changed title. Thanks a lot. – dani herrera Dec 10 '11 at 15:43
  • What kinds of objects are `invoice`, `custom`, `address` etc.? – Noufal Ibrahim Dec 12 '11 at 11:17

2 Answers2

2

To check chained attributes the following function might help:

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

I am not sure if it is more readable but by using this function your example can be written as:

if get_chainedattr(invoice, "customer", "adress", "country") in ...:
   invoice.makeSomeSpecialOffer()
Bora Caglayan
  • 151
  • 1
  • 7
  • This is out-rightly wrong. Please read the section [except](http://docs.python.org/howto/doanddont.html#except) in the article Idioms and Anti-Idioms in Python. – Abhijit Dec 12 '11 at 08:34
  • Thanks, I forgot to add the exception name. Do you see a problem in the answer now? – Bora Caglayan Dec 12 '11 at 11:14
  • I liked your approach but somehow the way you caught the exception was not right. After you corrected it, this is indeed good. – Abhijit Dec 12 '11 at 11:35
1

This is less readable! (also you can try with hasattr but is alse less readable).

Another option would be to enclose in a try 'except block.

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

Either you can make a proactive check like hasattr or a reactive like try-except. Readability is a perception and both the approach is except-able.

Abhijit
  • 62,056
  • 18
  • 131
  • 204
  • Yes, this is my work around as I explain in question: "My work arround is enclose if statement into a try" – dani herrera Dec 10 '11 at 17:01
  • @danihp I just read the above post, but unfortunately this is something you shouldn't do. Please read the link in my comment. – Abhijit Dec 12 '11 at 08:35
  • Sorry. I don't speack english correctly, That I want to say is: I know this is a solution as I explain in my question, I ask for other ways to do this. You talk about 'another option' but this is not another option, this option is enclosed in question text because this I can't mark your question as right. I check @boracaglayan answer as solution that is more close to question statement. Thanks about your time. Also, where is the link of your comment? – dani herrera Dec 12 '11 at 09:16
  • Comment next to the above post. In brief you should not catch an exceptions unconditionally. – Abhijit Dec 12 '11 at 09:20
  • Sorry, I have not a way to check both questions as solution. Is not easy for me. I uncheck bora answer as solution to keep both answere as the same level. Also, where you write None, is not [pass](http://docs.python.org/tutorial/controlflow.html#pass-statements) more pythatonic? – dani herrera Dec 12 '11 at 09:40