'Why this print statement is executed thhe oppsite order in this recursion?

 def isPalindrome(s):
    """Assumes s is a str
    Returns True if s is a palindrome; False otherwise.
     Punctuation marks, blanks, and capitalization are ignored."""

 def toChars(s):
    s = s.lower()
    letters = ''
    for c in s:
        if c in 'abcdefghijklmnopqrstuvwxyz':
            letters = letters + c
    return letters

 def isPal(s):
    print(' isPal called with', s)
    if len(s) <= 1:
        print(' About to return True from base case')
        return True
    else:
        answer = s[0] == s[-1] and isPal(s[1:-1])
        print(' About to return', answer, 'for', s)
        return answer
 return isPal(toChars(s))

print(isPalindrome('dogGo233214*d') )

This piece of code is from MIT OpenCourseWare. And I have a few problems with this piece of code. I made a simple test on the function by the print statement print(palindrome(‘dogGo32321421%&%&^d’)

The console shows:
isPal called with doggod
isPal called with oggo
isPal called with gg
isPal called with
About to return True from base case
About to return True for gg
About to return True for oggo
About to return True for doggod
True

1.answer = s[0] == s[-1] and insPal(s[1:-1]). How this assignment is interpreted? (Why make sense) Can I put it together like this: these two expressions are boolean-valued, as two conjuncts. It’s about revaluating the first one as true(like an if statement), then revaluating the second one, which itself is a function, returning a value being assigned to the answer. If so, what if these two boolean-valued expression both return values, which one should be assigned?

  1. Assume the above assignment makes sense, I’m OK with the first five lines in the console as the function is called recursively. But the last four lines, why the print statements in the else clause are executed in the opposite order of the original. Another way to ask about this is what happened to the first print statement, when the function is called recursively. I deduce this has something to do with the interpreter searching back stack frames for the value of “s”. Can someone help explain the whole course of this recursive function isPal(), please ?


Solution 1:[1]

  1. and does not represent normal day speech as in "apples and oranges" but a boolean expression. If both "sides" of and are true, then the result is true. For or the result is true if at least one of the sides is true. So answer is true if s[0] has the same value as s[-1] and insPal(s[1:-1]) is true, otherwise it is false (it is a palindrome if first equals last and everything inside is a palindrome).

Note that both and and or are "lazy", so for and the right hand side will not be evaluated if the left side is false, and for or the right hand side will not be evaluated if the left side is true.

  1. Why would you expect a different order? Each call basically prints "before", calls recursively, and when that completes prints "after". So if you manually step through the following function you will see that it should print
Before 1
Before 2
Before 3
No recurse on 3
After 3
After 2
After 1
def recurse(val):
    print("Before", val)
    if val == 3:
        print("No recurse on", val)
    else:
        recurse(val + 1)
    print("After", val)
    
recurse(0)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1