Example: IP Validator
Example: IP Validator
Let's write a function that validates an ip address[1]. For the first version of the function, we'll accept any IPV4 address as valid.
It's obvious that the function requires a parameter and that it should return a boolean value indicating whether the ip address is valid or not.
Since the function is checking if a string is a valid ip address, it should also check if the parameter is a string and return False if it's not. We can then continue by splitting the string into octets and checking if there are exactly 4 octets with values between 0 and 255.
def is_valid_ip_address(ip_address):
"""
Validates if a given string is a valid IP address
"""
if not type(ip_address) is str:
return False
octets = ip_address.split(".")
if not len(octets) == 4:
return False
for octet in octets:
if not octet.isnumeric() or int(octet) < 0 or int(octet) > 255:
return False
return True
ip1 = "192.16"
print(f"{ip1} is {'valid' if is_valid_ip_address(ip1) else 'invalid'}") # Output: 192.16 is invalid
ip2 = "192.168.1.25"
print(f"{ip2} is {'valid' if is_valid_ip_address(ip2) else 'invalid'}") # Output: 192.168.1.25 is valid
ip3 = 192
print(f"{ip3} is {'valid' if is_valid_ip_address(ip3) else 'invalid'}") # Output: 192 is invalid
ip4 = [192, 168, 1, 137]
print(f"{ip4} is {'valid' if is_valid_ip_address(ip4) else 'invalid'}") # Output: [192, 168, 1, 137] is invalidNote that the example above has multiple return statements. It's always a good idea to exit the function as soon as possible. We could of course keep track of the validity of the ip address in a variable and return it at the end of the function, but that would result in a lot of unnecessary code and/or indentation, which makes the function harder to read and understand.
The examples below shows an alternative implementation of the function that uses a variable to keep track of the validity of the ip address. Note that the loop at the end of the function does not stop once it's found an invalid octet, instead it continues to check the remaining octets, which is unnecessary and inefficient.
def is_valid_ip_address(ip_address):
"""
Validates if a given string is a valid IP address
"""
is_valid = True
if not type(ip_address) is str:
is_valid = False
octets = []
if is_valid:
octets = ip_address.split(".")
if is_valid and not len(octets) == 4:
is_valid = False
if is_valid:
for octet in octets:
if not octet.isnumeric() or int(octet) < 0 or int(octet) > 255:
is_valid = False
return is_validNote
The docstring can help colleagues understand what the function does, but it can also help us remember what the function does when we come back to it after a long time.
Each function in the standard Python library has a docstring that describes what the function does, what parameters it takes, and what it returns. The information can be viewed in the interpreter by using the help() function.
The line
help(print)returns the following information:
print(*args, sep=' ', end='\n', file=None, flush=False)
Prints the values to a stream, or to sys.stdout by default.
sep
string inserted between values, default a space.
end
string appended after the last value, default a newline.
file
a file-like object (stream); defaults to the current sys.stdout.
flush
whether to forcibly flush the stream.Multiple return values
The previous function works, but it does not validate IPV6 addresses. To fix this, we'll split the function into two other functions, one for validating IPV4 addresses and one for validating IPV6 addresses.
Since the IPV4 validation function is already implemented, we'll not repeat it here. The only change in the IPV4 function is the name (is_valid_ipv4_address() instead of is_valid_ip_address()). The function to validate in IPV6 addresses is a bit more complex, but it can be implemented in a similar way.
def is_hexadecimal(value):
"""
Validate if a given string is hexadecimal.
"""
if not type(value) is str:
return False
for character in value:
if not character.isdigit() and not character.upper() in ['A', 'B', 'C', 'D', 'E', 'F']:
return False
return True
def is_valid_ipv6_address(ip_address):
"""
Validates if a given string is a valid IPV6 address.
"""
if not type(ip_address) is str:
return False
if ip_address.count("::") > 1:
return False
# An IPV address may contain the '::' sequence 0 or 1 times.
ip_address = ip_address.replace("::", ":")
hexets = ip_address.split(":")
for hexet in hexets:
if len(hexet) > 4 or not is_hexadecimal(hexet):
return False
return True
def is_valid_ip_address(ip_address):
"""
Validates if a given string is a valid IP address (V4 or V6)
"""
return is_valid_ipv4_address(ip_address) or is_valid_ipv6_address(ip_address)The code above is fine, but it has one large limitation. When calling the is_valid_ip_address() function, we don't know if a valid IP address is an IPV4 or IPV6 address, which can be important information in some cases. To fix this, we can return a tuple with two values, the first indicating if the ip address is valid and the second indicating if it's an IPV4 or IPV6 address. In case the ip address is invalid, the second value will be None.
def is_valid_ip_address(ip_address):
"""
Validates if a given string is a valid IP address (V4 or V6)
ip_address:
The ip address to validate.
"""
if is_valid_ipv4_address(ip_address):
return (True, "IPv4")
if is_valid_ipv6_address(ip_address):
return (True, "IPv6")
return (False, None)Finally, we can create yet another function to print some output based on the return value of the is_valid_ip_address() function.
def example(value):
result = is_valid_ip_address(value)
if result[0]:
print(f"{value} is a valid {result[1]} address")
else:
print(f"{value} is invalid")
example("192.16")
example("192.168.1.25")
example("2001:db8:0:0:0:ff00:42:8329")
example("::1")
example("2001:db8::ff00::42:8329")Which results in:
192.16 is invalid
192.168.1.25 is a valid IPv4 address
2001:db8:0:0:0:ff00:42:8329 is a valid IPv6 address
::1 is a valid IPv6 address
2001:db8::ff00::42:8329 is invalidWe assume readers are familiar with the rules of IP address validity. If a refresher is needed, we refer to the CCNA course materials, which provide a comprehensive overview of IP address validity rules. ↩︎