Dictionaries

User Input & While Loops

Session 3 — Chapter 5: Dictionaries · Chapter 6: User Input and While Loops

SEC1302 · Python for Information Security

>>> service = {"name": "ssh", "port": 22, "state": "open"}
>>> while service["state"] == "open":
... print(f"Monitoring port {service['port']}")
... break
Monitoring port 22

Agenda

Chapter 5. Dictionaries

5.1 A Simple Dictionary Example

5.2 Working with Dictionaries

  • 5.2.1 Accessing values
  • 5.2.2 Adding new key-value pairs
  • 5.2.3 Starting with an empty dictionary
  • 5.2.4 Modifying values in a dictionary
  • 5.2.5 Removing key-value pairs
  • 5.2.6 A dictionary of similar objects
  • 5.2.7 Using get() to access values safely

5.3 Looping Through a Dictionary

  • 5.3.1 Looping through all key-value pairs (items)
  • 5.3.2 Looping through all keys (keys)
  • 5.3.3 Looping through keys in a specific order (sorted)
  • 5.3.4 Looping through all values (values, set)

5.4 Nesting

  • 5.4.1 A list of dictionaries
  • 5.4.2 A list in a dictionary
  • 5.4.3 A dictionary in a dictionary

Chapter 6. User Input and While Loops

6.1 How the input() Function Works

  • 6.1.1 Writing clear prompts
  • 6.1.2 Using int() to accept numerical input
  • 6.1.3 The modulo operator

6.2 Introducing while Loops

  • 6.2.1 The while loop in action
  • 6.2.2 Letting the user choose when to quit
  • 6.2.3 Using a flag
  • 6.2.4 Using break to exit a loop
  • 6.2.5 Using continue in a loop
  • 6.2.6 Avoiding infinite loops

6.3 Using while Loops with Lists and Dictionaries

  • 6.3.1 Moving items from one list to another
  • 6.3.2 Removing all instances of specific values from a list
  • 6.3.3 Filling a dictionary with user input

Exercises & Session Synthesis

Session Learning Outcomes

1

Construct and manipulate Python dictionaries

Perform key-based lookups, insertions, updates, deletions, and defensive retrieval with get().

2

Iterate through complex mappings

Traverse keys, values, and items; apply sorting and set deduplication to dictionary components.

3

Design nested data architectures

Model structured data using lists of dictionaries, lists within dictionaries, and hierarchical dictionaries (JSON / REST API format).

4

Control program execution with input() and while loops

Implement sentinel quits, boolean flags, break/continue flow controls, and queue processing.

Mapped to CLO1 — apply Python data structures and iterative control flows to program technical utilities (C3-P2).

Introduction to Python Dictionaries

A dictionary in Python is an unordered collection of key-value pairs (ordered by insertion since Python 3.7).

Each key is connected to a value; a key can be used to retrieve, modify, or delete its associated value.

Written with curly braces { }, with key-value pairs separated by commas, and keys separated from values by colons.

alien_0 = {'color': 'green', 'points': 5}
print(alien_0)
{'color': 'green', 'points': 5}

Real-world Information Security analogy

  • IP address to hostname mappings (DNS cache).
  • User IDs mapped to cryptographic hash digests.
  • Network interface names mapped to MAC addresses.

Accessing Values by Key

To access a value, write the dictionary name followed by the key in square brackets: dict[key].

Python searches the hash table and returns the associated value directly.

alien_0 = {'color': 'green', 'points': 5}
print(alien_0['color'])
new_points = alien_0['points']
print(f"You just earned {new_points} points!")
green
You just earned 5 points!

Adding New Key-Value Pairs

Dictionaries are dynamic structures: new key-value pairs can be added at any time.

Syntax: dict[new_key] = new_value.

New entries are appended to the dictionary's internal mapping, preserving insertion order.

