Avoiding argument checking in recursive calls

Gabriel Genellina gagsl-py2 at yahoo.com.ar
Tue Feb 10 23:31:16 EST 2009


En Tue, 10 Feb 2009 23:58:07 -0200, Steven D'Aprano  
<steven at remove.this.cybersource.com.au> escribió:

> I sometimes write recursive functions like this simple factorial:
>
>
> def fact(n):
>     if n < 0: raise ValueError
>     if n = 0: return 1
>     return fact(n-1)*n
>
> At the risk of premature optimization, I wonder if there is an idiom for
> avoiding the unnecessary test for n <= 0 in the subsequent recursive
> calls? For the sake of the argument, let's pretend the test is expensive
> and I have a good reason for wanting to avoid it on subsequent calls :)
>
>
>
> I've done this:
>
> def _fact(n):
>     if n = 0: return 1
>     return _fact(n-1)*n
>
> def fact(n):
>     if n < 0: raise ValueError
>     return _fact(n)
>
> but that's ugly. What else can I do?

I don't think it's ugly; you have an implementation (_fact) and its public  
interfase (fact). In 'fact' you could check that n is actually an integer  
(an implicit precondition, your algorithm doesn't finish in other case)  
and whatever validation is also required. Perhaps its arguments come from  
user input and you need stricter tests, or convert from other type (like  
float->int).
On the other hand, '_fact' is private and you can assume their arguments  
are exactly what you require.
In Pascal I would have used a nested _fact function; in Python it isn't as  
efficient so I'd write it as your own example.

This is a rather used idiom - in the Python C API, by example, usually you  
see a public function PyFoo_DoSomething(PyObject* obj) and a private one  
_PyFoo_DoSomething(double x) (assume a function like sqrt, number ->  
float). The public one takes a generic Python object, checks its type,  
converts it to a C "double" value, and if all went OK, finally calls the  
private implementation passing that value.

-- 
Gabriel Genellina




More information about the Python-list mailing list