dbf.py API question concerning Index.index_search()

Steven D'Aprano steve+comp.lang.python at pearwood.info
Thu Aug 16 02:52:10 CEST 2012


On Wed, 15 Aug 2012 16:26:09 -0700, Ethan Furman wrote:

> Indexes have a new method (rebirth of an old one, really):
> 
>    .index_search(
>       match,
>       start=None,
>       stop=None,
>       nearest=False,
>       partial=False )
[...]

Why "index_search" rather than just "search"?


> The question is what should the return value be?
> 
> I don't like the usual pattern of -1 meaning not found (as in
> 'nothere'.find('a'))

And you are right not to. The problem with returning -1 as a "not found" 
sentinel is that if it is mistakenly used where you would use a "found" 
result, your code silently does the wrong thing instead of giving an 
exception.

So pick a sentinel value which *cannot* be used as a successful found 
result.

Since successful searches return integer offsets (yes?), one possible 
sentinel might be None. (That's what re.search and re.match return 
instead of a MatchObject.) But first ensure that None is *not* valid 
input to any of your methods that take an integer.

For example, if str.find was changed to return None instead of -1 that 
would not solve the problem, because None is a valid argument for slices:

p = mystring.find(":")
print(mystring[p:-1])  # Oops, no better with None

You don't have to predict every imaginable failure mode or defend against 
utterly incompetent programmers, just against the obvious failure modes.

If None is not suitable as a sentinel, create a constant value that can't 
be mistaken for anything else:

class NotFoundType(object):
    def __repr__(self):
        return "Not Found"
    __str__ = __repr__

NOTFOUND = NotFoundType()
del NotFoundType


and then return that.


(By the way, I'm assuming that negative offsets are valid for your 
application. If they aren't, then using -1 as sentinel is perfectly safe, 
since passing a "not found" -1 as offset to another method will result in 
an immediate exception.)


> The other option is returning a (number, bool) tuple -- safer, yet more
> boring... ;)

Boring is good, but it is also a PITA to use, and that's not good. I 
never remember whether the signature is (offset, flag) or (flag, offset), 
and if you get it wrong, your code will probably fail silently:

py> flag, offset = (23, False)  # Oops, I got it wrong.
py> if flag:
...     print("hello world"[offset+1:])
...
ello world


   

-- 
Steven


More information about the Python-list mailing list