Finding the next perfect number after n This script is for a student who has never programmed before. The goal is that she can quickly start to understand what is going on and start to tinker with it.

As I am not very familiar with Python I wonder whether I am breaking any important style paradigm and whether there are things that can make the code further readable, by making it shorter or simpler.

# Define function
def npn(n):
    """ Find the next perfect number after integer n
    """
    org = n = abs(n)
    while True:
        n += 1
        # Keep track of sum of the positive divisors
        spd = 1
        # Now check (other) possible divisors.
        # Note that subset of divisors to check can be greatly reduced...
        # which will increase efficiency
        for i in range(2, n):
            # Check divisibility with the modulo operator
            if (n % i == 0):
                spd += i
        if n == spd:
            print("The next perfect number after", org, "is", n)
            break

# Get user input
print("\n", "Check what is the next perfect number after n.")
while True:
    try:
        x = int(input("Enter your n: "))
    except ValueError:
        print("n should be a postive integer!")
        continue
    if x &lt; 8128:
        break
    print("Oh. Finding perfect numbers is hard. Choose a lower number. Plz.")

# Run function with user input
npn(x)
The greatest hindrance to understanding is the naming:


What is npn?  Some type of transistor?  next_perfect_number would be a much better name for the function!
What is spd?  An abbreviation for "speed"?  sum_factors would be an improvement… but see below.
You prompt for "n", but assign the result to a variable named x.  That's confusing.


The next biggest problem is that the npn() function tries to do too much.  It would be much clearer if the while loop were moved into a separate is_perfect_number(n) function.

A function that performs a complex calculation should not also perform I/O, as such mixing will prevent code reuse (for unit testing or for a future GUI, for example).  That is, npn() should return its result rather than printing it.

Idiomatic Python would use more elegant ways to perform the loops.  The n += 1 loop could be done using itertools.count().  The loop to calculate spd would be much more succinctly expressed using sum() with a generator expression.  It would certainly be easier to read the intent behind the code that way, but you would also have to introduce a Python-specific language feature.  It's hard to say which approach a beginner would find easier to understand.

It would be good practice to reduce the amount of free-floating code.  I suggest packaging the prompting and printing code in a main() function.



from itertools import count

def next_perfect_number(n):
    """Find the next perfect number after integer n"""
    for i in count(n + 1):
        if is_perfect_number(i):
            return i

def is_perfect_number(n):
    """Test whether n is a perfect number"""
    # Simple but inefficient algorithm
    return n == sum(i for i in range(1, n) if n % i == 0)

def main():
    print("Find the next perfect number after n.")
    while True:
        try:
            n = int(input("Enter your n: "))
            if 1 &lt;= n &lt; 8128:
                break
            print("Choose a number between 1 and 8128, please.")
        except ValueError:
            print("n should be a positive integer!")
    print(
        "The next perfect number after {0} is {1}.".format(
            n,
            next_perfect_number(n)
        )
    )

if __name__ == '__main__':
    main()