Hot to get all possible divisors in python

I would like to know, how I can add up all possible divisors of a number in python without the given number itself. For example, all possible divisors of the number 36 are 1, 2, 3, 4, 6, 9, 12 and 18. When you add them up, you should get a total of 55. I would like to know how to get these divisors with a while loop.

I have tried the following code:

def sum_divisors(n):
    sum = 0
    divisor = 2
    while n % divisor == 0:
        if n == 0:
            return 0
        print(n / divisor)
        divisor += 1
print(sum_divisors(36))

When I excecute this code I only get the number 18, 12, and 9. After these numbers I get "None". I think my problem is, when I execute this code the divisor will add 1 as long as the condition ist "True". But when the programm have to divide 36 / 5 the remainder is 1 and the code will no longer be excecuted because the condition is "False". So I tried to fix this problem with the following code:

def sum_divisors(n):
    sum = 0
    divisor = 2
    while n % divisor == 0:
        if n == 0:
            return 0
        if n % divisor == 1:
            divisor += 2
        print(n / divisor)
        divisor += 1
print(sum_divisors(36))

But this code din't work either. Do you have some tips how I can fix this problem. I only want to have tips and not suggested solutions. I am aware that I still need to find a code on how to add everything up. But I will surely be able to solve this problem. ;)


Solution 1:

I highly suggest using the generator approach. We generate all possible divisors and then sum them. It will allow you to get the individual divisors as well:

import math
from typing import Iterator

def iter_divisors(n: int, /) -> Iterator[int]:
    """Iterate over the divisors of a given integer."""
    if n == 0:
        yield 0
        return

    sqrt = math.sqrt(n)

    # math.ceil explanation:
    # If sqrt is a whole number, we check everything until sqrt.
    # Else, we check everything until the closest integer from below.
    for i in range(1, math.ceil(sqrt)):
        if n % i == 0:
            yield i
            yield n // i
    
    # If the sqrt is whole, yield it only once (6 instead of 6,6 in 36)
    if sqrt.is_integer():
        yield int(sqrt)

Then you can sum it:

>>> print(sum(iter_divisors(36)))
91

Keep in mind it includes both 1 and n. You can subtract them if needed:

>>> print(sum(iter_divisors(36)) - 36)
55