views:

280

answers:

6

I'm often having code written as follows

try:
  self.title = item.title().content.string
except AttributeError, e:
  self.title = None

Is there a quicker way of dealing with this? a one-liner?

+3  A: 

What exceptions are you getting from item.title()? The bare except (horrible practice!) doesn't tell us. If it's an AttributeError (where item doesn't have a title method, for example),

self.title = getattr(item, 'title', lambda: None)()

might be the one-liner you seek (but performance won't be enormously different, mind you;-).

Edit: as the OP entirely changed the question (it was originally just using self.title(), it's now using self.title().content.string, and does specifically catch AttributeError rather than using a bare except), the previous version of this answer of course doesn't apply any more. The proper answer now is: attempting a one-liner is an absurd approach, when the chain of attribute references &c keeps growing longer and longer (how many will there be next time, nine? Since they jumped from one to three with the first edit...;-).

And with no idea of which of the many elementary operations expressed by that long, Law of Demeter-scoffing chain of references might raise the AttributeError, any attempt at optimization would be flying rather blind, too.

Alex Martelli
@Alex thanks!! I changed the code in the question, not sure how I can adapt the one liner. item is a BeautifulSoup node.
RadiantHex
@RadiantHex, that one-liner doesn't help w/a long chain of attribute references. What's the problem your try/except wards against -- no `title` method, no `content` attribute in its results, no `string` attribute in `content`...? If you're simultaneously warding against multiple such problems, no one-liner makes sense; if just one, then a `getattr` at that spot, with the right default value, might (microscopically) help, but don't expect solid performance gains!
Alex Martelli
@Alex: thank you so much! and thanks for adding interesting content to the answer!
RadiantHex
A: 
  • You should know ahead of time whether or not an object has a given attribute. It is a bad sign when you have an object but do not know what it is.

  • You retrieve three attributes in your try block. A try block should contain as little code as possible. You could let an error pass silently if a different attribute is missing than you think.

  • getattr lets you have a default value, but typically should not be used for this purpose.

Mike Graham
+2  A: 

In one line, although I’d only recommend this in 5% of all use cases.

self.title = item.title().content.string if hasattr(item, 'title') else None
Debilski
A: 

Your question focuses on the speed of this operation. First, why do you think this operation is slow? Second, there isn't a faster way to access the attributes. Even trying to avoid the catch by checking for the attribute first will likely be slower, simply because of the Python conditionals needed to check if the attribute exists. Also, hasattr attempts to read the attribute, and catches AttributeError, returning False. So checking for the attribute will actually involve a try/except anyway.

Ned Batchelder
A: 

How about a two-liner?

try: self.title = item.title().content.string
except AttributeError, e: self.title = None

Denser, less readable, but you really save two keypresses!

ΤΖΩΤΖΙΟΥ
This is, of course, awful!
Mike Graham
Oh, definitely, Mike. :)
ΤΖΩΤΖΙΟΥ
+2  A: 

Assuming the AttributeError happens on string:

self.title = getattr(item.title().content, 'string', None)
drr