Conditionals: code that judges
Everything in automation reduces to questions with yes/no answers. Is this
line an interface? Is this VLAN in the voice range? Does this config contain
aaa new-model? In Python, a question is an expression that evaluates to a
boolean — True or False:
>>> vlan = 150
>>> vlan >= 100
True
>>> vlan == 150 # == asks; = assigns
True
>>> "aaa new-model" in config
False
if acts on the answer, elif chains more questions, else catches
everything left:
if vlan < 100:
role = "users"
elif vlan < 200:
role = "voice"
elif vlan < 300:
role = "management"
else:
role = "other"
The indented block under each branch is what runs — indentation isn’t
style in Python, it is the syntax. Four spaces, consistently, never tabs.
Combine conditions with and, or, and not:
if line.startswith("interface") and "Te" in line:
print("found an uplink stanza")
One more idea that makes code read like English — truthiness. Empty
things ("", [], 0) count as False; non-empty things count as True:
if matches: # "if we found anything"
print(f"{len(matches)} findings")
else:
print("clean")
Loops: code that scales
A for loop runs a block once per item in a list. That’s the whole
mechanism — and it’s the difference between checking one switch and checking
the district:
devices = ["den-acc-sw01", "den-acc-sw02", "den-core-sw01"]
for device in devices:
print(f"auditing {device}...")
You choose the loop variable’s name. Choose well — for line in lines,
for intf in interfaces, for device in devices read like sentences;
for x in y reads like a puzzle.
The accumulator pattern — most of parsing is this
Start with an empty list, loop, keep what matches:
interfaces = []
for line in config_lines:
if line.startswith("interface "):
interfaces.append(line)
Four lines, and you’ve filtered a 400-line config down to its interface stanzas. Lesson 5 adds regex for fancier matching and Lesson 6 wraps this in reusable functions, but the skeleton never changes: empty list → loop → condition → append.
enumerate(): findings need line numbers
An audit finding without a line number is a scavenger hunt.
enumerate(lines) yields (index, item) pairs:
for i, line in enumerate(config_lines):
if "switchport mode trunk" in line:
print(f"line {i + 1}: {line.strip()}")
(The i + 1 is because humans count config lines from 1, not 0.)
break and continue — loop steering
break exits the loop entirely (you found what you came for);
continue skips to the next item (this one doesn’t apply):
for line in config_lines:
if line.startswith("!"):
continue # comment separator — skip it
if line == "end":
break # nothing meaningful after this
process(line)
Output appears here. First run downloads the Python runtime (~10 MB), so give it a few seconds.
Exercises (graded)
cd labs/python-foundations/lesson03
pytest -q
Five functions in exercises.py — number five is the first real audit:
classify_vlan(vlan_id)— map a VLAN ID to its role by rangefind_interfaces(config_lines)— all lines that open an interface stanzacount_matching(lines, text)— how many lines containtextaccess_ports(interfaces)— everything that isn’t a TenGig uplinkmissing_descriptions(config_lines)— challenge: interface names whose next line is not a description (a real compliance check — combine enumerate, indexing, and.startswith())
Your script dies with SyntaxError pointing at: if hostname = "den-core-sw01": — what is wrong?
After: found = [] / for v in [10, 150, 250, 20]: / if v < 100: found.append(v) — what is found?
What does "if matches:" test, given matches is a list your loop built?
Summary
Conditionals turn facts into decisions: if/elif/else branch on comparisons
(==, not =), joined by and/or/not, with truthiness letting
if matches: read as plain English. Loops apply those decisions at scale:
for line in lines visits everything, the accumulator pattern (empty list →
loop → condition → append) filters configs in four lines, enumerate()
attaches the line numbers an audit needs, and break/continue steer.
You also learned the silent-bug rule: never modify a list mid-loop — build a
new one. Next lesson: dictionaries and sets, where device inventories stop
being parallel lists and start being real data structures.