Python 学习笔记(第十二期)——运维自动化(中篇):IP地址规划——IPy模块详解

更多Python知识:Python基础入门

我的主页:AOwhisky,这里有更多运维系统性知识整理和其他有趣内容,欢迎与我一起探讨学习~

📖 引言:网络世界的“门牌号系统”

想象一下,你要给一栋新建的写字楼规划房间号——每层有多少个房间?电梯间和消防通道怎么编号?哪些房间是公共区域?如果规划不当,后续的物业管理、访客引导都会一片混乱。

IP地址规划就是网络世界的“门牌号系统”。一个糟糕的IP规划,会导致路由表臃肿、子网冲突、网络性能下降,甚至无法扩展。而一个好的IP规划,则能让网络管理员轻松地分配地址、配置路由、排查故障。

但IP地址的计算并不简单——子网掩码、广播地址、可用IP范围、CIDR表示法……手动计算既繁琐又容易出错。Python的IPy模块就是一个专门解决这个问题的工具库,它能让你用几行代码完成复杂的IP地址计算和网段规划工作。

本期我们将系统学习IPy模块的核心功能:从IP地址的创建与类型识别,到网段的遍历与计算,再到地址格式转换与网段比较。学完本期,你将能高效地完成各类IP规划任务。

— Compiled and Authored by Whisky — July 20 th, 2026

