⚡ IT Wisdom I asked the AI to write a bash script. Now my server is on fire and my files are somewhere in /dev/null.
Skilled Practitioner
4249 XP 1751 to Expert
Units
Whetting Your Appetite — Why Python for Networking? Using the Python Interpreter An Informal Introduction to Python — Network Basics Control Flow — Making Decisions in Network Scripts Data Structures — Modeling Network Inventories Modules — Organizing Your Network Scripts Input and Output — Reading and Writing Network Data Errors and Exceptions — Building Reliable Network Scripts Classes — Modeling Network Devices as Objects Standard Library Part I — Tools Every Network Script Needs Standard Library Part II — Logging, Formatting, and Counting Virtual Environments and Packages — Isolating Your Dependencies Capstone — Build a Network Inventory Tool

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/else evaluates conditions in order — first match wins
  • for loops iterate over any sequence; range() generates integer sequences
  • break exits a loop; continue skips to the next iteration; pass does nothing (placeholder)
  • def defines a function; add a one-line docstring as the first line inside it
  • Default arguments give parameters a fallback value when nothing is passed
  • lambda is an anonymous function — useful as an argument to sorted() or filter()
  • *args collects extra positional arguments; **kwargs collects extra keyword arguments