My problem is a general one, how to chain a series of attribute lookups when one of the intermediate ones might return None
, but since I ran into this problem trying to use Beautiful Soup, I'm going to ask it in that context.
Beautiful Soup parses an HTML document and returns an object that can be used to access the structured content of that document. For example, if the parsed document is in the variable soup
, I can get its title with:
title = soup.head.title.string
My problem is that if the document doesn't have a title, then soup.head.title
returns None
and the subsequent string
lookup throws an exception. I could break up the chain as:
x = soup.head
x = x.title if x else None
title = x.string if x else None
but this, to my eye, is verbose and hard to read.
I could write:
title = soup.head and soup.head.title and soup.title.head.string
but that is verbose and inefficient.
One solution if thought of, which I think is possible, would be to create an object (call it nil
) that would return None
for any attribute lookup. This would allow me to write:
title = ((soup.head or nil).title or nil).string
but this is pretty ugly. Is there a better way?
The most straightforward way is to wrap in a try
...except
block.
try:
title = soup.head.title.string
except AttributeError:
print "Title doesn't exist!"
There's really no reason to test at each level when removing each test would raise the same exception in the failure case. I would consider this idiomatic in Python.