Python for network engineers: the exam subset

Updated October 9, 2026

Python on the 200-901 CCNA Automation exam (formerly DevNet Associate) is not a programming test. It is a reading test: you get a short script or a code fragment and must say what it prints, what it sends, or why it fails. The decision rule is to know seven things cold: the four core data types (list, tuple, dict, string), how to index them, loops and comprehensions, defining and calling a function, json.loads against json.dumps, one requests call with its status handling, and which except clause catches which error. Everything below is that subset, and every snippet in this guide was run before it was written down.

The seven things, as a cheat sheet

SkillMinimal formWhat the exam asks about it
Listvlans = [10, 20, 30]Indexing (vlans[0] is 10, vlans[-1] is 30), append, mutability
Tuplemgmt = ("10.0.0.1", 22)Immutable: assigning to an item raises TypeError
Dictionaryd = {"hostname": "sw1"}d["k"] raises KeyError if missing; d.get("k", default) does not
Loopfor name, value in d.items():What gets printed; items() yields key and value pairs
Functiondef f(ids, prefix="VLAN"):Default arguments, return versus printing
JSONjson.loads(text)String to Python object, versus dumps the other way
HTTP callrequests.get(url, timeout=5)Status code, raise_for_status(), .json()

Data types and the errors they raise

A dictionary holds a device record, and its values can be any type, including lists and tuples:

device = {"hostname": "sw1", "vlans": [10, 20, 30], "mgmt": ("10.0.0.1", 22), "up": True}
device["vlans"].append(40)        # lists are mutable: now [10, 20, 30, 40]
device["mgmt"][1] = 830           # TypeError: 'tuple' object does not support item assignment
device.get("model", "unknown")    # 'unknown', no error
device["model"]                   # KeyError: 'model'

Running this produces exactly the errors in the comments. The distinction the exam leans on is mutable versus immutable: lists and dictionaries change in place, tuples and strings do not. Another is that a JSON true becomes Python True, null becomes None, an object becomes a dict and an array becomes a list, which is the mapping the Python json documentation defines.

Loops, comprehensions and functions

A list comprehension is a loop that builds a list. This function returns VLAN names while skipping VLAN 1:

def vlan_names(ids, prefix="VLAN"):
    return [f"{prefix}{i}" for i in ids if i != 1]

print(vlan_names(device["vlans"]))   # ['VLAN10', 'VLAN20', 'VLAN30', 'VLAN40']

Read comprehensions right to left in your head: for each i in ids, keep it if i != 1, then format it. A return hands a value back to the caller; a function with only print returns None, a classic trap in “what does this assign to x” questions.

Reading JSON from an API

Most network automation code is “fetch JSON, pick fields”. Given a text body, json.loads turns it into nested Python objects and you index into them:

import json
text = '{"interfaces": [{"name": "Gi1", "enabled": true}, {"name": "Gi2", "enabled": false}]}'
data = json.loads(text)
[i["name"] for i in data["interfaces"] if i["enabled"]]   # ['Gi1']

loads reads from a string and load reads from a file object; dumps and dump are the writing equivalents. The trailing “s” stands for string. For the format comparison itself, see JSON vs YAML vs XML.

One requests call, with error handling

This function fetches a list, treats HTTP errors and network errors separately, and returns an empty list on failure. It was tested against a local test server returning 200 and 404:

import requests

def get_items(url):
    try:
        r = requests.get(url, headers={"Accept": "application/json"},
                         params={"limit": 5}, timeout=5)
        r.raise_for_status()
        return r.json()["items"]
    except requests.exceptions.HTTPError as e:
        print("HTTP error:", e.response.status_code)
    except requests.exceptions.ConnectionError:
        print("cannot connect")
    except (KeyError, ValueError) as e:
        print("bad body", repr(e))
    return []

Three behaviours are testable. params= is appended to the URL as a query string (...?limit=5). raise_for_status() raises HTTPError for 4xx and 5xx responses, and does nothing for 2xx; without it a 404 is not an exception, and r.status_code just holds 404. json= on a request sends a dictionary as a JSON body and sets the content type, which the requests quickstart documents. The wider HTTP and status code picture is in REST API basics.

try, except, else, finally

except runs when the matching error is raised, else runs only when no error was raised, and finally always runs. With int("12") inside the try, the else and finally blocks both print; with int("ab"), a ValueError goes to the except and the else is skipped. Order matters: Python uses the first except that matches, so a broad except Exception placed first hides the specific clauses under it.

Which exams test this

ExamHow the topic appearsWhere on this site
200-901Software Development and Design: parsing XML, JSON and YAML into Python data structures and organising code into functions, classes and modules. Understanding and Using APIs: a Python script that calls a REST API with requests. Cisco Platforms and Development: a script that uses a Cisco SDK. Application Deployment and Security: a Python unit test. Infrastructure and Automation: identify the workflow of a Python script that uses Cisco APIsSoftware development and design, APIs explained

The CCNA (200-301) outline does not ask you to read Python in either version: v1.1 (until Feb 2, 2027) covers automation concepts, REST APIs and JSON-encoded data, and v2.0 (from Feb 3, 2027) covers management approaches and Ansible. The scripting-heavy exam in this family is 200-901, and the 200-901 cheat sheet keeps the requests call and status codes on one page.

How the questions are built

Questions give a script of five to ten lines and ask for the output, the error, or the missing line. The traps are repetitive, which is good news:

  • Index versus key. data["interfaces"][0]["name"] fails if you mix up list positions and dictionary keys. Trace each bracket and name the type before it.
  • loads versus dumps. One goes string to object, the other object to string.
  • Status code without exception. A 404 does not raise unless raise_for_status() is called. Questions that say “the script continues with an empty result” are about exactly this.
  • Which exception. A missing key is KeyError, a bad number string is ValueError, a refused connection is ConnectionError, a 4xx or 5xx after raise_for_status() is HTTPError.
  • Missing timeout. requests has no default timeout, so a script can hang; options mentioning a timeout are usually right when the scenario is about a hung call.

Question 1. A script runs r = requests.get(url) against a REST endpoint that returns HTTP 404, then executes items = r.json()['items'] without any other checks or try blocks. The response body is valid JSON that contains {'error': 'not found'}. What happens?

  • A. requests.exceptions.HTTPError is raised by the get call
  • B. requests.exceptions.ConnectionError is raised by the get call
  • C. KeyError is raised when items is read from the parsed body
  • D. ValueError is raised because the body is not valid JSON
Show answer

Answer: C

Without raise_for_status(), requests does not treat a 404 as an exception, and r.json() parses the body successfully. The failure comes from indexing: the parsed dictionary has no key named items, so Python raises KeyError. HTTPError is only raised by raise_for_status(). ConnectionError means the server could not be reached, which is not the case. A ValueError would need a body that is not valid JSON.

Question 2. A script stores a switch management address as mgmt = ('10.0.0.1', 22) and later runs mgmt[1] = 830 to change the port. What is the result and the best fix?

  • A. KeyError; use mgmt.get(1, 830) instead
  • B. TypeError; store the values in a list or dictionary instead of a tuple
  • C. IndexError; add a third element to the tuple first
  • D. No error; the tuple updates and prints (10.0.0.1, 830)
Show answer

Answer: B

A tuple is immutable, so item assignment raises TypeError. Because the data must change, store it in a mutable type such as a list or a dictionary with named keys, or build a new tuple. Using .get() applies to dictionaries and would not apply to a tuple. A KeyError belongs to missing dictionary keys, and catching the error would leave the port unchanged.

Go deeper