Check if a Number Is Prime in Python

A prime number is an integer greater than 1 with exactly two positive divisors: 1 and itself. In Python, the usual beginner-friendly approach is trial division: try possible divisors and stop as soon as one divides evenly.

You do not need to test every number up to n - 1. If a number has a factor larger than its square root, it also has a matching factor smaller than its square root. That means checking divisors up to math.isqrt(n) is enough.

The official Python documentation for math.isqrt() is useful for the square-root limit. Related PythonPool guides cover Python for loops, range(), and Python user input.

Start with clear rules: 0 and 1 are not prime, negative numbers are not prime, 2 is prime, and any even number larger than 2 is not prime. Handling those cases early makes the main loop smaller and easier to read.

For small classroom examples, a simple loop is fine. For cryptography or very large integers, use a library designed for number theory instead of a basic trial-division function.

Prime checking is a good example of improving an algorithm without making it hard to read. The first version can test every possible divisor. The improved version stops at the square root. The faster version skips even divisors after handling 2. Each step keeps the same result while reducing unnecessary work.

Keep the input type clear. These functions expect integers. If a value comes from a form, command line, file, or API response, parse it first and reject invalid text before calling the prime checker.

Also decide what your program should do with non-positive values. In most math and programming contexts, values below 2 simply return False. Raising an exception is usually only needed when negative input means the caller made a mistake.

The examples below keep the logic explicit so you can see each decision.

Check A Number With Trial Division

This direct version checks every possible divisor from 2 up to one less than the number.

number = 17
is_prime = number > 1

for divisor in range(2, number):
    if number % divisor == 0:
        is_prime = False
        break

print(is_prime)

The loop stops early if it finds a divisor. For 17, no divisor is found, so the result is True.

This version is easy to understand, but it does extra work for larger numbers.

Use this form when teaching the idea of divisibility. For real checks, move the logic into a function so the rules can be reused and tested.

Handle Small And Negative Numbers

Numbers less than 2 are not prime.

def is_prime_basic(number):
    if number < 2:
        return False
    for divisor in range(2, number):
        if number % divisor == 0:
            return False
    return True

print(is_prime_basic(-7))
print(is_prime_basic(1))
print(is_prime_basic(2))

This function returns early for values that cannot be prime. That makes the later loop responsible only for realistic candidates.

Early returns also make the function easier to audit. Each special case is handled once, and the main loop stays focused on divisibility.

Use A Square-Root Limit

math.isqrt() returns the integer square root without floating-point rounding issues.

from math import isqrt

def is_prime(number):
    if number < 2:
        return False
    for divisor in range(2, isqrt(number) + 1):
        if number % divisor == 0:
            return False
    return True

print(is_prime(97))
print(is_prime(100))

This is much faster than checking all divisors up to the number for larger inputs.

The + 1 matters because range() stops before the end value.

For example, if the square root limit is 7, the loop must include 7 as a possible divisor. Without the extra one, that final divisor would be skipped.

Skip Even Divisors

After handling 2, every other even number can be rejected or skipped.

from math import isqrt

def is_prime_fast(number):
    if number < 2:
        return False
    if number == 2:
        return True
    if number % 2 == 0:
        return False
    for divisor in range(3, isqrt(number) + 1, 2):
        if number % divisor == 0:
            return False
    return True

print(is_prime_fast(29))
print(is_prime_fast(91))

This loop checks only odd divisors after rejecting even candidates. It is still simple, but it cuts the loop work roughly in half.

This version is a good practical default for ordinary scripts. It avoids unnecessary even checks without adding complex number-theory code.

List Primes In A Range

Reuse the prime-checking function to collect primes from a range.

from math import isqrt

def is_prime(number):
    if number < 2:
        return False
    for divisor in range(2, isqrt(number) + 1):
        if number % divisor == 0:
            return False
    return True

primes = [number for number in range(2, 20) if is_prime(number)]
print(primes)

This style is useful for small reports and learning exercises. For very large ranges, look into sieve algorithms.

A sieve is better when you need many primes up to a limit because it reuses work across the whole range. Calling a single-number test repeatedly is simpler, but not always the fastest approach.

Validate User Input

When the number comes from text input, parse and validate it before checking primality.

from math import isqrt

def is_prime(number):
    if number < 2:
        return False
    for divisor in range(2, isqrt(number) + 1):
        if number % divisor == 0:
            return False
    return True

text = "31"
number = int(text)

print(is_prime(number))

In a real program, catch ValueError if the input may not be an integer. Keep parsing errors separate from prime-checking logic.

Common mistakes include treating 1 as prime, forgetting to stop at the square-root limit, and using floating-point square roots when integer math is cleaner.

Another common mistake is returning too early from the loop. Only return True after all required divisors have been tested. Returning inside the first non-dividing case can mark composite numbers as prime by accident.

In short, handle values below 2 first, test divisibility only up to isqrt(n), skip even divisors when you want a small speed improvement, and keep user input parsing outside the prime-checking function.

Subscribe
Notify of
guest
6 Comments
Oldest
Newest Most Voted
Sid
Sid
4 years ago

Methods 1 through 3 are all the same method. They are only slight variations to be selective about which numbers to iterate. How about adding a method that uses the Sieve of Eratosthenes, and one that uses a lookup table?

Python Pool
Admin
4 years ago
Reply to  Sid

Great catch! I’ll update the post with these methods.

Gabriel
Gabriel
4 years ago

Hi,

method 1.5 cannot work and should be updated :p

Cheers

Pratik Kinage
Admin
4 years ago
Reply to  Gabriel

Hi Gabriel,

Thank you for informing me :). I’ve updated the post accordingly.

Regards,
Pratik

ITech
ITech
4 years ago

I believe your purpose in the statement:
“int(num**1/2)”

is to refer to the root of num, but because you didn’t use parenthesis it becomes:
“int(num/2)”

if you do correct it to:
“int(num**0.5)”

the range needs to be changed in some of your codes here or else the range will be null for lower numbers, I checked for example with 3 and 5.

Pratik Kinage
Admin
4 years ago
Reply to  ITech

Correct. Thank you for pointing it out!