Python Basics for Automation — Study Notes

Study notes from Cisco’s CCNA Automation Python livestream — variables, dicts, virtual environments, JSON parsing, the requests library, and API auth, mapped to real security and AWS skills.

From the Cisco “CCNA Automation Prep — Python Basics for Automation” livestream (Oct 15, 2026). Cross-referenced to Black Hat Python and AWS DVA-C02.

1. Running Python

Two ways to run Python: test ideas in the shell, then save working code to a file.

  • python3 -i — opens the interactive shell (the >>> prompt). Type a line, press Enter, see the result. Good for experimenting.
  • python3 filename.py — runs a saved script top to bottom. Use this for real work you keep and rerun.
  • python3 -i filename.py — runs the script, then drops you at >>> with its variables still loaded, so you can inspect them.

On Kali, Debian, and Mac the command is usually python3, not python.

Watch out: slides often use smart curly quotes instead of straight quotes. Copy-pasting them into Python gives a SyntaxError. Type the quotes yourself.

2. Variables and data types

family = "Catalyst"          # string (text, in quotes)
platform_number = 9300        # integer (whole number)
interface_enabled = True      # boolean (True or False, capitalized)
print(f"Switch {family} interface is enabled: {interface_enabled}")
  • The three values show three data types: string, integer, boolean.
  • The f before the quote makes it an f-string. Anything inside { } is replaced with the variable’s value.
  • Output: Switch Catalyst interface is enabled: True

3. Lists

A list is an ordered collection in square brackets.

my_interfaces = ["GigabitEthernet 1", "GigabitEthernet 2"]
print(my_interfaces[1])   # GigabitEthernet 2
my_interfaces.append([24, True, "Default gateway"])
  • Zero-indexing: [0] is the first item, [1] is the second. So my_interfaces[1] prints GigabitEthernet 2, not 1. Most common beginner mistake, and a favorite on exams.
  • .append() adds one item to the end. The slide appends a whole list as a single item, so the result is a list nested inside the list (three items, the third being a list). Use .extend() if you want the items added separately.
  • A list can hold mixed types (24, True, a string all together).

4. Dictionaries

A dictionary stores key: value pairs in curly braces. You look things up by name (the key), not by position.

device_details = {
    "hostname": "sw1",
    "sw_version": 20.4,
    "alerts": False
}
print(device_details["hostname"])   # sw1

Pitfall worth noticing: 20.4 is stored as a number (a float). Software versions should be strings like "20.4". As floats, 20.10 becomes 20.1, and 17.9 compares as greater than 17.12. That kind of bug is easy to miss in real automation scripts.

5. Functions

def add(num1, num2):
    result = num1 + num2
    return result

print(add(3, 4))   # 7
  • def defines a function, a named block of code you reuse.
  • num1, num2 are parameters, placeholders for values you pass in.
  • return sends a value back to whoever called the function.
  • Indentation is the syntax. Python uses the indented lines (not braces) to know what is inside the function. Wrong indentation is one of the most common beginner errors.
  • In automation you would write a function like configure_interface(switch, port) and call it for every port instead of repeating the code.

6. Virtual environments

A virtual environment keeps each project’s packages separate so they don’t conflict with system tools. On modern Kali and Debian, a system-wide pip install is often blocked (“externally-managed-environment” error) — a venv is the clean fix.

python3 -m venv .venv              # create (.venv = hidden folder, common convention)
source .venv/bin/activate          # activate; prompt now shows (.venv)
pip install -r requirements.txt    # install everything the project needs
deactivate                         # turn it off
  • The (.venv) prefix on your prompt confirms it’s active. Any pip install from here lands inside the environment.
  • requirements.txt lists a project’s libraries, one per line. -r means “read the list from this file.”
  • Generate one from an environment you already built: pip freeze > requirements.txt.
  • DVA-C02 tie-in: this is exactly how you package a Lambda function’s dependencies — pip install into a folder, then zip it as the deployment package.

7. Importing libraries

Three sources of code you can pull in:

# Standard library (ships with Python, nothing to install)
import time
time.sleep(30)

# Community library (pip install first)
import requests
requests.get(url)

# Self-made module (your own file, my_custom_math.py next to your script)
import my_custom_math
my_custom_math.add(3, 4)
  • Standard library is built in. time.sleep(30) pauses 30 seconds.
  • Community libraries need pip install first — inside your activated venv, not system-wide. requests is the big one for web APIs.
  • Self-made modules are just your own .py files in the same folder.
  • boto3 (the AWS SDK) is itself a community library you pip install — same pattern as requests.

8. Data formats (Exam 1.2)

Data arrives as text. You turn it into a Python object to work with it, then back to text to send it. This is the single most important slide for AWS: almost every AWS API returns JSON, which boto3 parses into dicts and lists for you.