📑 本期目录

  1. IP地址规划概述
  2. IPy模块安装与IP类基础
  3. IP地址的创建与版本识别
  4. 网段遍历与IP清单生成
  5. IP地址类型判断与反向解析
  6. IP地址格式转换(整型/十六进制/二进制)
  7. 网段格式标准化(strNormal
  8. 网段比较与重叠判断
  9. 综合实战:交互式IP信息查询工具
  10. 总结与知识点一览表

正文

一、IP地址规划概述

1.1 什么是IP地址规划

IP地址规划是网络设计中最重要的环节之一,它直接影响路由协议效率、网络性能、可扩展性。一个好的IP规划需要解决以下问题:

规划内容 要回答的问题
子网划分 每个子网应该分配多大地址范围?
地址分配 哪些地址分配给服务器?哪些给终端设备?
路由聚合 如何通过CIDR减少路由表条目?
预留扩容 未来新增设备时,地址空间还够用吗?

💡 白话理解:IP地址规划就像给城市街道编门牌号——既要让现有的房子有编号,也要预留空位给未来的新建筑。编得太密(子网太小),新楼没号可用;编得太松(子网太大),门牌号浪费严重。

1.2 为什么需要IPy模块

在没有工具的情况下,IP地址计算需要手动进行二进制转换。例如计算 192.168.1.0/24 的广播地址,你需要:

  1. 192.168.1.0 转为二进制
  2. 255.255.255.0 转为二进制
  3. 按位计算网络地址、广播地址
  4. 再转回十进制

有了IPy模块,一行代码就能完成所有计算。

1.3 IPy模块的安装与导入
pip install IPy
from IPy import IP

二、IP类的核心方法预览

在深入学习之前,先快速预览IP类的核心方法,建立一个全局认知:

from IPy import IP

ip = IP('192.168.1.0/24')

# 基本属性
ip.version()          # IP版本:4 或 6
ip.len()              # 网段包含的IP总数
ip.net()              # 网络地址
ip.netmask()          # 子网掩码
ip.broadcast()        # 广播地址
ip.reverseNames()     # 反向解析地址

# 类型判断
ip.iptype()           # PUBLIC 或 PRIVATE
ip.is_loopback()      # 是否环回地址
ip.is_multicast()     # 是否组播地址

# 格式转换
ip.int()              # 转换为整数
ip.strHex()           # 转换为十六进制
ip.strBin()           # 转换为二进制

# 网段格式
ip.make_net('255.255.255.0')   # IP+掩码生成网段
ip.strNormal(0)       # 多种网段输出格式

三、IP地址的创建与版本识别

3.1 创建IP对象

IPy模块的核心是IP类,它可以接受多种格式的输入:

from IPy import IP

# 1. 单个IP地址
ip1 = IP('192.168.1.1')
print(ip1)

# 2. IP + 子网掩码(十进制)
ip2 = IP('192.168.1.0/255.255.255.0')
print(ip2)   # 自动转为CIDR格式

# 3. IP + CIDR前缀
ip3 = IP('192.168.1.0/24')
print(ip3)

# 4. IP范围
ip4 = IP('192.168.1.0-192.168.1.255')
print(ip4)   # 自动转为CIDR格式

运行结果

192.168.1.1
192.168.1.0/24
192.168.1.0/24
192.168.1.0/24
3.2 识别IP版本——version()
from IPy import IP

ipv4 = IP('192.168.1.1')
ipv6 = IP('2001:db8::1')

print(f"192.168.1.1 是 IPv{ipv4.version()}")
print(f"2001:db8::1 是 IPv{ipv6.version()}")

运行结果

192.168.1.1 是 IPv4
2001:db8::1 是 IPv6

四、网段遍历与IP清单生成

4.1 获取网段IP总数——len()
from IPy import IP

# /24 网段包含 256 个IP
net24 = IP('192.168.1.0/24')
print(f"192.168.1.0/24 包含 {len(net24)} 个IP地址")

# /16 网段包含 65536 个IP
net16 = IP('192.168.0.0/16')
print(f"192.168.0.0/16 包含 {len(net16)} 个IP地址")

# /28 网段包含 16 个IP
net28 = IP('192.168.1.0/28')
print(f"192.168.1.0/28 包含 {len(net28)} 个IP地址")

运行结果

192.168.1.0/24 包含 256 个IP地址
192.168.0.0/16 包含 65536 个IP地址
192.168.1.0/28 包含 16 个IP地址
4.2 遍历网段中的所有IP

IP对象是可迭代的,可以直接用于for循环:

from IPy import IP

net = IP('192.168.1.0/28')
print(f"网段 {net} 的所有IP地址:")

for ip in net:
    print(ip, end=" ")

运行结果

网段 192.168.1.0/28 的所有IP地址:
192.168.1.0 192.168.1.1 192.168.1.2 192.168.1.3 192.168.1.4 192.168.1.5 192.168.1.6 192.168.1.7 192.168.1.8 192.168.1.9 192.168.1.10 192.168.1.11 192.168.1.12 192.168.1.13 192.168.1.14 192.168.1.15

⚠️ 注意:遍历整个网段会生成所有IP地址,对于/16及以上(65536个IP)的大网段,遍历可能消耗较多内存和时间,使用时要注意性能影响。

4.3 获取网段的关键地址
from IPy import IP

net = IP('192.168.1.0/24')

print(f"网段:{net}")
print(f"网络地址:{net.net()}")
print(f"子网掩码:{net.netmask()}")
print(f"广播地址:{net.broadcast()}")
print(f"反向解析地址:{net.reverseNames()[0]}")
print(f"网段IP总数:{len(net)}")

运行结果

网段:192.168.1.0/24
网络地址:192.168.1.0
子网掩码:255.255.255.0
广播地址:192.168.1.255
反向解析地址:0.1.168.192.in-addr.arpa.
网段IP总数:256

五、IP地址类型判断与反向解析

5.1 判断IP地址类型——iptype()

在实际运维中,经常需要区分一个IP是公网地址还是私网地址,或者判断其特殊类型:

from IPy import IP

ips = [
    '192.168.1.1',
    '114.114.114.114',
    '8.8.8.8',
    '127.0.0.1',
    '10.0.0.1',
    '172.16.0.1',
    '224.0.0.1',
    '169.254.1.1'
]

for ip_str in ips:
    ip = IP(ip_str)
    print(f"{ip_str:20}{ip.iptype()}")

运行结果

192.168.1.1          → PRIVATE
114.114.114.114      → PUBLIC
8.8.8.8              → PUBLIC
127.0.0.1            → LOOPBACK
10.0.0.1             → PRIVATE
172.16.0.1           → PRIVATE
224.0.0.1            → MULTICAST
169.254.1.1          → LINKLOCAL

iptype() 返回值说明

返回值 含义 典型范围 说明
PRIVATE 私网地址 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 内网使用,不可在公网路由
PUBLIC 公网地址 除私网、环回、组播等之外的地址 可在公网路由
LOOPBACK 环回地址 127.0.0.0/8 本机通信,不会离开设备
MULTICAST 组播地址 224.0.0.0/4 一对多通信
LINKLOCAL 链路本地地址 169.254.0.0/16 DHCP失败时自动分配
BROADCAST 广播地址 255.255.255.255 全网广播
UNSPECIFIED 未指定地址 0.0.0.0 默认路由或未配置
5.2 反向解析地址——reverseNames()

反向解析(PTR记录)用于从IP地址查找域名,是DNS查询中的反向操作:

from IPy import IP

ip = IP('192.168.1.100')
print(f"正向地址:{ip}")
print(f"反向解析:{ip.reverseNames()[0]}")

运行结果

正向地址:192.168.1.100
反向解析:100.1.168.192.in-addr.arpa.

六、IP地址格式转换

在数据库中存储IP地址时,为了提高查询性能,通常使用**整型(整数)**格式存储而不是字符串。IPy模块提供了方便的转换方法:

from IPy import IP

ip = IP('8.8.8.8')

print(f"原始IP地址:{ip}")
print(f"整型格式:{ip.int()}")
print(f"十六进制:{ip.strHex()}")
print(f"二进制:{ip.strBin()}")

运行结果

原始IP地址:8.8.8.8
整型格式:134744072
十六进制:0x8080808
二进制:00001000000010000000100000001000

转换验证

from IPy import IP

ip_int = 134744072
ip_from_int = IP(ip_int)
print(f"整数 {ip_int} 还原为IP地址:{ip_from_int}")

运行结果

整数 134744072 还原为IP地址:8.8.8.8

💡 实战价值:在数据库中存储IP整型值,查询速度比字符串快得多,且存储空间更小。例如MySQL的INET_ATON()INET_NTOA()函数就是做这个转换的。

七、网段格式标准化——strNormal()

strNormal()方法可以控制网段的输出格式,满足不同场景的需求:

from IPy import IP

net = IP('192.168.1.0/24')

print("wantprefixlen=0(无返回):", net.strNormal(0))
print("wantprefixlen=1(CIDR格式):", net.strNormal(1))
print("wantprefixlen=2(十进制掩码):", net.strNormal(2))
print("wantprefixlen=3(IP范围格式):", net.strNormal(3))

运行结果

wantprefixlen=0(无返回): 192.168.1.0
wantprefixlen=1(CIDR格式): 192.168.1.0/24
wantprefixlen=2(十进制掩码): 192.168.1.0/255.255.255.0
wantprefixlen=3(IP范围格式): 192.168.1.0-192.168.1.255

参数说明

参数值 输出格式 示例 适用场景
0 仅网络地址 192.168.1.0 需要干净的IP地址时
1 CIDR前缀格式 192.168.1.0/24 标准网络规划
2 十进制掩码格式 192.168.1.0/255.255.255.0 传统网络配置
3 IP范围格式 192.168.1.0-192.168.1.255 防火墙策略配置

八、网段比较与重叠判断

8.1 网段大小比较

IPy支持使用比较运算符(<>==)比较两个网段:

from IPy import IP

net1 = IP('10.0.0.0/16')
net2 = IP('10.0.0.0/24')
net3 = IP('192.168.0.0/16')

# 比较网段大小(基于网络地址)
print(f"10.0.0.0/16 < 10.0.0.0/24:{net1 < net2}")
print(f"10.0.0.0/24 < 10.0.0.0/16:{net2 < net1}")

# 相等比较
print(f"10.0.0.0/16 == 10.0.0.0/16:{net1 == net1}")
print(f"10.0.0.0/16 == 192.168.0.0/16:{net1 == net3}")

运行结果

10.0.0.0/16 < 10.0.0.0/24:True
10.0.0.0/24 < 10.0.0.0/16:False
10.0.0.0/16 == 10.0.0.0/16:True
10.0.0.0/16 == 192.168.0.0/16:False

⚠️ 注意net1 < net2 的结果是 True(因为 /16 的网络地址小于 /24),但这并不是一个严格的“谁包含谁”的逻辑,而是基于网络地址数值的比较。

8.2 判断IP或网段是否包含在另一个网段中(in
from IPy import IP

# 单个IP是否在网段中
print("192.168.1.100" in IP("192.168.1.0/24"))   # True
print("192.168.2.100" in IP("192.168.1.0/24"))   # False

# 网段是否在另一个网段中
print(IP("192.168.1.0/24") in IP("192.168.0.0/16"))  # True
print(IP("192.168.1.0/24") in IP("172.16.0.0/12"))   # False

运行结果

True
False
True
False
8.3 判断网段是否重叠——overlaps()

overlaps()方法用于判断两个网段是否存在重叠部分:

from IPy import IP

# 完全重叠(相同网段)
print(IP("192.168.1.0/24").overlaps("192.168.1.0/24"))  # 1

# 部分重叠(包含关系)
print(IP("192.168.1.0/24").overlaps("192.168.1.128/25"))  # 1

# 完全相邻但不重叠
print(IP("192.168.1.0/24").overlaps("192.168.2.0/24"))  # 0

# 不相邻也不重叠
print(IP("192.168.1.0/24").overlaps("10.0.0.0/8"))  # 0

运行结果

1
1
0
0

返回值说明

返回值 含义
1 两个网段存在重叠(包含或部分重叠)
0 两个网段完全不重叠

💡 实战场景:在网络规划时,overlaps()可以帮助检测地址冲突——例如在分配新的子网之前,先检查是否与现有子网重叠,避免因地址冲突导致的路由问题。

九、综合实战:交互式IP信息查询工具

需求描述:编写一个交互式Python脚本,用户输入一个IP地址或网段,程序输出该IP/网段的完整信息,包括网络地址、掩码、广播地址、IP类型、反向解析、子网数量、十六进制和二进制表示等。

设计思路

  • 使用IPy.IP类处理用户输入(自动识别单IP和网段)
  • 判断输入是单个IP还是网段,分别展示不同的信息
  • 使用iptype()strNormal()int()strHex()等方法
  • 提供友好的格式化输出
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
交互式IP信息查询工具
用途:输入IP地址或网段,输出完整的地址信息
作者:Whisky
"""

from IPy import IP

def format_network_info(ip_obj):
    """格式化输出网段信息"""
    print("\n" + "=" * 60)
    print("  网段信息")
    print("=" * 60)
    print(f"网段(CIDR):{ip_obj.strNormal(1)}")
    print(f"网段(掩码):{ip_obj.strNormal(2)}")
    print(f"网段(范围):{ip_obj.strNormal(3)}")
    print(f"网络地址:{ip_obj.net()}")
    print(f"子网掩码:{ip_obj.netmask()}")
    print(f"广播地址:{ip_obj.broadcast()}")
    print(f"反向解析:{ip_obj.reverseNames()[0]}")
    print(f"IP总数:{len(ip_obj)}")
    print(f"IP类型:{ip_obj.iptype()}")
    print(f"十六进制:{ip_obj.strHex()}")
    print(f"二进制:{ip_obj.strBin()}")
    print("=" * 60)

def format_single_ip_info(ip_obj):
    """格式化输出单个IP信息"""
    print("\n" + "=" * 60)
    print("  单个IP信息")
    print("=" * 60)
    print(f"IP地址:{ip_obj}")
    print(f"IP版本:IPv{ip_obj.version()}")
    print(f"IP类型:{ip_obj.iptype()}")
    print(f"反向解析:{ip_obj.reverseNames()[0]}")
    print(f"整型格式:{ip_obj.int()}")
    print(f"十六进制:{ip_obj.strHex()}")
    print(f"二进制:{ip_obj.strBin()}")
    print("=" * 60)

def main():
    print("=" * 60)
    print("  🌐 IP地址/网段信息查询工具 v1.0")
    print("  支持格式:")
    print("    单个IP  ->  192.168.1.1")
    print("    CIDR    ->  192.168.1.0/24")
    print("    掩码    ->  192.168.1.0/255.255.255.0")
    print("    范围    ->  192.168.1.0-192.168.1.255")
    print("=" * 60)

    while True:
        user_input = input("\n请输入IP地址或网段(输入 q 退出):").strip()

        if user_input.lower() == 'q':
            print("👋 再见!")
            break

        if not user_input:
            print("❌ 输入不能为空,请重新输入")
            continue

        try:
            ip_obj = IP(user_input)

            # 判断是单个IP还是网段
            if len(ip_obj) == 1:
                format_single_ip_info(ip_obj)
            else:
                format_network_info(ip_obj)

        except ValueError as e:
            print(f"❌ 输入的IP地址格式无效:{e}")
        except Exception as e:
            print(f"❌ 处理过程中出现错误:{e}")

if __name__ == "__main__":
    main()

运行效果

============================================================
  🌐 IP地址/网段信息查询工具 v1.0
  支持格式:
    单个IP  ->  192.168.1.1
    CIDR    ->  192.168.1.0/24
    掩码    ->  192.168.1.0/255.255.255.0
    范围    ->  192.168.1.0-192.168.1.255
============================================================

请输入IP地址或网段(输入 q 退出):18.18.18.0/26

============================================================
  网段信息
============================================================
网段(CIDR):18.18.18.0/26
网段(掩码):18.18.18.0/255.255.255.192
网段(范围):18.18.18.0-18.18.18.63
网络地址:18.18.18.0
子网掩码:255.255.255.192
广播地址:18.18.18.63
反向解析:0.18.18.18.in-addr.arpa.
IP总数:64
IP类型:PUBLIC
十六进制:0x12121200
二进制:00010010000100100001001000000000
============================================================

十、补充知识:CIDR与子网掩码对照速查表

CIDR前缀 子网掩码 IP总数 可用IP数 典型用途
/8 255.0.0.0 16,777,216 16,777,214 大型A类网段
/16 255.255.0.0 65,536 65,534 中型B类网段
/24 255.255.255.0 256 254 标准C类网段(最常用)
/25 255.255.255.128 128 126 小型子网
/26 255.255.255.192 64 62 小型子网
/27 255.255.255.224 32 30 小型子网
/28 255.255.255.240 16 14 微型子网
/29 255.255.255.248 8 6 点对点链路
/30 255.255.255.252 4 2 路由器间链路
/31 255.255.255.254 2 2 点对点(RFC 3021)
/32 255.255.255.255 1 1 单个主机地址

十一、IPy vs socket模块对比

对于IP地址处理,Python标准库的 socket 模块也提供了一些基础功能,但IPy更为专业和便捷:

功能 socket 模块 IPy 模块
域名解析 gethostbyname() ❌ 不支持(需配合socket)
IP版本识别 ❌ 需手动判断 version()
网段遍历 ❌ 需手动实现 ✅ 迭代器
CIDR计算 ❌ 需手动实现 net()broadcast()
IP类型判断 ❌ 需手动实现 iptype()
网段重叠检测 ❌ 需手动实现 overlaps()
格式转换 ❌ 需手动实现 int()strHex()

📝 总结与知识点一览表

核心API速查表

功能分类 方法/属性 作用
创建 IP('192.168.1.0/24') 创建IP对象
版本 ip.version() 返回IPv4或IPv6
属性 ip.net() 网络地址
ip.netmask() 子网掩码
ip.broadcast() 广播地址
ip.len() IP总数
遍历 for i in ip: 遍历网段所有IP
类型 ip.iptype() PUBLIC/PRIVATE/LOOPBACK等
反向解析 ip.reverseNames() 返回PTR记录列表
格式转换 ip.int() 转为整型
ip.strHex() 转为十六进制
ip.strBin() 转为二进制
网段格式 ip.strNormal(0/1/2/3) 多种输出格式
网段生成 IP('192.168.1.0').make_net('255.255.255.0') IP+掩码→网段
包含判断 ip in net IP是否在网段中
重叠判断 net1.overlaps(net2) 两网段是否重叠

常见错误排查指南

错误现象 大概率原因 解决方案
ValueError: 'xxx' does not appear to be an IPv4 or IPv6 address 输入格式无效 检查IP格式是否正确,如 192.168.1.0/24
TypeError: 'IP' object is not iterable 对单个IP使用遍历 先通过 len(ip_obj) 判断是否为网段
overlaps() 返回非预期结果 误解了重叠的含义 只要两个网段有任何IP交集即为重叠
reverseNames() 返回空列表 输入的IP格式无法反向解析 确认输入的是有效的IPv4/IPv6地址

运维/学习最佳实践

  1. 使用CIDR格式输入:虽然IPy支持多种格式,但CIDR表示法(如 192.168.1.0/24)是最规范、最常用的输入方式。
  2. IP类型判断用于安全策略iptype() 可用于自动检测IP是否属于私网地址,在防火墙策略配置和路由策略中非常实用。
  3. 整型存储提升性能:将IP地址转为整型存储到数据库,查询性能远超字符串匹配,且存储空间更小。
  4. overlaps() 用于规划校验:在分配新网段前,使用 overlaps() 检查是否与现有网段重叠,避免地址冲突。
  5. strNormal() 选择合适格式
    • 路由配置 → CIDR格式(strNormal(1)
    • 传统设备配置 → 十进制掩码格式(strNormal(2)
    • 防火墙策略 → IP范围格式(strNormal(3)

🔜 下期预告

本期我们系统学习了IPy模块的完整功能——从IP地址的创建与版本识别、网段遍历与IP清单生成、IP类型判断与反向解析、地址格式转换、网段格式标准化,到网段比较与重叠判断,最后通过“交互式IP信息查询工具”将所有知识整合为实战应用。

下一期 ,我们将开启 paramiko 远程运维 系列的第一篇,学习如何用 Python 实现 SSH 远程连接和命令执行——这是自动化运维最核心的能力之一。我们将从 paramiko 的环境部署开始,逐步掌握 SSHClient 的连接认证、远程命令执行、批量运维脚本开发等实用技能。敬请期待!


— Compiled and Authored by Whisky — July 20 th, 2026
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