Unit 4 — Control Flow — Making Decisions in Network Scripts
if / elif / else — Making Decisions
hostname = "sw-core-01"
if hostname.startswith("sw"):
device_type = "switch"
elif hostname.startswith("rtr"):
device_type = "router"
elif hostname.startswith("fw"):
device_type = "firewall"
else:
device_type = "unknown"
print(device_type) # switch
Python evaluates each condition in order and runs the first block that matches. else is optional — it catches everything that did not match.
for Loops and range()
devices = ["sw-core-01", "sw-access-01", "rtr-edge-01"]
for device in devices:
print(device)
range() generates a sequence of numbers:
for i in range(1, 6):
print(i) # 1 2 3 4 5
range(start, stop, step) — stop is not included.
break, continue, and pass
break exits the loop immediately. continue skips to the next iteration. pass does nothing — it is a placeholder for a block of code you have not written yet:
devices = ["sw-core-01", "offline", "rtr-edge-01", "offline", "fw-dmz-01"]
for device in devices:
if device == "offline":
continue # skip offline entries
if device == "fw-dmz-01":
break # stop at the firewall
print(f"Processing {device}")
Use pass when a block is required syntactically but you have nothing to put there yet:
for device in devices:
pass # TODO: implement this
Defining Functions
def get_device_type(hostname, default="unknown"):
"""Return the device type inferred from the hostname prefix."""
if hostname.startswith("sw"):
return "switch"
elif hostname.startswith("rtr"):
return "router"
elif hostname.startswith("fw"):
return "firewall"
return default
print(get_device_type("sw-core-01")) # switch
print(get_device_type("ap-office-01")) # unknown
print(get_device_type("ap-office-01", "access point")) # access point
The triple-quoted string immediately after def is the docstring — a one-line (or multi-line) description of what the function does. Include one on every function you write.
lambda — Small Anonymous Functions
A lambda is a function with no name. It is useful when you need a short function as an argument to sorted(), filter(), or map() — cases where defining a full function would be verbose.
devices = [
{"name": "rtr-edge-01", "site": "Branch"},
{"name": "sw-core-01", "site": "HQ"},
{"name": "fw-dmz-01", "site": "DMZ"},
]
by_name = sorted(devices, key=lambda d: d["name"])
by_site = sorted(devices, key=lambda d: d["site"])
lambda d: d["name"] is equivalent to:
def get_name(d):
return d["name"]
Use lambda for short, one-expression operations. If the logic is longer, write a real function.
args and *kwargs — Flexible Function Arguments
*args lets a function accept any number of positional arguments as a tuple:
def log_devices(*hostnames):
"""Print a processing line for each hostname provided."""
for name in hostnames:
print(f"Processing: {name}")
log_devices("sw-core-01", "rtr-edge-01", "fw-dmz-01")
**kwargs lets a function accept any number of keyword arguments as a dictionary:
def create_device(**fields):
"""Build and return a device record from keyword arguments."""
return fields
d = create_device(name="sw-core-01", ip="10.1.1.1", site="HQ")
print(d) # {'name': 'sw-core-01', 'ip': '10.1.1.1', 'site': 'HQ'}
You will see both constantly when working with automation libraries — functions that accept optional configuration you do not always know in advance.
Summary
if/elif/elseevaluates conditions in order — first match winsforloops iterate over any sequence;range()generates integer sequencesbreakexits a loop;continueskips to the next iteration;passdoes nothing (placeholder)defdefines a function; add a one-line docstring as the first line inside it- Default arguments give parameters a fallback value when nothing is passed
lambdais an anonymous function — useful as an argument tosorted()orfilter()*argscollects extra positional arguments;**kwargscollects extra keyword arguments