Skip to content

How to Convert an IP Address to Integer in Python

Learn how to convert IPv4 and IPv6 addresses to integers in Python using the built-in ipaddress module for efficient database storage, range checks, and accurate sorting.

Converting IP addresses to integers enables efficient database storage, fast sorting, and simple range queries. A 4-byte integer is smaller and faster to index than a 15-character string, and subnet checks become straightforward numeric comparisons.

Python's built-in ipaddress module handles this conversion securely and reliably for both IPv4 and IPv6.

In this guide, you will learn how to perform these conversions, explore practical use cases, and understand why the ipaddress module is the right tool for the job.

Converting an IP Address to an Integer

The most direct approach is to create an IP address object using the ipaddress module and cast it to int:

import ipaddress

ip = ipaddress.ip_address("192.168.1.1")
ip_int = int(ip)

print(f"{ip} -> {ip_int}")

Output:

192.168.1.1 -> 3232235777

The math behind this conversion follows the positional value of each octet:

192 * 256³ + 168 * 256² + 1 * 256¹ + 1 * 256⁰ = 3232235777

Each octet represents 8 bits, so an IPv4 address maps to a 32-bit unsigned integer.

Converting an Integer Back to an IP Address

Pass the integer directly to the ipaddress.ip_address() constructor to reverse the conversion:

import ipaddress

ip_int = 3232235777
ip = ipaddress.ip_address(ip_int)

print(ip)
print(type(ip))

Output:

192.168.1.1
<class 'ipaddress.IPv4Address'>

Handling IPv6 Addresses

The same approach works seamlessly for IPv6 addresses, though the resulting integers are much larger since IPv6 uses 128-bit addresses:

import ipaddress

ipv6 = ipaddress.ip_address("2001:db8::1")
ipv6_int = int(ipv6)

print(f"{ipv6} -> {ipv6_int}")

restored = ipaddress.ip_address(ipv6_int)
print(f"{ipv6_int} -> {restored}")

Output:

2001:db8::1 -> 42540766411282592856903984951653826561
42540766411282592856903984951653826561 -> 2001:db8::1

Practical Applications

Efficient Database Storage

Storing IP addresses as integers significantly improves indexing and query performance compared to storing them as variable-length strings:

import ipaddress
import sqlite3

def store_ip(conn, ip_string):
    """Store an IP address as an integer for efficient indexing."""
    ip = ipaddress.ip_address(ip_string)
    ip_int = int(ip)
    version = ip.version

    conn.execute(
        "INSERT INTO access_log (ip_int, ip_version) VALUES (?, ?)",
        (ip_int, version)
    )

def retrieve_ip(ip_int):
    """Convert a stored integer back to a readable IP string."""
    return str(ipaddress.ip_address(ip_int))

IP Range Checking

Integer comparison makes range checks trivial, which is especially useful for firewall rules, geolocation lookups, or rate limiting:

import ipaddress

def is_ip_in_range(ip_string, start_ip, end_ip):
    """Check if an IP falls within a numeric range."""
    ip = int(ipaddress.ip_address(ip_string))
    start = int(ipaddress.ip_address(start_ip))
    end = int(ipaddress.ip_address(end_ip))

    return start <= ip <= end

print(is_ip_in_range("192.168.1.50", "192.168.1.0", "192.168.1.255"))
print(is_ip_in_range("10.0.0.1", "192.168.1.0", "192.168.1.255"))

Output:

True
False

Subnet Membership

The ipaddress module also provides a clean way to check whether an IP belongs to a subnet without manual integer arithmetic:

import ipaddress

def is_in_subnet(ip_string, subnet_string):
    """Check if an IP belongs to a given subnet."""
    ip = ipaddress.ip_address(ip_string)
    network = ipaddress.ip_network(subnet_string, strict=False)

    return ip in network

print(is_in_subnet("192.168.1.100", "192.168.1.0/24"))
print(is_in_subnet("192.168.2.1", "192.168.1.0/24"))

