Python for Network Engineers

How to Generate, Filter, Exclude IP Addresses Using List Comprehensions and More

by: George El., February 2019, Reading time: 5 minutes

In this post, I will show how to create a list of ip addresses using list comprehensions and also using the ipaddress module in python 3.

Put it simply List Comprehensions is a way to create a list from another list or iterable. They provide an alternative to filter and map functions that can be found in other languages and python

I will start with a basic example and then proceed to show how they can be applied to ip addresses.

list1 = [1,2,3,4,5]
list2 = [x**2 for x in list1]
print(list2)
[1, 4, 9, 16, 25]

you can also add an if statement

list1 = [1,2,3,4,5]
list2 = [x**2 for x in list1 if x>2]
print(list2)
[9, 16, 25]

Generating IP addresses

Now lets see how we can create some ip addresses in a given subnet. Lets say subnet 192.168.1.0/24

ips1 = ["192.168.1.{}".format(i) for i in range(1,255)]

the outcome is

['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.254']

Now if I want to loop through them, I will do

for ip in ips1:
    print(ip)

If I want to add numbers I can do

for ip in enumerate(ips1, start=1):
    print(ip)

this will print

(1, '192.168.1.1')
(2, '192.168.1.2')
(3, '192.168.1.3')
...
(255, '192.168.1.254')

Now lets say I have a list of class C ip addresses and I know that the gw is the .1. So I want to get a new list with all the GWs. I will do something like

import re
ips3 = ["10.1.0.10","192.168.1.22","192.168.3.40"]
ips3_gw = [re.sub(r"\d+$","1",ip) for ip in ips3]
the outcome is
['10.1.0.1', '192.168.1.1', '192.168.3.1']

re is the module for regular expressions. What I do is I substitute the last digits(\d+$) in each string with .1. I will show you also another way, which looks more complicated

ips3_gw = [".".join(ip.split(".")[:3])+".1" for ip in ips3]

what I do here, I split the string in “.”. This return an array of emelement for each ip. For the first ip it will retun [“10”,“1”,“0”,“1”]. Then I join the first 3 [:3] with “.”, and I concatenetate with “1”. I know it’s a bit confusing, but try it out for a single ip.

Filtering IP addresses from a list

If you want to filter a list of ip addresses you can use the if clause. Lets say I have again the ips3 list and I want to filter out any address that starts with 10.

ips3 = ["10.1.0.10","192.168.1.22","192.168.3.40"]
ips4 = [ip for ip in ips3 if int(ip.split(".")[0]) != 10]
print(ips4)
['192.168.1.22', '192.168.3.40']

again I split the ip in octets, and I say the first octet shouldn’t be 10. Please note that these are strings. So I convert them to integer using int(). I could also compare them as strings, but it is easier and more efficient like integers.

Get the list of hosts from a given subnet

Python 3 offers an ipaddress module that provides us with some interesting methods. One of them called hosts() generates a list of all the hosts in a given network. First I have to create an IPv4Network object using the ip_network() function and then call the hosts() function. The hosts() returns a generator, so I have to use the list() function to create the list. In the example below we combine the two steps.

import ipaddress
ips5 = list(ipaddress.ip_network('192.0.2.0/29').hosts()) 
print(ips5)
[IPv4Address('192.0.2.1'),
 IPv4Address('192.0.2.2'),
 IPv4Address('192.0.2.3'),
 IPv4Address('192.0.2.4'),
 IPv4Address('192.0.2.5'),
 IPv4Address('192.0.2.6')]

each IPv4Address is an object with some properties like the following

print(ips5[0].is_private)
print(ips5[0].is_multicast)
print(ips5[0].is_global)
True
False
False

if you want to loop through them

for ip in list(ipaddress.ip_network('192.0.2.0/29').hosts()):
    print(ip)
192.0.2.1
192.0.2.2
192.0.2.3
192.0.2.4
192.0.2.5
192.0.2.6

Joining two lists

the final thing I want to show you is how to join two lists. We will use the zip function. Lets first create two lists

ips = ["192.168.1.{}".format(i) for i in range(1,11)]
hosts = ["host{}".format(i) for i in range(1,11)]
for host, ip in zip(hosts, ips1):
    print(host,ip)
host1 192.168.1.1
host2 192.168.1.2
host3 192.168.1.3
host4 192.168.1.4
host5 192.168.1.5
host6 192.168.1.6
host7 192.168.1.7
host8 192.168.1.8
host9 192.168.1.9
host10 192.168.1.10

the zip function returns an iterator of tuples. if you want to convert to list use the list()

list(zip(hosts,ips))
[('host1', '192.168.1.1'),
 ('host2', '192.168.1.2'),
 ('host3', '192.168.1.3'),
 ('host4', '192.168.1.4'),
 ('host5', '192.168.1.5'),
 ('host6', '192.168.1.6'),
 ('host7', '192.168.1.7'),
 ('host8', '192.168.1.8'),
 ('host9', '192.168.1.9'),
 ('host10', '192.168.1.10')]

Filtering out duplicate IP address.

Lets see how we can filter duplicate IPs with just one line. Our code lies in the fact that in python sets cannot have duplicate items. So we will convert our list to set and back to list

ips = ["1.1.1.1","2.2.2.2","3.3.3.3","1.1.1.1"]
ips2 = list(set(ips))
print(ips2)
['2.2.2.2', '3.3.3.3', '1.1.1.1']

Excluding IP addresses of a list from another list

Final example. I will show you how to exclude ip addresses from a list. Lets say I have two lists and I want to exlude from list1 all IPs from list2. I have to convert them to sets and use the difference function. Then I convert the set to list. Please note that sets are unordered, so the list returns the item unordered.

ips1 = ["192.168.1.{}".format(i) for i in range(1,31)]
ips2 = ["192.168.1.{}".format(i) for i in range(10,21)]
ips3 = list(set(ips1).difference(set(ips2)))
print(ips3)
['192.168.1.4', '192.168.1.5', '192.168.1.30', '192.168.1.25', '192.168.1.22', '192.168.1.26', '192.168.1.24', '192.168.1.2', '192.168.1.1', '192.168.1.6', '192.168.1.21', '192.168.1.23', '192.168.1.27', '192.168.1.9', '192.168.1.28', '192.168.1.29', '192.168.1.3', '192.168.1.7', '192.168.1.8']

the result includes all ip addresses from 1-30 excluding 10-20. If I use the sort method to sort them, it won’t work, because it will treat them as strings. lets see:

ips3.sort()
for ip in ips3:
    print(ip)
192.168.1.1
192.168.1.2
192.168.1.21
192.168.1.22
192.168.1.23
192.168.1.24
192.168.1.25
192.168.1.26
192.168.1.27
192.168.1.28
192.168.1.29
192.168.1.3
192.168.1.30
192.168.1.4
192.168.1.5
192.168.1.6
192.168.1.7
192.168.1.8
192.168.1.9

if you want to sort the ip addresses check my other post here where I explain how to do it.

for ip in sorted(ips3, key = lambda ip: ( int(ip.split(".")[0]), int(ip.split(".")[1]), int(ip.split(".")[2]), int(ip.split(".")[3]))):
            print(ip)
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.21
192.168.1.22
192.168.1.23
192.168.1.24
192.168.1.25
192.168.1.26
192.168.1.27
192.168.1.28
192.168.1.29
192.168.1.30

comments powered by Disqus