one to many (passing variables)

Steven D'Aprano steve+gmane at pearwood.info
Fri Jul 25 23:43:20 EDT 2014


On Fri, 25 Jul 2014 18:47:55 -0700, C.D. Reimer wrote:

> On 7/24/2014 2:58 AM, Ben Finney wrote:
>> Here is an article on good API design; the principles apply to Python
>> <URL:http://blog.isnotworking.com/2007/05/api-design-guidelines.html>.
>> You know your API and its requirements better than we; see whether that
>> sheds any light on improvements to make.
> Thank you for the link. I'm curious about one item mentioned in the
> article: "Avoid return values that Demand Exceptional Processing: return
> zero-length array or empty collection, not null"
> 
> Isn't a zero-length array, empty collection and null all the same thing?

No.

Since an array is a kind of collection, a zero-length array is an empty
array, which is an empty collection. But null is not the same thing. In
Python terms, it is the difference between:

    return []

    return None


While I agree that in general it is better to return (say) a consistent list
result, sometimes you need an exceptional result that is different from
the "empty" or "zero" result. In that case, there are two obvious ways to
deal with exceptional circumstances:

- raise an exception, e.g. "spam".index("e") raises

- return a special result, e.g. "spam".find("e") returns -1


Raising an exception is the obvious way to handle it, but exception handling
is a little less convenient than testing for a special value. Hence the
find() convenience method. However, find() makes a silly mistake: it
returns -1 to indicate Not Found, and -1 is acceptable as an index. So if
you forget to test for the Not Found case, you might write this:

    p = some_string.find(needle)
    return another_string[p]


which is wrong. If find() returns -1, another_string[p] returns the *last*
character in the string, which is probably not what you want.

A better API is that of the regular expression module. re.search() and
re.match() return either a match object, or None if the regex doesn't match
at all. So if you forget to test for None, and blindly try to treat the
result as if it where a match object, you will immediately get an exception
instead of invalid results:

    mo = re.search(text, needle)
    return mo.group()  # will raise if mo is None

In summary:

* if you're returning a list of results, deal with no results 
  by returning an empty list [] rather than None;

* if you need to distinguish between the empty list case and 
  some exceptional situation, the best way is to raise an 
  exception;

* if you don't wish to raise an exception, it is better to 
  return some result which clearly cannot be mistaken for, or
  accidentally used as, a regular non-exceptional result;

* e.g. if your function normally returns an integer, better to
  return None as a "no result exists" than 0 or -1, since they
  are valid integers and None isn't.


-- 
Steven





More information about the Python-list mailing list