R / Richie全部文章 ↑

Python · 4 分钟阅读

IPy:IP 地址处理库

目录


处理 IP 地址、子网、掩码、广播、范围等需求时,Python 3 有 两个选择:

选项 优缺点
IPy 老牌第三方库、API 友好;已停更多年(最后一次更新 2020)
ipaddress 标准库、自 Python 3 起内置;功能覆盖 95% 日常需求

新项目建议直接用标准库 ipaddress,0 依赖、与 Python 版本同步。
如果你接手老代码看到 IPy,下面是“对照表”,快速迁移不是问题。


1. 安装(仅当用 IPy 时)

pip install IPy

Python 3.4+ 已经有 ipaddress,大部分情况下不需要再装 IPy。


2. ipaddress(推荐):标准库

2.1 创建对象

import ipaddress

v4 = ipaddress.ip_address("192.168.50.20")
v6 = ipaddress.ip_address("::1")
print(v4.version)            # 4
print(v6.version)            # 6

自动判断是 IPv4 还是 IPv6。

2.2 网络 / 子网

net = ipaddress.ip_network("192.168.0.0/16", strict=False)
print(net.num_addresses)     # 65536
print(net.network_address)   # 192.168.0.0
print(net.broadcast_address) # 192.168.255.255
print(net.netmask)           # 255.255.0.0
print(net.prefixlen)         # 16

2.3 遍历地址

net = ipaddress.ip_network("192.168.0.0/24")
print(net.num_addresses)     # 256

# /24 太小,打印前几个就行
for i, ip in enumerate(net):
    if i >= 3: break
    print(ip)
# 192.168.0.0
# 192.168.0.1
# 192.168.0.2

net.hosts() 只给出“可用的 host 地址”,跳过网络地址与广播。

2.4 成员判断

"192.168.1.100" in ipaddress.ip_network("192.168.0.0/16")   # True
ipaddress.ip_address("10.0.0.1") in ipaddress.ip_network("10.0.0.0/24")  # True

2.5 整数 / 字节 / 十六进制表示

ip = ipaddress.ip_address("192.168.50.20")
print(int(ip))               # 3232255508
print(ip.packed)             # b'\xc0\xa83\x14'
print(hex(int(ip)))          # 0xc0a83214
print(format(int(ip), "08x"))

想看二进制:bin(int(ip));想格式化输出可自己写 format_ip。

2.6 反向解析名(PTR 记录)

ipaddress.ip_address("8.8.8.8").reverse_pointer
# '8.8.8.8.in-addr.arpa'

2.7 IPv4 与 IPv6 互转

ipaddress.IPv4Address("192.168.0.1").ipv4_mapped    # ::ffff:192.168.0.1
ipaddress.IPv6Address("::ffff:c0a8:1").ipv4_mapped # ::ffff:192.168.0.1

2.8 多网络比较

a = ipaddress.ip_network("10.0.0.0/24")
b = ipaddress.ip_network("12.0.0.0/24")
print(a < b)                                         # True

print("192.168.1.100" in ipaddress.ip_network("192.168.0.0/24"))    # True
print(ipaddress.ip_network("192.168.0.0/23")
      .overlaps(ipaddress.ip_network("192.168.0.0/24")))           # True

2.9 网络地址运算

n = ipaddress.ip_network("192.168.50.0/24")
print(n.network_address)         # 192.168.50.0
print(n.broadcast_address)       # 192.168.50.255
print(n.netmask)                 # 255.255.255.0
print(n.hostmask)                # 0.0.0.255
print(n.with_prefixlen)          # 192.168.50.0/24
print(n.with_netmask)            # 192.168.50.0/255.255.255.0

2.10 拆分子网

supernet = ipaddress.ip_network("192.168.0.0/16")
for sub in supernet.subnets(new_prefix=18):
    print(sub)
# 192.168.0.0/18
# 192.168.64.0/18
# 192.168.128.0/18
# 192.168.192.0/18

3. IPy(已停更):老 API 对照

如果你接手老代码,可以按下面方式改写:

IPy 用法 ipaddress 等价
IP("192.168.50.0/24").version() ipaddress.ip_address(...).version
IP("192.168.0.0/16").len() ipaddress.ip_network(...).num_addresses
IP("...").net() .network_address
IP("...").netmask() .netmask
IP("...").broadcast() .broadcast_address
IP("...").reverseName() .reverse_pointer
IP("...").int() int(...)
IP("...").strHex() format(int(...), '08x')
IP("...").iptype() 自己判断(is_global / is_private 等)
IP("192.168.0.0/24") in IP(...) ipaddress.ip_address(...) in ipaddress.ip_network(...)
IP(...).overlaps(...) ipaddress.ip_network(...).overlaps(...)

IPy 的 iptype() 区分 “LOOPBACK / PRIVATE / PUBLIC / …”,ipaddress 改为
is_loopback / is_private / is_global / is_multicast / is_reserved 等
几个 bool 方法:

ip = ipaddress.ip_address("10.0.0.1")
print(ip.is_private)              # True
print(ip.is_global)               # False
print(ip.is_loopback)             # False

4. 综合案例:IP 段信息查询

import ipaddress


def describe(s: str) -> str:
    """打印 IP / 网段 的网络信息。"""
    if "/" in s:
        net = ipaddress.ip_network(s, strict=False)
        return (
            f"network   : {net}\n"
            f"mask      : {net.netmask}\n"
            f"broadcast : {net.broadcast_address}\n"
            f"num_hosts : {net.num_addresses}\n"
            f"first host: {next(net.hosts()) if net.num_addresses > 2 else net.network_address}\n"
            f"last host : {net.broadcast_address - 1 if net.num_addresses > 2 else net.broadcast_address}"
        )
    else:
        ip = ipaddress.ip_address(s)
        return (
            f"ip      : {ip}\n"
            f"version : IPv{ip.version}\n"
            f"private : {ip.is_private}\n"
            f"global  : {ip.is_global}\n"
            f"reverse : {ip.reverse_pointer}"
        )


if __name__ == "__main__":
    print(describe("192.168.50.0/24"))
    print()
    print(describe("8.8.8.8"))

5. 选型

需求 用什么
解析 IP、判定私有/公网、遍历网段 ipaddress(标准库)
想用更“人性化”的 API、需要 iptype IPy(不推荐新项目)
IP 反查域名(PTR) ipaddress.ip_address(...).reverse_pointer 或 socket.gethostbyaddr
IPv6 转换 / 6to4 / 4to6 ipaddress 已覆盖常见场景
复杂的 IP 归属地查询 借助 ip-api.com / MaxMind / ip2region 等数据库

6. 小结

  • 新项目用 ipaddress:标准库、0 依赖、文档全。
  • IPy 还能用,但已停更多年,复杂 IPv6 场景偶尔会有 bug。
  • 需要 IP 归属地信息时,ipaddress 不会替你做;要自己接 GeoIP 库。