Python Fundamentals
The building blocks. Master these cold before moving on.
Variables & Types
Basic Types
# Strings
hostname = "ise-01.inside.domusdigitalis.dev"
ip = "10.50.1.20"
# Numbers
port = 443
timeout = 30.5
vlan_id = 10
# Booleans
is_active = True
has_certificate = False
# None
result = None
Type Checking
# Check type
type(hostname) # <class 'str'>
type(port) # <class 'int'>
type(timeout) # <class 'float'>
# isinstance (preferred)
isinstance(port, int) # True
isinstance(port, (int, float)) # True - multiple types
Type Conversion
# String to int
port = int("443")
# Int to string
port_str = str(443)
# String to float
timeout = float("30.5")
# To boolean
bool("") # False
bool("text") # True
bool(0) # False
bool(1) # True
bool([]) # False
bool([1,2]) # True
Strings
String Operations
hostname = "ise-01.inside.domusdigitalis.dev"
# Length
len(hostname) # 32
# Case
hostname.upper() # "ISE-01.INSIDE.DOMUSDIGITALIS.DEV"
hostname.lower() # "ise-01.inside.domusdigitalis.dev"
hostname.title() # "Ise-01.Inside.Domusdigitalis.Dev"
# Check content
hostname.startswith("ise") # True
hostname.endswith(".dev") # True
"inside" in hostname # True
# Split and join
parts = hostname.split(".") # ["ise-01", "inside", "domusdigitalis", "dev"]
".".join(parts) # Back to original
# Strip whitespace
" spaced ".strip() # "spaced"
" spaced ".lstrip() # "spaced "
" spaced ".rstrip() # " spaced"
# Replace
hostname.replace("ise-01", "ise-02")
F-Strings (Formatted Strings)
hostname = "ise-01"
ip = "10.50.1.20"
port = 443
# Basic interpolation
url = f"https://{hostname}:{port}/api"
# Expressions inside
msg = f"Port {port} is {'open' if port == 443 else 'closed'}"
# Formatting numbers
pi = 3.14159
f"{pi:.2f}" # "3.14" - 2 decimal places
f"{1000000:,}" # "1,000,000" - thousands separator
f"{port:05d}" # "00443" - zero-padded
# Width and alignment
f"{'left':<10}" # "left "
f"{'right':>10}" # " right"
f"{'center':^10}" # " center "
Raw Strings & Multiline
# Raw string (no escape processing) - good for regex
pattern = r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"
# Multiline
config = """
interface GigabitEthernet0/1
description Uplink to Core
switchport mode trunk
"""
# Multiline with f-string
vlan = 10
interface = f"""
interface Vlan{vlan}
ip address 10.50.{vlan}.1 255.255.255.0
no shutdown
"""
Operators
Arithmetic
a, b = 10, 3
a + b # 13 - addition
a - b # 7 - subtraction
a * b # 30 - multiplication
a / b # 3.333... - division (float)
a // b # 3 - floor division (int)
a % b # 1 - modulo (remainder)
a ** b # 1000 - power
# Augmented assignment
count = 0
count += 1 # count = count + 1
count -= 1 # count = count - 1
count *= 2 # count = count * 2
Comparison
a, b = 10, 20
a == b # False - equal
a != b # True - not equal
a < b # True - less than
a <= b # True - less than or equal
a > b # False - greater than
a >= b # False - greater than or equal
# Chained comparisons
x = 15
10 < x < 20 # True - x is between 10 and 20
# Identity (same object, not just equal value)
a = [1, 2, 3]
b = [1, 2, 3]
c = a
a == b # True - same value
a is b # False - different objects
a is c # True - same object
Logical
# and - both must be True
True and True # True
True and False # False
# or - at least one True
True or False # True
False or False # False
# not - invert
not True # False
not False # True
# Practical example
is_admin = True
is_active = True
has_permission = False
# Access granted if admin AND active, OR has explicit permission
can_access = (is_admin and is_active) or has_permission
Control Flow
if/elif/else
status_code = 200
if status_code == 200:
print("Success")
elif status_code == 404:
print("Not Found")
elif status_code >= 500:
print("Server Error")
else:
print(f"Unknown status: {status_code}")
# Ternary (inline if)
result = "Success" if status_code == 200 else "Error"
# Multiple conditions
if status_code == 200 and response_time < 1.0:
print("Fast success")
match (Python 3.10+)
status_code = 404
match status_code:
case 200:
print("OK")
case 301 | 302:
print("Redirect")
case 400:
print("Bad Request")
case 404:
print("Not Found")
case _ if status_code >= 500:
print("Server Error")
case _:
print("Unknown")
# Pattern matching with structure
response = {"status": "error", "code": 500}
match response:
case {"status": "ok", "data": data}:
print(f"Got data: {data}")
case {"status": "error", "code": code}:
print(f"Error {code}")
for Loops
# Iterate over list
hosts = ["ise-01", "ise-02", "ise-03"]
for host in hosts:
print(host)
# With index
for i, host in enumerate(hosts):
print(f"{i}: {host}")
# Iterate over dict
config = {"hostname": "ise-01", "ip": "10.50.1.20", "port": 443}
for key in config:
print(key)
for key, value in config.items():
print(f"{key} = {value}")
# Range
for i in range(5): # 0, 1, 2, 3, 4
print(i)
for i in range(1, 6): # 1, 2, 3, 4, 5
print(i)
for i in range(0, 10, 2): # 0, 2, 4, 6, 8 (step by 2)
print(i)
while Loops
# Basic while
count = 0
while count < 5:
print(count)
count += 1
# With break
while True:
response = check_status()
if response == "ready":
break
time.sleep(1)
# With continue
for i in range(10):
if i % 2 == 0: # Skip even numbers
continue
print(i) # Only prints odd: 1, 3, 5, 7, 9
# While with else (runs if no break)
attempts = 0
while attempts < 3:
if try_connect():
print("Connected!")
break
attempts += 1
else:
print("Failed after 3 attempts")
Exception Handling
try/except
# Basic
try:
result = 10 / 0
except ZeroDivisionError:
print("Cannot divide by zero")
# Multiple exceptions
try:
value = int(user_input)
except ValueError:
print("Invalid number")
except TypeError:
print("Wrong type")
# Catch multiple in one
try:
risky_operation()
except (ValueError, TypeError) as e:
print(f"Error: {e}")
# Catch all (use sparingly)
try:
risky_operation()
except Exception as e:
print(f"Unexpected error: {e}")
try/except/else/finally
try:
file = open("config.json")
data = json.load(file)
except FileNotFoundError:
print("Config not found")
data = {}
except json.JSONDecodeError:
print("Invalid JSON")
data = {}
else:
# Runs only if no exception
print(f"Loaded {len(data)} items")
finally:
# Always runs (cleanup)
if 'file' in locals():
file.close()
# Better: context manager
try:
with open("config.json") as f:
data = json.load(f)
except (FileNotFoundError, json.JSONDecodeError) as e:
print(f"Error loading config: {e}")
data = {}
Raising Exceptions
def validate_ip(ip: str) -> bool:
parts = ip.split(".")
if len(parts) != 4:
raise ValueError(f"Invalid IP format: {ip}")
for part in parts:
if not part.isdigit() or not 0 <= int(part) <= 255:
raise ValueError(f"Invalid octet: {part}")
return True
# Re-raise with context
try:
validate_ip(user_input)
except ValueError as e:
raise ValueError(f"Configuration error: {e}") from e
Practice Exercises
Exercise 1: Parse ISE Hostname
# Given: "ise-psn-01.inside.domusdigitalis.dev"
# Extract: role (psn), number (01), domain (inside.domusdigitalis.dev)
hostname = "ise-psn-01.inside.domusdigitalis.dev"
# Solution
parts = hostname.split(".")
node_parts = parts[0].split("-")
role = node_parts[1] # "psn"
number = node_parts[2] # "01"
domain = ".".join(parts[1:]) # "inside.domusdigitalis.dev"
print(f"Role: {role}, Number: {number}, Domain: {domain}")
Exercise 2: Validate VLAN Range
def is_valid_vlan(vlan_id: int) -> bool:
"""Check if VLAN ID is valid (1-4094, excluding reserved)."""
if not isinstance(vlan_id, int):
return False
if vlan_id < 1 or vlan_id > 4094:
return False
if vlan_id in (1, 1002, 1003, 1004, 1005): # Reserved
return False
return True
# Test
print(is_valid_vlan(10)) # True
print(is_valid_vlan(1)) # False (reserved)
print(is_valid_vlan(5000)) # False (out of range)
Next Module
Data Structures - Lists, dicts, sets, and comprehensions.