Python's "only one way to do it" philosophy isn't good?

Josiah Carlson josiah.carlson at sbcglobal.net
Sat Jun 9 18:52:32 EDT 2007


Alexander Schmolck wrote:
> Josiah Carlson <josiah.carlson at sbcglobal.net> writes:
> 
>> James Stroud wrote:
>>> Terry Reedy wrote:
>>>> In Python, you have a choice of recursion (normal or tail)
>>> Please explain this. I remember reading on this newsgroup that an advantage
>>> of ruby (wrt python) is that ruby has tail recursion, implying that python
>>> does not. Does python have fully optimized tail recursion as described in
>>> the tail recursion Wikipedia entry? Under what circumstances can one count
>>> on the python interpreter recognizing the possibility for optimized tail
>>> recursion?
>> Note that Terry said that you could do normal or tail recursion, he didn't
>> claim that either were optimized.  
> 
> Well yeah, but without the implication how do the two words "or tail" add to
> the information content of the sentence?

Normal and tail recursion are different, based upon whether or not one 
can technically considered to be done with the stack frame.

def normal(arg):
     if arg == 1:
         return 1
     return arg * normal(arg-1)

def tail(arg, default=1):
     if arg == 1:
         return arg * default
     return tail(arg-1, default*arg)


>> As for why tail calls are not optimized out, it was decided that being able
>> to have the stack traces (with variable information, etc.) was more useful
>> than offering tail call optimization
> 
> I don't buy this. What's more important, making code not fail arbitrarily (and
> thus making approaches to certain problems feasible that otherwise wouldn't
> be) or making it a be a bit easier to debug code that will fail arbitrarily?
> Why not only do tail-call optimization in .pyo files and get the best of both
> worlds?

I didn't make the decisions, I'm just reporting what was decided upon.

Personally, I have never found the lack of tail call optimization an 
issue for two reasons.  The first is because I typically write such 
programs in an iterative fashion.  And generally for recursion for which 
tail call optimization doesn't work (the vast majority of recursive 
algorithms I use), I typically write the algorithm recursively first, 
verify its correctness, then convert it into an iterative version with 
explicit stack.  I find it is good practice, and would be necessary 
regardless of whether Python did tail call optimization or not.


>> (do what I say).
> 
> Where did you say run out of memory and fail? More importantly how do you say
> "don't run out of memory and fail"?

By virtue of Python's underlying implementation, Python "does what I 
say", it doesn't "do what I mean".  While I may not have explicitly 
stated "run out of stack space", the underlying implementation *has* 
limited stack space.  You are stating that when you write a tail 
recursive program, you want Python to optimize it away by destroying the 
stack frames.  And that's fine.  There are tail-call optimization 
decorators available, and if you dig into sourceforge, there should even 
be a full patch to make such things available in a previous Python.

However, Python is not Lisp and is not partially defined by infinite 
recursion (see sys.setrecursionlimit() ).  Instead, it is limited by the 
C call stack (in CPython), and makes guarantees regarding what will 
always be available during debugging (the only thing that optimization 
currently does in Python at present is to discard docstrings).  If you 
want to change what is available for debugging (to make things like tail 
call optimization possible), you are free to write and submit a PEP.

In the mean time, you may need to do some source conversion.


  - Josiah



More information about the Python-list mailing list