Output:

True
False

Sorting IP Addresses Correctly

String-based sorting produces incorrect results for IP addresses because it compares character by character. Converting to integers ensures proper numeric ordering:

import ipaddress

ips = ["10.0.0.1", "192.168.1.1", "8.8.8.8", "172.16.0.1"]

sorted_ips = sorted(ips, key=lambda x: int(ipaddress.ip_address(x)))
print(sorted_ips)

Output:

['8.8.8.8', '10.0.0.1', '172.16.0.1', '192.168.1.1']

Without integer conversion, a naive string sort would incorrectly place "8.8.8.8" after "192.168.1.1" because the character "8" comes after "1" in ASCII order.

Batch Conversion Utilities

For applications that process large numbers of IP addresses, having reusable utility functions keeps your code clean and consistent:

import ipaddress
from typing import List

def ip_to_int(ip: str) -> int:
    """Convert an IP string to an integer."""
    return int(ipaddress.ip_address(ip))

def int_to_ip(ip_int: int) -> str:
    """Convert an integer to an IP string."""
    return str(ipaddress.ip_address(ip_int))

def batch_convert_to_int(ips: List[str]) -> List[int]:
    """Convert a list of IP strings to integers."""
    return [ip_to_int(ip) for ip in ips]

def batch_convert_to_ip(integers: List[int]) -> List[str]:
    """Convert a list of integers to IP strings."""
    return [int_to_ip(i) for i in integers]

ips = ["192.168.1.1", "10.0.0.1", "8.8.8.8"]
integers = batch_convert_to_int(ips)
print(f"Integers: {integers}")

restored = batch_convert_to_ip(integers)
print(f"IPs:      {restored}")

Output:

Integers: [3232235777, 167772161, 134744072]
IPs:      ['192.168.1.1', '10.0.0.1', '8.8.8.8']

Handling Mixed IP Versions Safely

When processing user input or log files, you may encounter a mix of IPv4 addresses, IPv6 addresses, and invalid entries. Wrapping conversions in error handling ensures your application remains robust:

import ipaddress

def convert_ip_safely(ip_string):
    """Convert an IP address with version detection and validation."""
    try:
        ip = ipaddress.ip_address(ip_string)
        return {
            'ip': str(ip),
            'integer': int(ip),
            'version': ip.version,
            'is_private': ip.is_private,
            'is_loopback': ip.is_loopback
        }
    except ValueError as e:
        return {'error': str(e)}

print(convert_ip_safely("192.168.1.1"))
print(convert_ip_safely("::1"))
print(convert_ip_safely("invalid"))

Output:

{'ip': '192.168.1.1', 'integer': 3232235777, 'version': 4, 'is_private': True, 'is_loopback': False}
{'ip': '::1', 'integer': 1, 'version': 6, 'is_private': True, 'is_loopback': True}
{'error': "'invalid' does not appear to be an IPv4 or IPv6 address"}

Why You Should Avoid Manual Bit Manipulation

You might encounter tutorials suggesting manual conversion using bit shifting or string splitting. While this can work for simple cases, it is error-prone and lacks input validation.

Quick Reference

Operation Code
IP string to integer int(ipaddress.ip_address("192.168.1.1"))
Integer to IP string str(ipaddress.ip_address(3232235777))
Numeric range check start_int <= ip_int <= end_int
Subnet membership ipaddress.ip_address(ip) in ipaddress.ip_network(subnet)
Version detection ipaddress.ip_address(ip).version

Conclusion

Converting IP addresses to integers in Python is simple and reliable when you use the built-in ipaddress module. Casting an IP address object to int gives you an efficient numeric representation suitable for database storage, fast comparisons, range queries, and correct sorting. The same module handles both IPv4 and IPv6 seamlessly, validates input automatically, and manages edge cases that manual bit manipulation would miss.

Navigation