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.
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?
Great catch! I’ll update the post with these methods.
Hi,
method 1.5 cannot work and should be updated :p
Cheers
Hi Gabriel,
Thank you for informing me :). I’ve updated the post accordingly.
Regards,
Pratik
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.
Correct. Thank you for pointing it out!