import json, yaml

# Text -> Python dict
device = json.loads(json_text)
device = yaml.safe_load(yaml_text)   # safe_load refuses hidden code; always use it

# Python dict -> text
body = json.dumps(device, indent=2)

print(device["interfaces"][0])       # GigabitEthernet1

Memory aid: loads / dumps both have an “s” for string (in / out). The versions without s (json.load / json.dump) work on files.

XML is a tree of tags, not key-value pairs:

import xml.etree.ElementTree as ET
root = ET.fromstring(xml_text)
name = root.find("hostname").text          # first matching tag's text
for intf in root.findall("interface"):     # every matching tag
    print(intf.find("name").text)
# intf.get("id") reads an attribute

YAML tie-in: CloudFormation and SAM templates are YAML, which maps to the same dict structure as JSON.

9. The requests library

Authenticate once, get a token back, then use the token on later requests.

import requests

url = "https://198.18.129.100/dna/system/api/v1/auth/token"
response = requests.request("POST", url, auth=(username, password), verify=False)
token = response.json()["Token"]
  • POST sends data (here, credentials); GET retrieves. The /auth/token path trades a username and password for a token.
  • auth=(username, password) is HTTP Basic Auth.
  • response.json()["Token"] parses the JSON reply into a dict and pulls out the token.

Two security flags (demo shortcuts, not for real code):

  1. verify=False disables HTTPS certificate checking. Fine against a lab self-signed cert, but in real code it leaves you open to a man-in-the-middle attack — the same attack type as ARP spoofing.
  2. Never hard-code real credentials in a script. Keep them in a config file (as in your Shodan tool) or, on AWS, in Secrets Manager / Parameter Store.

10. Authentication (Exam 2.7)

Three ways APIs check who you are. Headers are dictionaries (key-value pairs).

MethodLogin step?Where the secret goesAWS equivalent
Basic → tokenYes, onceauth=(...), then token in a headerCognito (issues tokens)
Token on each callUses token from aboveX-Auth-Token headerCognito JWT
API keyNoCustom header or Authorization: BearerAPI Gateway (x-api-key)
# Token on each call
headers = {"X-Auth-Token": token, "Content-Type": "application/json"}
r = requests.get(devices_url, headers=headers)

# API key, no login step
headers = {"X-Cisco-Meraki-API-Key": api_key, "Accept": "application/json"}

# Bearer style (very common standard)
headers = {"Authorization": f"Bearer {token}"}
  • Content-Type = “the data I’m sending is JSON.” Accept = “send me JSON back.”
  • Trade-off: tokens expire (safer if stolen); API keys are long-lived (convenient, but worse if leaked). A leaked long-lived key is the worst case — it works until manually revoked. This is why AWS prefers IAM roles over long-lived access keys, and why bots scan GitHub for exposed keys within minutes.

11. The live demo script

The instructor turned the data-formats slide into runnable code, adding two new ideas: the built-in .json() shortcut and looping over a dictionary.

# json.loads() parses JSON text into a dict
deck = json.loads(response.text)
print("Type:    ", type(deck))

# response.json() is a built-in shortcut for the same thing
print("Same result?  ", deck == response.json())   # True

# json.dumps() goes back: dict -> formatted JSON text
print(json.dumps(deck, indent=2))

# Pull one value by its key
deck_id = deck["deck_id"]

# Loop the whole dict: .items() gives each key and value
for key, value in deck.items():
    print(f"  {key:<10} = {value}")   # :<10 left-aligns in a 10-char column
  • In real code you’ll use response.json(), not json.loads(response.text).
  • The for key, value in ...items() loop is how you walk an entire API response instead of grabbing one field — the most useful single technique in the session.
  • type(deck) confirms it’s a dict, reinforcing that AWS responses are dicts you navigate by key.

12. Pattern to memorize + security watch-list

The three-command setup for every new Python project:

python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

Security watch-list from this session (carry forward, don’t copy into real code):

  • verify=False — disables HTTPS cert checking; opens you to man-in-the-middle. Lab only.
  • Hard-coded credentials — keep secrets in a config file or a secrets manager, never in the code or in git.
  • yaml.safe_load — always use it over yaml.load, which can execute hidden code.
  • Long-lived API keys — the worst thing to leak; prefer expiring tokens / IAM roles.

How the session maps to your two exams:

  • DVA-C02: JSON parsing (response.json()), requests as the raw version of boto3, Bearer tokens = Cognito, API keys = API Gateway, Secrets Manager for credentials, venv + requirements.txt = Lambda packaging.
  • Black Hat Python: requests, import, and the venv habit are exactly what your Shodan and future API tools use; the man-in-the-middle idea behind verify=False is the ARP-spoofing tutorial you’re planning.