alien_0 = {'color': 'green', 'points': 5}
print(alien_0)
alien_0['x_position'] = 0
alien_0['y_position'] = 25
print(alien_0)
{'color': 'green', 'points': 5}
{'color': 'green', 'points': 5', 'x_position': 0, 'y_position': 25}

Initializing and Populating an Empty Dictionary

It is standard practice to define an empty dictionary using empty curly braces {} or dict() and populate it as runtime data arrives.

Particularly common when parsing network packets, ingesting JSON configuration files, or harvesting user input.

alien_0 = {}
alien_0['color'] = 'green'
alien_0['points'] = 5
print(alien_0)
{'color': 'green', 'points': 5}

Modifying Values in a Dictionary

To modify a value, assign a new value to an existing key: dict[existing_key] = new_value.

Enables state tracking in monitoring systems, game engines, and network telemetry.

alien_0 = {'x_position': 0, 'y_position': 25, 'speed': 'medium'}
print(f"Original position: {alien_0['x_position']}")
# Move alien to the right based on current speed
if alien_0['speed'] == 'slow':
    x_increment = 1
elif alien_0['speed'] == 'medium':
    x_increment = 2
else:
    x_increment = 3
alien_0['x_position'] = alien_0['x_position'] + x_increment
print(f"New position: {alien_0['x_position']}")
Original position: 0
New position: 2

Removing Key-Value Pairs

When a piece of information is no longer needed, use the del statement with the key: del dict[key].

The deletion removes both the key and its associated value permanently.

alien_0 = {'color': 'green', 'points': 5}
print(alien_0)
del alien_0['points']
print(alien_0)
{'color': 'green', 'points': 5}
{'color': 'green'}

Structuring a Dictionary of Similar Objects

While a dictionary can store multiple attributes of one object (an alien), it can also store one attribute across many objects (favorite programming languages of team members).

Multi-line formatting: PEP 8 recommends placing each key-value pair on its own indented line, with a closing brace on a new line matching the indentation.

favorite_languages = {
    'jen': 'python',
    'sarah': 'c',
    'edward': 'ruby',
    'phil': 'python',
}
language = favorite_languages['sarah'].title()
print(f"Sarah's favorite language is {language}.")
Sarah's favorite language is C.

Defensive Key Retrieval with get()

Using square bracket notation dict[key] on an absent key terminates execution with a KeyError.

The get() method accepts a key and an optional default fallback value: dict.get(key, default).

If the key exists, it returns the corresponding value; if absent, it returns the default (or None if omitted).

alien_0 = {'color': 'green', 'speed': 'slow'}
point_value = alien_0.get('points', 'No point value assigned.')
print(point_value)
missing_value = alien_0.get('points')
print(missing_value)
No point value assigned.
None

Under the Hood: How Python Dictionaries Work

Python dictionaries are implemented using Hash Tables.

When an entry is stored, Python passes the key through the built-in hash() function to compute an integer hash code, which determines the bucket index.

Lookup complexity: O(1) average time complexity for insertion, retrieval, and deletion.

Key Requirements

Keys MUST be immutable (hashable): strings, integers, floats, and tuples containing only immutables.

Lists and dictionaries CANNOT be keys (TypeError: unhashable type: 'list').

print(hash("admin"))  # Returns integer hash
# invalid_dict = {[1, 2]: "forbidden"}
# Raises TypeError: unhashable type: 'list'


Flowchart for algorithm to add element to the hash table of a set


The Old Approach: Single Sparse Hash Table (Before Python 3.6)

Memory structure

Only ONE table. Each slot stores a triple: [hash_code, key_pointer, value_pointer]. With a table size of 8, 5 slots stay empty (NULL).

Example: d = {}; d['timmy'] = 'red'; d['barry'] = 'green'; d['guido'] = 'blue' with hash('timmy') % 8 = 4, hash('barry') % 8 = 1, hash('guido') % 8 = 0.

Query d['timmy'] — 1 step

  1. Hash: compute hash('timmy') % 8 = 4.
  1. Jump: go directly to row 4 of the table.
  1. Verify: the stored hash matches hash('timmy'), and the stored key equals 'timmy'.
  1. Return: read the Value column of row 4 → 'red'.

The New Approach: Compact Hash Table (Python 3.6+)

Memory structure

The data is split into TWO separate arrays: a dense entries array (only the 3 real items, stored in insertion order) and a sparse indices table (small integers pointing to rows in entries, stored as 1-byte int8_t values).

Indices table (8 slots, 1 byte each)

Entries array (dense, in insertion order)

Query d['timmy'] — 2 steps

  1. Hash: compute hash('timmy') % 8 = 4.
  1. Read the index table: indices[4] = 0 (a value of -1 means the key does not exist, so KeyError is raised immediately).
  1. Access the entries array: jump to row 0 of entries.
  1. Verify: the stored hash matches hash('timmy'), and the stored key equals 'timmy'.
  1. Return: entries[0].value → 'red'.

Comparison: Old vs New Hash Table Design

CPython Memory Optimization: Compact and Ordered Dicts

Before Python 3.6: Dictionaries stored hash, key, and value in a single sparse array, wasting substantial memory (dense table with empty slots).

Python 3.6+ (PEP 468 / Raymond Hettinger design): Split into a compact entries array and a small indices array.

"Dictionaries preserve insertion order. Note that updating a key does not affect the order."

Looping Through All Key-Value Pairs with items()

The items() method returns a sequence-like view of key-value tuples: [(k1, v1), (k2, v2), ...].

Use tuple unpacking in a for loop: for key, value in dictionary.items():.

user_0 = {
    'username': 'efermi',
    'first': 'enrico',
    'last': 'fermi',
}
for key, value in user_0.items():
    print(f"Key: {key}")
    print(f"Value: {value} ")
Key: username
Value: efermi
Key: first
Value: enrico
Key: last
Value: fermi

Looping Through All Keys with keys()

The keys() method returns a view of all keys in the dictionary.

Looping through a dictionary directly (for name in dictionary:) defaults to iterating through keys. Explicitly calling .keys() clarifies programmer intent.

favorite_languages = {
    'jen': 'python',
    'sarah': 'c',
    'edward': 'ruby',
    'phil': 'python',
}
friends = ['phil', 'sarah']
for name in favorite_languages.keys():
    print(f"Hi {name.title()}.")
    if name in friends:
        language = favorite_languages[name].title()
        print(f" {name.title()}, I see you love {language}!")
Hi Jen.
Hi Sarah.
  Sarah, I see you love C!
Hi Edward.
Hi Phil.
  Phil, I see you love Python!

Sorting Dictionary Keys During Iteration

A dictionary preserves insertion order, but analytical tasks often require alphabetical or numerical order.

Wrap the keys() method with the sorted() function: for key in sorted(dictionary.keys()):.

favorite_languages = {
    'jen': 'python',
    'sarah': 'c',
    'edward': 'ruby',
    'phil': 'python',
}
for name in sorted(favorite_languages.keys()):
    print(f"{name.title()}, thank you for taking the poll.")
Edward, thank you for taking the poll.
Jen, thank you for taking the poll.
Phil, thank you for taking the poll.
Sarah, thank you for taking the poll.

Looping Through All Values with values()

To access values without regard to their associated keys, use the values() method.

Returns a dict_values view containing all values, including duplicates.

favorite_languages = {
    'jen': 'python',
    'sarah': 'c',
    'edward': 'ruby',
    'phil': 'python',
}
print("The following languages have been mentioned:")
for language in favorite_languages.values():
    print(language.title())
The following languages have been mentioned:
Python
C
Ruby
Python

Extracting Unique Values Using set()

To eliminate duplicate values from a collection, wrap the values() call with the set() function.

A set is an unordered collection in which every element must be unique.

Set literals can also be written using curly braces without colons: {'python', 'c', 'ruby'}.

favorite_languages = {
    'jen': 'python',
    'sarah': 'c',
    'edward': 'ruby',
    'phil': 'python',
}
print("Unique languages mentioned:")
for language in set(favorite_languages.values()):
    print(language.title())
Unique languages mentioned:
Ruby
C
Python

Comparison

Dictionary: {'key': 'value'} → key-value pairs

Set: {'value1', 'value2'} → collection of unique elements

Nesting: Building Complex Data Structures

Nesting refers to storing a list inside a dictionary, a dictionary inside a list, or a dictionary inside another dictionary.

Mimics hierarchical data standards in modern computing: JSON (JavaScript Object Notation) used in REST APIs and web services; YAML configuration files in Kubernetes and cloud deployments; NoSQL document databases like MongoDB.

List of Dictionaries

[ {user1}, {user2}, {user3} ] → Tabular records / fleets.

List in a Dictionary

{ user: ['role1', 'role2'] } → One-to-many relationships.

Dictionary in a Dictionary

{ user1: {profile}, user2: {profile} } → Hierarchical entities.

A List of Dictionaries (Fleet Management Pattern)

Storing multiple individual entities (represented as dictionaries) inside a single list.

Enables batch processing, scaling fleets, and querying database rows.

aliens = []
# Create a fleet of 3 green aliens
for alien_number in range(3):
    new_alien = {'color': 'green', 'points': 5, 'speed': 'slow'}
    aliens.append(new_alien)
# Modify the first alien in the fleet
aliens[0]['color'] = 'yellow'
aliens[0]['speed'] = 'medium'
for alien in aliens:
    print(alien)
{'color': 'yellow', 'points': 5, 'speed': 'medium'}
{'color': 'green', 'points': 5, 'speed': 'slow'}
{'color': 'green', 'points': 5, 'speed': 'slow'}

A List Inside a Dictionary (One-to-Many Relationships)

Storing a list as a dictionary value allows one key to be associated with multiple items.

Example: an order with a list of toppings, or a network firewall host with a list of open ports.

pizza = {
    'crust': 'thick',
    'toppings': ['mushrooms', 'extra cheese'],
}
print(f"You ordered a {pizza['crust']}-crust pizza with:")
for topping in pizza['toppings']:
    print(f" - {topping}")
You ordered a thick-crust pizza with:
 - mushrooms
 - extra cheese

Security Use-case

server = {
    'hostname': 'auth-01',
    'open_ports': [22, 443, 8443]
}

A Dictionary Inside a Dictionary (Hierarchical Records)

Storing a dictionary as the value of another dictionary enables nested namespace structuring.

Common in representing user profiles, configuration trees, and multi-tenant environments.

users = {
    'aeinstein': {
        'first': 'albert',
        'last': 'einstein',
        'location': 'princeton',
    },
    'mcurie': {
        'first': 'marie',
        'last': 'curie',
        'location': 'paris',
    },
}
for username, user_info in users.items():
    print(f" Username: {username}")
    full_name = f"{user_info['first']} {user_info['last']}"
    print(f" Full name: {full_name.title()}")
    print(f" Location: {user_info['location'].title()}")
Username: aeinstein
Full name: Albert Einstein
Location: Princeton
Username: mcurie
Full name: Marie Curie
Location: Paris

Comparison: List vs Tuple vs Dictionary

Security Applications: Dictionaries in InfoSec Systems

JSON Web Tokens (JWT) & Claims

Decoded JWT headers and payloads are Python dictionaries containing standard claims (iss, sub, exp, roles).

HTTP Headers & Request Metadata

Web frameworks (Flask, FastAPI, Django) parse client requests into dictionaries: request.headers['Authorization'].

Log Parsing & Threat Detection

Syslog, Zeek, and Suricata JSON event logs are ingested directly into dictionaries for fast rule-based field inspection.

Vulnerability Data (CVE & NVD)

National Vulnerability Database feeds are structured nested dictionaries containing CVE IDs, CVSS scores, and affected CPE ranges.

Standards Source: RFC 7519 — JSON Web Token (JWT): datatracker.ietf.org/doc/html/rfc7519 · NIST NVD JSON API Schema: nvd.nist.gov/developers/vulnerabilities

How the input() Function Works

The input() function pauses program execution and waits for the user to type text in the console and press Enter.

The entered text is captured and returned as a string (str).

It takes one argument: the prompt string displayed to the user.

message = input("Tell me something, and I will repeat it back to you: ")
print(message)

Interactive Console Simulation

Tell me something, and I will repeat it back to you: Hello everyone!
Hello everyone!

Critical Rule

input() ALWAYS returns a string (str), even if the user types numeric digits (e.g. typing 21 returns "21", not 21).

Writing Clear Prompts and Multi-line Input

Prompts must clearly instruct the user what kind of information is expected.

Add a space at the end of the prompt string to separate the prompt text from the user's cursor.

When instructions exceed one line, build a multi-line prompt string across multiple lines using +=.

prompt = "If you share your name, we can personalize the messages you see."
prompt += " What is your first name? "
name = input(prompt)
print(f" Hello, {name}!")

Interactive Console Simulation

If you share your name, we can personalize the messages you see.
What is your first name? Eric
Hello, Eric!

Best Practice

Clean prompts reduce user entry errors and clarify interface flow.

Converting Input to Numbers with int() and float()

Because input() yields a string, passing it directly to a numerical comparison (<, >) raises TypeError: '<' not supported between instances of 'str' and 'int'.

Use the int() function to convert the input string to an integer, or float() for floating-point decimals.

age = input("How old are you? ")
age = int(age)
if age >= 18:
    print("You are old enough to vote!")
else:
    print("You are not old enough to vote yet.")

Console Simulation

How old are you? 21
You are old enough to vote!

Error Handling Note

If the user inputs non-digit characters (e.g. "twenty"), int() raises ValueError: invalid literal for int() with base 10.

The Modulo Operator (%) in Input Logic

The modulo operator % divides one number by another and returns the remainder (e.g., 7 % 3 is 1).

It does not return the quotient; it returns what remains after integer division.

Core use-case: determining whether an integer is even (number % 2 == 0) or odd (number % 2 != 0).

number = input("Enter a number, and I'll tell you if it's even or odd: ")
number = int(number)
if number % 2 == 0:
    print(f" The number {number} is even.")
else:
    print(f" The number {number} is odd.")

Console Simulation

Enter a number, and I'll tell you if it's even or odd: 42
The number 42 is even.

Security relevance

Modulo arithmetic is the mathematical foundation of public-key cryptography (RSA, Diffie-Hellman).

Introducing while Loops: Condition-Controlled Iteration

A for loop takes a collection of items and executes a code block once for each item in the collection (definite iteration).

A while loop runs as long as (while) a specific condition evaluates to True (indefinite iteration).

while condition:
    # Code block executed repeatedly while condition is True

A while Loop in Action: Counting and State Tracking

A while loop must modify variables involved in the condition to ensure the condition eventually becomes False.

current_number = 1
while current_number <= 5:
    print(current_number)
    current_number += 1
1
2
3
4
5

Step-by-step trace

  1. current_number = 1 <= 5 (True) → print 1, increment to 2
  1. current_number = 2 <= 5 (True) → print 2, increment to 3
  1. ...
  1. current_number = 6 <= 5 (False) → loop terminates.

Interactive Sentinel Loop: Quitting on Command

Define a sentinel value (such as 'quit') that signals the loop to stop.

Initialize the control variable with a non-sentinel value so the loop can start.

prompt = " Tell me something, and I will repeat it back to you:"
prompt += " Enter 'quit' to end the program. "
message = ""
while message != 'quit':
    message = input(prompt)
    if message != 'quit':
        print(message)

Console Simulation

Tell me something, and I will repeat it back to you:
Enter 'quit' to end the program. Hello!
Hello!
Tell me something, and I will repeat it back to you:
Enter 'quit' to end the program. quit

Managing Complex States with a Flag Variable

When many different events or conditions could cause a program to stop running, managing a single condition in the while statement becomes awkward.

A flag variable acts as a master switch: while active:. If any event requires the program to stop, set active = False.

prompt = " Enter 'quit' to exit: "
active = True
while active:
    message = input(prompt)
    if message == 'quit':
        active = False
    elif message == 'lockout':
        print("Security alert: terminal locked.")
        active = False
    else:
        print(f"Echo: {message}")

Console Simulation

Enter 'quit' to exit: status
Echo: status
Enter 'quit' to exit: lockout
Security alert: terminal locked.

Immediate Loop Termination with break

The break statement directs Python to immediately exit the while loop or for loop without running any remaining code in the loop.

It bypasses the conditional test and ends the loop instantly.

prompt = " Please enter the name of a city you have visited:"
prompt += " (Enter 'quit' when you are finished.) "
while True:
    city = input(prompt)
    if city == 'quit':
        break
    else:
        print(f"I'd love to go to {city.title()}!")

Console Simulation

Please enter the name of a city you have visited:
(Enter 'quit' when you are finished.) tokyo
I'd love to go to Tokyo!
Please enter the name of a city you have visited:
(Enter 'quit' when you are finished.) quit

Skipping Iterations with continue

The continue statement tells Python to stop executing the current iteration and return to the beginning of the loop to re-evaluate the condition.

Useful for skipping invalid inputs, malformed records, or comments in configuration files without terminating the entire loop.

current_number = 0
while current_number < 10:
    current_number += 1
    if current_number % 2 == 0:
        continue
    print(current_number)
1
3
5
7
9

Flow diagram

[ Check number % 2 == 0 ]

(True) → [ continue ] → (Jumps directly to while current_number < 10)

(False) → [ print(current_number) ]

Detecting and Preventing Infinite Loops

Every while loop must have a reachable path to make its conditional test False or execute a break statement.

If the variable controlling the loop is never updated, the loop runs endlessly until memory or CPU exhaustion occurs.

Code with bug (DO NOT RUN)

x = 1
while x <= 5:
    print(x)
    # Bug: x += 1 was omitted! x stays 1 forever.

Defensive Strategies

  1. Ensure loop variables are updated on EVERY execution branch.
  1. In production systems, include a maximum iteration cap or timeout:
max_retries = 5
while attempts < max_retries:
    ...

Terminal command to abort an infinite loop: Ctrl + C (sends SIGINT signal).

Comparative Analysis: for Loop vs while Loop

Moving Items Between Lists: The Work Queue Pattern

Modifying a list with for loops while iterating over it causes Python to lose track of index positions.

Use a while loop with pop() to remove items from an unverified list and append() them to a confirmed list until the work queue is empty.


unconfirmed_users = ['alice', 'brian', 'candace']
confirmed_users = []
while unconfirmed_users:
    current_user = unconfirmed_users.pop()
    print(f"Verifying user: {current_user.title()}")
    confirmed_users.append(current_user)
print(" The following users have been confirmed:")
for confirmed_user in confirmed_users:
    print(confirmed_user.title())
Verifying user: Candace
Verifying user: Brian
Verifying user: Alice
The following users have been confirmed:
Candace
Brian
Alice

Removing All Instances of a Value with while

The remove() method removes only the FIRST occurrence of a value.

To purge every occurrence of a specific value (e.g. blacklisted IP, spam flag), combine while and in with remove().

pets = ['dog', 'cat', 'dog', 'goldfish', 'cat', 'rabbit', 'cat']
print(f"Original: {pets}")
while 'cat' in pets:
    pets.remove('cat')
print(f"Filtered: {pets}")
Original: ['dog', 'cat', 'dog', 'goldfish', 'cat', 'rabbit', 'cat']
Filtered: ['dog', 'dog', 'goldfish', 'rabbit']

Security Use-case

Cleansing raw packet traces to strip out internal broadcast addresses before exporting external telemetry.

Filling a Dictionary Interactively

Combining input() and while loops allows interactive population of key-value dictionaries.

Prompt for a key, prompt for a value, assign responses[key] = value, and prompt whether to continue.

responses = {}
polling_active = True
while polling_active:
    name = input(" What is your name? ")
    response = input("Which mountain would you like to climb someday? ")
    responses[name] = response
    repeat = input("Would you like to let another person respond? (yes/ no) ")
    if repeat == 'no':
        polling_active = False
print(" --- Poll Results ---")
for name, response in responses.items():
    print(f"{name} would like to climb {response}.")

Console Simulation

What is your name? Alice
Which mountain would you like to climb someday? Denali
Would you like to let another person respond? (yes/ no) no
--- Poll Results ---
Alice would like to climb Denali.

Defensive Programming: Validating and Sanitizing Input

Never trust user input: users may provide malformed strings, malicious payloads, or leading/trailing whitespace.

Use string sanitization methods: .strip(), .lower(), .replace().

raw_port = input("Enter port number: ").strip()
if not raw_port.isdigit():
    print("Error: Port must contain only numeric digits.")
else:
    port = int(raw_port)
    if 1 <= port <= 65535:
        print(f"Valid port configured: {port}")
    else:
        print("Error: Port out of valid range (1 - 65535).")

Key Safeguards

  1. strip(): removes accidental whitespace or newline characters.
  1. isdigit(): guards int() against ValueError crashes.
  1. Range verification: confirms protocol boundaries.

Vulnerability Deep Dive: CWE-400 Uncontrolled Resource Consumption

Common Weakness Enumeration CWE-400: Resource Exhaustion.

When a while loop condition relies on external network data or user input without an upper bound, attackers can trigger infinite loops or extreme CPU consumption (Denial of Service).

Code pattern (Vulnerable)

# while packet_received: process(packet)
# If flood attack, thread hangs indefinitely

Mitigation Pattern (Safe)

import time
MAX_ATTEMPTS = 100
TIMEOUT_SECONDS = 5.0
start_time = time.time()
attempts = 0
while attempts < MAX_ATTEMPTS:
    if time.time() - start_time > TIMEOUT_SECONDS:
        print("Safety timeout reached. Aborting loop.")
        break
    attempts += 1

Security Standard: MITRE CWE-400: cwe.mitre.org/data/definitions/400.html · OWASP Denial of Service Cheat Sheet: cheatsheetseries.owasp.org

Modern Technology Link: Network Daemons & Event Loops

In production operating systems and cloud services, network servers run inside continuous while True event loops: Web servers (Nginx, Gunicorn, Uvicorn) listen on sockets indefinitely; Python asyncio event loop processes concurrent I/O tasks.

Architecture Diagram

Code snippet

# Minimal server listener skeleton:
# while True:
#     client_sock, addr = server_sock.accept()
#     handle_client(client_sock)

Security Application: Simulating Brute-Force & Lockout Logic

Demonstrating how dictionaries and while loops interact in authentication subsystems: Tracking login attempts per IP/username, locking out after threshold K consecutive failures.

user_db = {'admin': 'SecretPass123!'}
failed_attempts = 0
MAX_FAILS = 3
while failed_attempts < MAX_FAILS:
    pwd = input("Enter password: ")
    if pwd == user_db['admin']:
        print("Authentication successful! Welcome.")
        failed_attempts = 0
        break
    else:
        failed_attempts += 1
        remaining = MAX_FAILS - failed_attempts
        print(f"Invalid password. Attempts remaining: {remaining}")
else:
    print("ALERT: Account locked due to excessive failed attempts.")

Industry Reference

NIST SP 800-63B (Digital Identity Guidelines: Authentication and Lifecycle Management)

Integrated Case Study: Network Service Inventory

Architecture: Combining nested dictionaries, user input, input validation, and while loop queue processing.

inventory = {}
while True:
    service_name = input("Enter service name (or 'quit' to finalize): ").strip().lower()
    if service_name == 'quit':
        break
    port_str = input(f"Enter port for {service_name}: ").strip()
    if not port_str.isdigit():
        print("Port must be numeric. Skipping entry.")
        continue
    port = int(port_str)
    protocol = input("Enter protocol (TCP/UDP): ").strip().upper()
    inventory[service_name] = {'port': port, 'protocol': protocol}
print(" --- Verified Service Inventory ---")
for svc, data in sorted(inventory.items()):
    print(f"Service: {svc.upper():<10} | Port: {data['port']:<5} | Protocol: {data['protocol']}")

Output Demonstration

--- Verified Service Inventory ---
Service: HTTPS | Port: 443 | Protocol: TCP
Service: SSH | Port: 22 | Protocol: TCP

Session 3 Summary: Key Takeaways

Chapter 5 — Dictionaries

  • Key-Value Associative Mappings: curly braces {}, O(1) average lookup time.
  • CRUD Operations: access with dict[k] or safe dict.get(k, default), assign dict[k] = v, del dict[k].
  • Iteration: dict.items() for pairs, dict.keys() for keys, dict.values() for values, set() for deduplication.
  • Hierarchical Nesting: lists of dicts, lists in dicts, dicts in dicts (JSON / REST API foundation).

Chapter 6 — User Input & While Loops

  • Input Capture: input() always returns str; convert with int() or float(); test divisibility with %.
  • Iterative Control: while condition runs indefinitely until False; use sentinel values or active flags.
  • Loop Controls: break terminates instantly; continue skips to next evaluation; guard against infinite loops.
  • Queue Processing: while lst: lst.pop() safely modifies collections during execution.

Official References & Standards Index

Course: SEC1302 · Python for Information Security · Primary Textbook: Eric Matthes, Python Crash Course, 2nd ed.