Numbers, Files, and Lists

Do real math on network values, read whole config files off disk instead of single lines, and use lists - Python's workhorse container - to slice and organize everything you parse.

TL;DR - only got 10 minutes? This is the lesson. Hit to have it read to you.
  • Integer math does subnet sizing: 2 ** (32 - prefix) - 2 is your usable host count. round(used / total * 100, 1) is your utilization percentage.
  • Everything you parse from device output is a string. int("24") before you do math - "100" + 5 is a TypeError, not 105.
  • Always read files with the with statement: with open(path) as f: - it closes the file automatically, even when your code blows up mid-read.
  • f.read().splitlines() turns a config file into a clean list of lines, no trailing newlines.
  • Lists index from 0, negatives count from the end, and slices are [start:stop] with stop excluded - lines[-2:] is the last two entries.
  • sorted(vlans) returns a NEW sorted list; vlans.sort() sorts in place and returns None. Assigning x = x.sort() silently destroys your list.
  • Prove it: the graded lab at the end runs in your browser - implement the functions and make every check green.
In this lesson you will:
  • Use integer and float math for subnet sizing and utilization numbers
  • Convert parsed text to numbers (and dodge the string-math trap)
  • Read and write files safely with the with statement
  • Index, slice, and grow lists of interfaces, VLANs, and config lines
  • Know when sorted() and .sort() behave differently - and why it bites

Numbers: subnet math without a calculator tab

Python has two numeric types you’ll use constantly: integers (int) for things you count - ports, VLANs, prefix lengths - and floats (float) for things you measure - utilization, error rates. The operators are mostly what you’d expect, plus three that matter more in networking than anywhere else:

>>> 2 ** (32 - 24) - 2     # ** is exponent: usable hosts in a /24
254
>>> 48 // 12               # // is integer division (no remainder)
4
>>> 530 % 48               # % is modulo: the remainder
2

That first line is the one to tattoo somewhere: a /26 has 2 ** (32 - 26) - 2 = 62 usable addresses, and now you never count on your fingers during a design review again. (That is the traditional formula for normal IPv4 LAN subnets; /31 point-to-points and /32 host routes are special cases, and Lesson 9 shows the production-safe library version.) Division with / always returns a float, which pairs with round() for human-readable reporting:

>>> used, total = 87, 254
>>> round(used / total * 100, 1)
34.3

Files: configs live on disk, not in single lines

Lesson 1 parsed one line at a time. Real work starts with whole files - saved configs, inventory exports, show output you redirected last night. The professional pattern is the with statement:

with open("acc-sw03.cfg") as f:
    config = f.read()

lines = config.splitlines()

with guarantees the file gets closed when the block ends - including when your code crashes halfway through. The bare f = open(...) form you’ll see in old scripts leaks file handles when things go wrong; just don’t.

From a file on disk to a list you can work with
Rendering diagram…
View diagram source - it's just text (Mermaid). Diagrams-as-code is how modern network docs work; the flagship course has a free module on it.
flowchart LR
  A[/"acc-sw03.cfg<br/>(on disk)"/] -- "with open(...)" --> B["file object f"]
  B -- ".read()" --> C["one big string"]
  C -- ".splitlines()" --> D["['hostname acc-sw03',<br/>'vlan 10', ..., 'end']"]
  D -- "lines[-1]" --> E["'end'"]

Two reading styles cover nearly everything:

  • f.read() - the whole file as one string. Pair with .splitlines() to get a clean list of lines with no trailing \n characters.
  • f.readlines() - a list of lines with their newlines still attached. Usually the wrong choice for exactly that reason.

Writing is the same shape with a mode argument:

with open("pre-check-acc-sw03.txt", "w") as f:
    f.write(version_output)

Lists: the container you’ll use every single day

A list is an ordered, changeable collection - and almost everything in network automation arrives as one: lines of a config, interfaces on a switch, devices in a site.

>>> uplinks = ["Gi1/0/1", "Gi1/0/2", "Te1/1/1", "Te1/1/2"]
>>> len(uplinks)
4
>>> uplinks[0]          # indexing starts at ZERO
'Gi1/0/1'
>>> uplinks[-1]         # negatives count from the end
'Te1/1/2'

Slicing pulls out sub-lists with [start:stop] - start included, stop excluded:

>>> uplinks[0:2]
['Gi1/0/1', 'Gi1/0/2']
>>> uplinks[-2:]        # everything from the second-to-last on: the tens
['Te1/1/1', 'Te1/1/2']

Omitting an endpoint means “from the beginning” or “to the end” - so lines[:10] is the first ten lines of a config and lines[-5:] is the last five. Lists grow and reorganize in place:

>>> vlans = [10, 30, 20]
>>> vlans.append(40)        # add one item to the end
>>> vlans
[10, 30, 20, 40]
>>> sorted(vlans)           # returns a NEW sorted list
[10, 20, 30, 40]
>>> vlans                   # the original is untouched
[10, 30, 20, 40]

And because a config is just a list of strings once you .splitlines() it, everything from Lesson 1 composes with everything above:

Subnet math and slicing config lines
Try it yourself (Python runs in your browser)
Output appears here. First run downloads the Python runtime (~10 MB), so give it a few seconds.

Prove it (graded lab)

Write each function in the editor, then Run grader - it runs the lesson’s real checks right here in your browser, nothing to install. Green means the skill is yours, and these are the building blocks the Lesson 10 capstone (netaudit) is assembled from.

Five functions:

  1. usable_hosts(prefix_len) - usable host count for a prefix length
  2. utilization_pct(used, total) - percentage utilization, one decimal place
  3. read_config_lines(path) - a file’s lines as a clean list (no newlines)
  4. get_uplinks(interfaces) - the last two interfaces in a list
  5. add_vlan(vlans, vlan_id) - a new sorted list with the VLAN added
Graded lab - 5 checks, run right here
Edit the functions above, then Run grader. First run downloads the Python runtime (~10 MB), so give it a few seconds.
Reveal a reference solution
"""Lesson 2 reference solutions. Read after an honest attempt."""


def usable_hosts(prefix_len):
    return 2 ** (32 - prefix_len) - 2


def utilization_pct(used, total):
    return round(used / total * 100, 1)


def read_config_lines(path):
    with open(path) as f:
        return f.read().splitlines()


def get_uplinks(interfaces):
    return interfaces[-2:]


def add_vlan(vlans, vlan_id):
    return sorted(vlans + [vlan_id])

Read it, close it, then re-type your own version from memory. Wrong turns are where the learning is.

Check your understanding

A /26 subnet - how many usable host addresses, and which expression computes it?

1 / 3

Summary

Integer math (**, //, %) handles subnet sizing - 2 ** (32 - prefix) - 2

  • and floats with round() handle utilization reporting, but only after you int() whatever you parsed, because parsed text is always strings. The with open(...) statement is the only file-reading pattern worth learning, and .read().splitlines() hands you a config as a clean list. Lists index from zero, slice with [start:stop], grow with .append(), and hide one classic trap: in-place methods like .sort() return None. Next lesson: conditionals and loops - where your scripts finally start making decisions about every line in that config, not just the ones you point at.