3
\$\begingroup\$

I am a beginner coder learning Python. This is a simple exercise from the thinkpython book. I would like to know if this circular referencing to restart the program the best way to do it. Also if you have other comments as to how to improve the code, please feel free to suggest.

def program_restart():
    print("Would you like to try again? ")
    prompt = input("type 'Y' to continue and 'N' to exit:\n")
    if prompt =="Y" or prompt == "y":
        user_input()
    return

def check_fermat(a,b,c,n):
    if a**n+b**n == c**n:
        print("Holy Smokes, Fermat was wrong!")
        print("---------------------------")
    else:
        print("No, that does not work!")
        print("---------------------------")
    program_restart()

def user_input():
    print("Let's see if Fermet was right. He claims that a^n+b^n=c^n cannot be True!")
    while True:
        try:
            a = int(input('Give a positive number bigger than 2 for "a":\n'))
        except ValueError:
            print ("Not a string, a number please.")
            continue

        if a > 2:
            a = int(a)
            break

    while True:
        try:
            b = int(input('Give a positive number bigger than 2 for "b":\n'))
        except ValueError:
            print ("Not a string, a number please.")
            continue

        if b > 2:
            b = int(b)
            break

    while True:
        try:
            c = int(input('Give a positive number bigger than 2 for "c":\n'))
        except ValueError:
            print ("Not a string, a number please.")
            continue

        if c > 2:
            c = int(c)
            break

    while True:
        try:
            n = int(input('Give a positive number for the exponent "n":\n'))
        except ValueError:
            print ("Not a string, a number please.")
            continue

        if n > 2:
            n = int(n)
            break

    check_fermat(a,b,c,n)

user_input()
\$\endgroup\$
0

3 Answers 3

3
\$\begingroup\$

Mathematics

Fermat's Last Theorem states:

No three positive integers a, b, and c satisfy the equation an + bn = cn for any integer value of n greater than 2.

That's not what your code does. Why are you requiring that a, b, and c be greater than 2, when they only need to be greater than 0? Why does your prompt for n only say Give a positive number for the exponent "n" when it should say Give an integer greater than 2 for the exponent "n"?

And who is "Fermet"?

Flow control

Function calls should not be used as gotos. Functions should accept parameters and return a result. Your calls to user_input() and program_restart(), on the other hand, expect the execution to never return to the caller. To see the problem with that, say "yes" a few times to retry the calculation, then hit CtrlC to abort. You'll see the stack trace, which indicates that the ever-deepening stack is keeping track of all the calls, in anticipation for the opportunity to return control to the caller. Since control never returns, the stack grows deeper and would eventually overflow.

Suggested solution

def prompt_yesno(prompt):
    return input(prompt) in 'Yy'

def prompt_int(prompt, min=None):
    while True:
        try:
            ans = int(input(prompt))
            if min is None or min <= ans:
                return ans
        except ValueError:
            print("Input must be an integer.")

def is_fermat_counterexample(a, b, c, n):
    return n > 2 and a**n + b**n == c**n

def fermat_demo():
    print("Let's see if Fermat was right.")
    print("He claims that a^n + b^n = c^n cannot be true for any n > 2.")
    a = prompt_int('Give a positive integer for "a": ', 1)
    b = prompt_int('Give a positive integer for "b": ', 1)
    c = prompt_int('Give a positive integer for "c": ', 1)
    n = prompt_int('Give an integer bigger than 2 for exponent "n": ', 3)
    print("Holy smokes, Fermat was wrong!"
          if is_fermat_counterexample(a, b, c, n) else
          "No, that does not work!")

while True:
    fermat_demo()
    if not prompt_yesno("Would you like to try again?\n"
                        "Type 'Y' to continue and 'N' to exit: "):
        break

A more interesting demonstration

It would be a more satisfying demonstration if the computer asked the user for a, b, and n, then solved for c, showing that c is not an integer.

\$\endgroup\$
2
\$\begingroup\$

Some PEP-8 details:

1.- According PEP-8 between each function you have to have two blank lines.

2.- Space between parameters (ie def check_fermat(a, b, c, n): instead of def check_fermat(a,b,c,n):. Source

3.- End of file it should be an new empty line.

4.- There is an extra space between print and ("Not a string, a number please.")

Related with the code;

5.- Instead of checking for 'y' or 'Y' you can apply lowercase to user input ( if str.lower(prompt) == "y":)

6.- a = int(a) is redundant, same for b, c and n.

7.- According your code n it should be higher than 2, is this correct?

8.- You are repeating the user input code, you should create a new function for that.

9.- Check fermat should just do that, so, program_restart should be handled in another place.

10.- That return on program_restart is unnecessary.

11.- If inside program_restart you have another call to user_input and inside this second user_input another call to program_restart and so on.. (You are falling into a recursion. Recursion per se is not bad, but in this case it is because you are trying to just repeat the program, no to solve some problema trough recursion), a better approach is control that with a loop.

12.- Add if __name__ == '__main__':

def program_restart():
    print("Would you like to try again? ")
    prompt = input("type 'Y' to continue or any other character to exit:\n")
    return str.lower(prompt) == "y"


def check_fermat(a, b, c, n):
    if a ** n + b ** n == c ** n:
        print("Holy Smokes, Fermat was wrong!")
    else:
        print("No, that does not work!")

    print("---------------------------")


def ask_number(text, bigger_than=0):
    number = bigger_than - 1
    while number <= bigger_than:
        try:
            number = int(input(text))
        except ValueError:
            print("Please write a valid number.")

    return number


def user_input():
    run_program = True

    while run_program:
        print("Let's see if Fermat was right. He claims that a^n+b^n=c^n cannot be True!")
        a = ask_number(text='Give a positive number bigger than 2 for "a":\n', bigger_than=2)
        b = ask_number(text='Give a positive number bigger than 2 for "b":\n', bigger_than=2)
        c = ask_number(text='Give a positive number bigger than 2 for "c":\n', bigger_than=2)
        n = ask_number(text='Give a positive number for the exponent "n":\n')
        check_fermat(a, b, c, n)

        run_program = program_restart()


if __name__ == '__main__':
    user_input()
\$\endgroup\$
1
\$\begingroup\$

the problem with circular referencing to restart the program is that you call stack will get bigger and bigger and you'll get an exception after 340~ tries.

you should use a loop instead:

while 1:
    user_input()
\$\endgroup\$
1
  • 1
    \$\begingroup\$ while True would be more idiomatic than while 1. \$\endgroup\$ Commented Feb 24, 2017 at 22:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.