SEC1302 · Python for Information Security
>>> ports = [22, 80, 443]
>>> if 22 in ports:
... print("SSH exposed")
SSH exposedExercises · Chapter summaries
Mapped to CLO1 — apply Python to solve basic programming problems (C3-P2).
bicycles = ['trek', 'cannondale', 'redline', 'specialized']
print(bicycles)['trek', 'cannondale', 'redline', 'specialized']bicycles = ['trek', 'cannondale', 'redline', 'specialized']
print(bicycles[0])
print(bicycles[0].title())
message = f"My first bicycle was a {bicycles[0].title()}."
print(message)trek
Trek
My first bicycle was a Trek.positive: 0 | negative: -4
positive: 1 | negative: -3
positive: 2 | negative: -2
positive: 3 | negative: -1
bicycles = ['trek', 'cannondale', 'redline', 'specialized']
print(bicycles[1])
print(bicycles[3])
print(bicycles[-1])cannondale
specialized
specializedmotorcycles = ['honda', 'yamaha', 'suzuki']
print(motorcycles)
motorcycles[0] = 'ducati'
print(motorcycles)['honda', 'yamaha', 'suzuki']
['ducati', 'yamaha', 'suzuki']Assigning to list[index] replaces the item at that position; other items are unchanged.
Strings are immutable (Chapter 2), so "honda"[0] = "H" raises TypeError; lists are mutable.
motorcycles = []
motorcycles.append('honda')
motorcycles.append('yamaha')
motorcycles.append('suzuki')
print(motorcycles)['honda', 'yamaha', 'suzuki']motorcycles = ['honda', 'yamaha', 'suzuki']
motorcycles.insert(0, 'ducati')
print(motorcycles)['ducati', 'honda', 'yamaha', 'suzuki']motorcycles = ['honda', 'yamaha', 'suzuki']
del motorcycles[1]
print(motorcycles)['honda', 'suzuki']motorcycles = ['honda', 'yamaha', 'suzuki']
popped_motorcycle = motorcycles.pop()
print(motorcycles)
print(popped_motorcycle)['honda', 'yamaha']
suzukimotorcycles = ['honda', 'yamaha', 'suzuki']
first_owned = motorcycles.pop(0)
print(f"The first motorcycle I owned was a {first_owned.title()}.")The first motorcycle I owned was a Honda.Visual: "stack" diagram for pop() — the top of the stack is the end of the list.
motorcycles = ['honda', 'yamaha', 'suzuki', 'ducati']
too_expensive = 'ducati'
motorcycles.remove(too_expensive)
print(motorcycles)
print(f"\nA {too_expensive.title()} is too expensive for me.")['honda', 'yamaha', 'suzuki']
A Ducati is too expensive for me.Rule of thumb (coursebook): use del when the item is no longer needed; use pop() when the item is still needed.
cars = ['bmw', 'audi', 'toyota', 'subaru']
cars.sort()
print(cars)
cars.sort(reverse=True)
print(cars)['audi', 'bmw', 'subaru', 'toyota']
['toyota', 'subaru', 'bmw', 'audi']cars = cars.sort() sets cars to None).cars = ['bmw', 'audi', 'toyota', 'subaru']
print("Here is the original list:")
print(cars)
print("\nHere is the sorted list:")
print(sorted(cars))
print("\nHere is the original list again:")
print(cars)Here is the original list:
['bmw', 'audi', 'toyota', 'subaru']
Here is the sorted list:
['audi', 'bmw', 'subaru', 'toyota']
Here is the original list again:
['bmw', 'audi', 'toyota', 'subaru']cars = ['bmw', 'Audi', 'toyota', 'Subaru']
print(sorted(cars))
print(sorted(cars, key=str.lower))['Audi', 'Subaru', 'bmw', 'toyota']
['Audi', 'bmw', 'Subaru', 'toyota']Strings compare by Unicode code point, so 'S' (83) comes before 'b' (98). The key function converts each item before comparison without changing the stored values.
import ipaddress
ips = ['10.0.0.2', '10.0.0.10', '9.1.1.1']
print(sorted(ips))
print(sorted(ips, key=ipaddress.ip_address))['10.0.0.10', '10.0.0.2', '9.1.1.1']
['9.1.1.1', '10.0.0.2', '10.0.0.10']Key message: text sorting puts "10.0.0.10" before "10.0.0.2"; analysts should sort IPs as addresses.
cars = ['bmw', 'audi', 'toyota', 'subaru']
cars.reverse()
print(cars)
print(len(cars))['subaru', 'toyota', 'audi', 'bmw']
4motorcycles = ['honda', 'yamaha', 'suzuki']
print(motorcycles[3])Traceback (most recent call last):
File "motorcycles.py", line 2, in <module>
print(motorcycles[3])
IndexError: list index out of rangeA list of 3 items has indexes 0, 1, 2; index 3 asks for a fourth item.
motorcycles = [] then motorcycles[-1] → IndexError: list index out of range[].pop() → IndexError: pop from empty listSource: docs.python.org — IndexError
magicians = ['alice', 'david', 'carolina']
for magician in magicians:
print(magician)alice
david
carolinaThe for statement iterates over the items of any sequence in order; no index variable is needed.
The loop variable name is chosen by the programmer; singular/plural pairs make code readable:
for cat in cats:
for dog in dogs:
for item in list_of_items:
for port in open_ports:The loop runs once per item, whether the list has 3 items or 1,000,000.
// C++
for (int i = 0; i < n; i++) { cout << arr[i]; }
# Python
for item in items:
print(item)When the index is also needed, use enumerate():
for i, magician in enumerate(magicians):
print(i, magician)0 alice
1 david
2 carolinaSource: docs.python.org — enumerate
magicians = ['alice', 'david', 'carolina']
for magician in magicians:
print(f"{magician.title()}, that was a great trick!")
print(f"I can't wait to see your next trick, {magician.title()}.\n")
print("Thank you, everyone. That was a great magic show!")Alice, that was a great trick!
I can't wait to see your next trick, Alice.
David, that was a great trick!
I can't wait to see your next trick, David.
Carolina, that was a great trick!
I can't wait to see your next trick, Carolina.
Thank you, everyone. That was a great magic show!Indented lines run once per item; the unindented final line runs once after the loop.
A scanner reports each host inside the loop, then prints one summary line after the loop.
for value in range(1, 5):
print(value)1
2
3
4Source: docs.python.org — ranges
numbers = list(range(1, 6))
print(numbers)
even_numbers = list(range(2, 11, 2))
print(even_numbers)
squares = []
for value in range(1, 11):
squares.append(value ** 2)
print(squares)[1, 2, 3, 4, 5]
[2, 4, 6, 8, 10]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]well_known_ports = range(0, 1024)
print(len(well_known_ports), well_known_ports[0], well_known_ports[-1])1024 0 1023Sources: docs.python.org — range function
RFC 6335 (port number ranges: System Ports 0–1023)
digits = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
print(min(digits))
print(max(digits))
print(sum(digits))0
9
45failed_logins = [3, 0, 1, 42, 2]
print(max(failed_logins), sum(failed_logins) / len(failed_logins))42 9.6The peak (42) stands out against the mean (9.6) — the basis of simple threshold alerts.
Optional: the statistics module provides mean(), median(), stdev().
squares = [value ** 2 for value in range(1, 11)]
print(squares)[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]Anatomy: [ expression for variable in iterable ] → [ value**2 | for value in range(1, 11) ]
Comparison: 4-line loop with append() (previous slide) vs 1-line comprehension — same result.
ports = [21, 22, 80, 443, 3389]
risky = [p for p in ports if p in (21, 23, 3389)]
print(risky)[21, 3389]Guideline: use a comprehension when it stays readable on one line; otherwise use a normal loop.
players = ['charles', 'martina', 'michael', 'florence', 'eli']
print(players[0:3])
print(players[1:4])
print(players[:4])
print(players[2:])
print(players[-3:])
print(players[::2])['charles', 'martina', 'michael']
['martina', 'michael', 'florence']
['charles', 'martina', 'michael', 'florence']
['michael', 'florence', 'eli']
['michael', 'florence', 'eli']
['charles', 'michael', 'eli']Index ruler: start (included) and stop (excluded).
players = ['charles', 'martina', 'michael', 'florence', 'eli']
print("Here are the first three players on my team:")
for player in players[:3]:
print(player.title())Here are the first three players on my team:
Charles
Martina
MichaelShow the top 5 offending IP addresses after sorting by number of alerts:
for ip in sorted_ips[:5]:
...Note: "last N lines of a log" is lines[-N:], similar to the Unix tail command.
my_foods = ['pizza', 'falafel', 'carrot cake']
friend_foods = my_foods[:]
my_foods.append('cannoli')
friend_foods.append('ice cream')
print(my_foods)
print(friend_foods)['pizza', 'falafel', 'carrot cake', 'cannoli']
['pizza', 'falafel', 'carrot cake', 'ice cream']my_foods = ['pizza', 'falafel', 'carrot cake']
friend_foods = my_foods
my_foods.append('cannoli')
friend_foods.append('ice cream')
print(my_foods)['pizza', 'falafel', 'carrot cake', 'cannoli', 'ice cream']Memory diagram: two names → one list object (alias) vs two names → two list objects (copy). Link back to Chapter 2 "variables are labels".
import copy
rules = [['22', 'deny'], ['80', 'allow']]
shallow = rules[:]
shallow[0][1] = 'allow'
print(rules)[['22', 'allow'], ['80', 'allow']]A slice copies only the outer list; nested lists are shared. copy.deepcopy(rules) copies them too — important when testing changes to a firewall rule set without altering the original.
dimensions = (200, 50)
print(dimensions[0])
print(dimensions[1])
dimensions[0] = 250200
50
Traceback (most recent call last):
File "dimensions.py", line 4, in <module>
dimensions[0] = 250
TypeError: 'tuple' object does not support item assignmentmy_t = (3,)
print(type(my_t), type((3)))<class 'tuple'> <class 'int'>dimensions = (200, 50)
print("Original dimensions:")
for dimension in dimensions:
print(dimension)
dimensions = (400, 100)
print("\nModified dimensions:")
for dimension in dimensions:
print(dimension)Original dimensions:
200
50
Modified dimensions:
400
100Items of a tuple cannot be changed, but the variable can be bound to a new tuple. Python raises no error because the name is reassigned; the old tuple is not modified.
server_address = ("127.0.0.1", 8080)
host, port = server_address
print(host, port)127.0.0.1 8080cars = ['audi', 'bmw', 'subaru', 'toyota']
for car in cars:
if car == 'bmw':
print(car.upper())
else:
print(car.title())Audi
BMW
Subaru
ToyotaInside the loop, each car is tested; 'bmw' is an acronym and is printed in uppercase, all others in title case.
Source: docs.python.org — if statements
>>> car = 'bmw'
>>> car == 'bmw'
True
>>> car = 'audi'
>>> car == 'bmw'
Falserequested_topping = 'mushrooms'
if requested_topping != 'anchovies':
print("Hold the anchovies!")Hold the anchovies!Note: every conditional test evaluates to True or False (type bool).
Source: docs.python.org — comparisons
>>> car = 'Audi'
>>> car == 'audi'
False
>>> car.lower() == 'audi'
True
>>> car
'Audi'lower() returns a new string for the comparison; the stored value keeps its original case.
blocked_users = ['admin', 'root']
username = ' Admin '
print(username in blocked_users)
print(username.strip().lower() in blocked_users)False
True>>> age = 19
>>> age < 21
True
>>> age <= 21
True
>>> age > 21
False
>>> age >= 21
Falseanswer = 17
if answer != 42:
print("That is not the correct answer. Please try again!")That is not the correct answer. Please try again!18 <= 21 < 65 → True (same as 18 <= 21 and 21 < 65).0.1 + 0.2 == 0.3 → False; use math.isclose() (link to Chapter 2).>>> age_0 = 22
>>> age_1 = 18
>>> age_0 >= 21 and age_1 >= 21
False
>>> age_1 = 22
>>> age_0 >= 21 and age_1 >= 21
True
>>> age_0 = 22
>>> age_1 = 18
>>> age_0 >= 21 or age_1 >= 21
True
>>> age_0 = 18
>>> age_0 >= 21 or age_1 >= 21
False(age_0 >= 21) and (age_1 >= 21).if users and users[0] == 'admin':>>> requested_toppings = ['mushrooms', 'onions', 'pineapple']
>>> 'mushrooms' in requested_toppings
True
>>> 'pepperoni' in requested_toppings
Falsebanned_users = ['andrew', 'carolina', 'david']
user = 'marie'
if user not in banned_users:
print(f"{user.title()}, you can post a response if you wish.")Marie, you can post a response if you wish.Performance note: x in list scans items one by one (O(n)); sets (Chapter 6) give fast lookups for large lists.
game_active = True
can_edit = False
print(bool([]), bool([0]), bool(''), bool('0'))False True False TrueFalse, None, 0, 0.0, '' (empty string), [] (empty list), () (empty tuple), {} (empty dict), set(), range(0)
Everything else counts as True, including '0' and [0].
if not seq: / if seq: rather than if len(seq) == 0:.age = 19
if age >= 18:
print("You are old enough to vote!")
print("Have you registered to vote yet?")You are old enough to vote!
Have you registered to vote yet?age = 17
if age >= 18:
print("You are old enough to vote!")
else:
print("Sorry, you are too young to vote.")
print("Please register to vote as soon as you turn 18!")Sorry, you are too young to vote.
Please register to vote as soon as you turn 18!age = 12
if age < 4:
print("Your admission cost is 0 USD.")
elif age < 18:
print("Your admission cost is 25 USD.")
else:
print("Your admission cost is 40 USD.")Your admission cost is 25 USD.age = 12
if age < 4:
price = 0
elif age < 18:
price = 25
else:
price = 40
print(f"Your admission cost is {price} USD.")Your admission cost is 25 USD.Key point: Python tests conditions top-down and runs ONLY the first block whose test is True.
age = 70
if age < 4:
price = 0
elif age < 18:
price = 25
elif age < 65:
price = 40
elif age >= 65:
price = 20
print(f"Your admission cost is {price} USD.")Your admission cost is 20 USD.elif age >= 65 makes the code reject unexpected cases: else catches EVERYTHING, including invalid or malicious input.Optional note: Python 3.10 adds the match statement (structural pattern matching) for multi-way branching on values and shapes.
requested_toppings = ['mushrooms', 'extra cheese']
if 'mushrooms' in requested_toppings:
print("Adding mushrooms.")
if 'pepperoni' in requested_toppings:
print("Adding pepperoni.")
if 'extra cheese' in requested_toppings:
print("Adding extra cheese.")
print("\nFinished making your pizza!")Adding mushrooms.
Adding extra cheese.
Finished making your pizza!Output would be:
Adding mushrooms.
Finished making your pizza!failed_logins = 42
if failed_logins >= 50:
severity = "critical"
elif failed_logins >= 20:
severity = "high"
elif failed_logins >= 5:
severity = "medium"
else:
severity = "low"
print(f"{failed_logins} failed logins -> severity: {severity}")42 failed logins -> severity: highrequested_toppings = ['mushrooms', 'green peppers', 'extra cheese']
for requested_topping in requested_toppings:
if requested_topping == 'green peppers':
print("Sorry, we are out of green peppers right now.")
else:
print(f"Adding {requested_topping}.")
print("\nFinished making your pizza!")Adding mushrooms.
Sorry, we are out of green peppers right now.
Adding extra cheese.
Finished making your pizza!requested_toppings = []
if requested_toppings:
for requested_topping in requested_toppings:
print(f"Adding {requested_topping}.")
print("\nFinished making your pizza!")
else:
print("Are you sure you want a plain pizza?")Are you sure you want a plain pizza?Note: an empty list evaluates to False in an if test (see the truthiness slide).
available_toppings = ['mushrooms', 'olives', 'green peppers',
'pepperoni', 'pineapple', 'extra cheese']
requested_toppings = ['mushrooms', 'french fries', 'extra cheese']
for requested_topping in requested_toppings:
if requested_topping in available_toppings:
print(f"Adding {requested_topping}.")
else:
print(f"Sorry, we don't have {requested_topping}.")
print("\nFinished making your pizza!")Adding mushrooms.
Sorry, we don't have french fries.
Adding extra cheese.
Finished making your pizza!allowed_ports = [80, 443]
requested_ports = [443, 23, 80]
for port in requested_ports:
if port in allowed_ports:
print(f"Port {port}: allow")
else:
print(f"Port {port}: deny")Port 443: allow
Port 23: deny
Port 80: allowKey message: available_toppings is an allow-list; the same pattern underlies firewall rules and input validation.
Next session — Chapter 5: Dictionaries
Eric Matthes, Python Crash Course, 2nd ed., No Starch Press, 2019 · Official docs: https://docs.python.org/3/
Lists & Conditional Control Flow