Python for network engineers: the exam subset
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
| Skill | Minimal form | What the exam asks about it |
|---|---|---|
| List | vlans = [10, 20, 30] | Indexing (vlans[0] is 10, vlans[-1] is 30), append, mutability |
| Tuple | mgmt = ("10.0.0.1", 22) | Immutable: assigning to an item raises TypeError |
| Dictionary | d = {"hostname": "sw1"} | d["k"] raises KeyError if missing; d.get("k", default) does not |
| Loop | for name, value in d.items(): | What gets printed; items() yields key and value pairs |
| Function | def f(ids, prefix="VLAN"): | Default arguments, return versus printing |
| JSON | json.loads(text) | String to Python object, versus dumps the other way |
| HTTP call | requests.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
| Exam | How the topic appears | Where on this site |
|---|---|---|
| 200-901 | Software 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 APIs | Software 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. loadsversusdumps. One goes string to object, the other object to string.- Status code without exception. A
404does not raise unlessraise_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 isValueError, a refused connection isConnectionError, a 4xx or 5xx afterraise_for_status()isHTTPError. - Missing timeout.
requestshas 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
- Python tutorial: errors and exceptions on docs.python.org
- Python json module
- Requests quickstart
- Next topics: REST API basics, REST, NETCONF and RESTCONF, JSON vs YAML vs XML, and how to practise in how to study for certification exams.