[Tutor] Re: streamlining a return statement

Michael Chermside mcherm@destiny.com
Mon, 09 Sep 2002 12:49:17 -0400


Erik Price wrote:
> I have a function in a chunk of code...
> 
> It works fine.  But I'm wondering whether returning an empty tuple is a 
> good idea...
> 
> Can someone criticize my code please?

Sure. But it's just my opinion... don't be afraid to trust your own 
instincts too: they seem pretty good.

 > Specifically the "return"
> statements -- the first part of the function is just the way I want it. 
>  Also, using "if matchobj" works but is that the preferred way to detect 
> whether a re.search() was successful?

Yes, it is.

 > (Testing for successful
> assignment, "if matchobj = re.search()", which I admit is a Perlish way 
> of looking at it, doesn't work.)
> 
> def atts_detect(line):
>     """searches a line for a tag with attributes and
>     returns a tuple of info about the tag if attributes are found"""
>     
>     import re
>     
>     # this regex ensures that the tag the kind we want
>     needle = r'(\s*)<(\w+)(\s+[-\w]+=[\'"].+[\'"])+(\s*/?>)'
>     regex = re.compile(needle)
>     
>     # a match object is only returned if search is successful
>     matchobj = regex.search(line)
>     if matchobj: return matchobj.groups()
>     # return an empty tuple if no matches found
>     else: return ()

I can see two approaches here, both of which are pretty good style. The 
first approach would be to use your code as is... making two changes. 
The first (and perhaps this is already how you do it) would be to use 
the truth value of the tuple returned as the indicator of whether a tag 
was found or not. So I mean something like this:

     def outer_program(line):
         atts = atts_detect(line):
         if atts:
             handle_a_tag( atts[0], atts[1], atts[2] )
         else:
             handle_no_tag()

The other approach would be, as you suggest, to use an exception:


     def outer_program(line):
         try:
             atts = atts_detect(line)
             handle_a_tag( atts[0], atts[1], atts[2] )
         except NoTagFoundException:
             handle_no_tag()

It's probably fairly easy to get a big debate going about the advantages 
of each, but I think the best answer has to do with how you think about 
the results. If there is supposed to be a tag on each line, and a 
missing tag indicates that the file is corrupt, then the exception 
approach definitely makes more sense. If you expect no tag found to be 
fairly common, then some people would say "never use an exception to 
handle a non-error condition". (I am not one of them -- the overhead of 
exceptions is larger than most normal statements, but not overwhelming 
in Python, even "for" loops use exceptions for termination.)

But in EITHER case, there's one thing missing. Your docstring should 
specify what happens in the unusual case. Go with one of these:

      """Searches a line for a tag with attributes. Returns a 4-element
      tuple (<whitespace preceeding tag>, <tagname>, <tag attributes>,
      <closing bracket>) if found, and an empty tuple if not found."""

      """Finds the first tag with attributes on the line. Returns a
      4-element tuple (<whitespace preceeding tag>, <tagname>, <tag
      attributes>, <closing bracket>). If no tag with attributes is
      found, it raises NoTagFoundException."""

Notice that my documentation of the tuple that is returned matches what 
is implemented in the code, but does NOT match your description. Was 
that a bug?

-- Michael Chermside