That is a programmatic solution to a puzzler from Car Talk, its summary is:I noticed that the last 4 digits were palindromic. I drove a mile,  and the last 5 were palindromic. I drove another mile and the middle 4  were palindromic, and the ends were not involved. And then one mile  later, all 6 digits were palindromic.def is_palindrome(string):    Finds if a string is a plaindrome or not.       string: str       returns: bool           return string == string[::-1]def find_puzzle_number():    Finds the number which was first seen.       prints: int           guess = 100000      # the odometer shows only 6 numbers,    # therefore 999999 is the last number to test.    while guess < 1000000:        if is_palindrome(str(guess)[2:]):  # last 4 numbers.                   if is_palindrome(str(guess + 1)[1:]):  # last 5 numbers.                if is_palindrome(str(guess + 2)[1:5]):  # middle 4 numbers.                         if is_palindrome(str(guess + 3)):                        print(guess)        guess = guess + 1print('These are the possible odometer readings: ')find_puzzle_number()Notes:I'm a hobbyist and a beginner.I don't only want to optimize the code, but also my skills and style. Therefore any notes, advice and suggestions aren't only welcomed, but also encouraged!
The Palindromic Odometer Puzzler: A Programmatic Solution
python;beginner;algorithm;python 3.x;palindrome
The documentation   string: str   returns: boolis pretty obvious. I would skip it. The rest of the documentation can be more idiomatically written asReturn whether input sequence is a palindrome.(note palindrome, not plaindrome). I removed the term string because many sequence types can be palindromic, like [1, 2, 3, 2, 1].find_puzzle_number should yield, not print, its values.I would change the documentation to specify the rules the output satisfy.def find_puzzle_number():    Generates 6-digit integers, x, where all of    * the last 4 digits of x,    * the last 5 digits of x+1,    * the middle 4 digits of x+2, and    * all 6 digits of x+3    are palindromes.        guess = 100000    # the odometer shows only 6 numbers,    # therefore 999999 is the last number to test.    while guess < 1000000:        if is_palindrome(str(guess)[2:]):  # last 4 numbers.            if is_palindrome(str(guess + 1)[1:]):  # last 5 numbers.                if is_palindrome(str(guess + 2)[1:5]):  # middle 4 numbers.                    if is_palindrome(str(guess + 3)):                        yield guess        guess = guess + 1The while should become a for# 6 digit numbersfor guess in range(10**5, 10**6):Then the if chain of is_palindromes can be simplified:valid = (    is_palindrome(str(guess + 0)[2:]) and    is_palindrome(str(guess + 1)[1:]) and    is_palindrome(str(guess + 2)[1:5]) and    is_palindrome(str(guess + 3)))if valid:    yield guessNow note something bad: guess + 3, can overflow. Either you want to clamp the code so that guess + 3 < 10**6, or you want to perform modular arithmetic.Further, you don't know that 10**5 is a valid lower bound: 000000 is a valid reading. You can use format(guess, 06) to pad like this.If you care about speed, PyPy makes the code run in about a tenth the time.def is_palindrome(seq):    Return whether input sequence is a palindrome.    return seq == seq[::-1]def find_puzzle_number():    Generates 6-digit integers, x, where all of    * the last 4 digits of x,    * the last 5 digits of x+1,    * the middle 4 digits of x+2, and    * all 6 digits of x+3    are palindromes.        def as_reading(x):        return format(x % 10**6, 06)    # 6 digit numbers    for guess in range(10**6):        valid = (            is_palindrome(as_reading(guess + 0)[2:]) and            is_palindrome(as_reading(guess + 1)[1:]) and            is_palindrome(as_reading(guess + 2)[1:5]) and            is_palindrome(as_reading(guess + 3))        )        if valid:            yield guessprint('These are the possible odometer readings: ')for solution in find_puzzle_number():    print(solution)Note that there are simple optimizations you can apply. For instance, you can easily iterate over only those values for which guess + 3 is a palindrome by construction - this reduces the values to iterate over from \$10^6\$ to \$10^3\$.for guess_digits in range(10**3):    # guess + 3 is a palindrome    # NOTE: relies on correct handling of wrapping    guess = guess_digits + int(format(guess_digits, 06)[::-1]) - 3This makes the code basically instantaneous, so if optimizations were pointless to apply before they're most certainly pointless to apply now.