ICTPRG435 - Session 3: Tuples, Dictionaries, Loops and Operators
Overview: This session introduces Python tuples and dictionaries, loop structures (while and for), logical and membership operators, bitwise operations, number base conversions, and concludes with a practical encryption/decryption activity.
This session focuses on:
Tuples
A tuple is similar to a list but immutable (cannot be changed after creation). Tuples use parentheses () instead of square brackets.
Each item within the tuple is separated with a comma and is assigned a number known as its index (or position) in the sequence, the first index is 0. To access an item in the tuple, the index value of the item is required as demonstrated in the examples below
# A tuple containing integers
tup1 = (1, 0, 1) # Tuple of integers
tup2 = ("ant", "apple", "pear") # Tuple of strings
tup3 = (True, False, True, True) # Tuple of Boolean values
tup4 = ((1, 0, 5, -5), ("a", "apple", "xyz"), (True, False)) # Tuple of tuples
print(tup1) # print all items in the tuple -> (1, 0, 1)
print(tup1[0]) # print the first item in the tuple -> 1
print(tup2[1]) # print the second item in the tuple -> 'apple'
print(tup2[-1]) # print the last item in the tuple using negative indexing -> 'pear'
print(tup2[2][0]) # print the first character of third item in the tuple -> 'p'
print(tup4[1][1][:3]) # Print the first three characters of the second item in the tuple -> 'app'
Tuples are useful for fixed collections of items (e.g., coordinates, settings). Because they are immutable, they are hashable and can be used as dictionary keys.
Dictionaries
A dictionary is a Python data structure used to store a collection of key–value pairs enclosed in curly braces {}. Dictionaries like lists are mutable, but keys must be unique and immutable.
dict1 = {1: "ant", 2: "bug", 3: "fly"} # Creating a dictionary with integer keys
print(dict1) # print dictionary -> {1: "ant", 2: "bug", 3: "fly"}
dict1 = {1: "ant", 2: "bug", 3: "fly", 3: "bee"} # Duplicated keys override previous ones
print(dict1) # key 3 is overwritten -> {1: 'ant', 2: 'bug', 3: 'bee'}
print(dict1[3]) # dictionary uses key to access value -> 'bee'
dict1[4] = "Nit" # Add an item to the dictionary
print(dict1) # -> {1: 'ant', 2: 'bug', 3: 'bee', 4:'Nit'}
dict1[1] = "bot" # update value under key 1
print(dict1) # -> {1: 'bot', 2: 'bug', 3: 'bee', 4:'Nit'}
dict1.pop(1) # remove key 1 from the dictionary
print(dict1) # {2: 'bug', 3: 'bee', 4: 'Nit'}
dict2 = {"pet": "Dog", "name": "Flip", "age": 5} # create dictionary with string keys
print(dict2["name"]) # access value associated with the 'name' key -> 'Flip'
KeyError occurs if you try to access a key that doesn't exist. Use get() method to avoid it:
dict1 = {1: "ant", 2: "bug", 3: "fly", 4: "bee"}
print(dict1.get(5)) # -> None
print(dict1.get(5, "No Value Available")) # -> No Value Available
print(dict1.get(4, "No Value Available")) # -> 'bee'
Tip: Use .keys(), .values(), and .items() to loop through dictionaries (see below).
Loops
Python supports two main looping constructs: while and for.
While loops
while loops execute a block of code repeatedly as long as the condition remains True. The loop iteration stops when the condition evaluates to False.
counter = 0
while counter < 3:
print(counter)
counter = counter + 1
print("Out of the loop!") # Output: 0, 1, 2, Out of the loop!
In the example above, as long as the value associated with the counter variable remains less than 3, the condition will always evaluate to True, therefore the body of code will be executed.
Use break to exit early:
counter = 0
while True:
print(counter)
counter += 1
if counter == 5:
break
print("Out of the loop!")
Warning: If the loop condition never becomes False and no break is used, the program enters an infinite loop.
For loops
for loops iterate directly over items of a sequence (e.g., string, list, dictionary, range).
# Looping through a string
pet = "Cat"
for x in pet:
print(x) -> will print 'C' on the first iteration, then 'a' and 't'
# Looping through a list
pets = ["Cat", "Dog", "Rabbit"]
for x in pets:
print(x) -> will print 'Cat' on the first iteration, then 'Dog' and 'Rabbit'
for x in pets:
if x == "Dog":
break
print(x) -> will print only first item 'Cat'
for x in pets:
if x == "Dog":
continue
print(x) -> will skip 'Dog' and prints 'Cat' and 'Rabbit'
Note: The latter two examples are different, one uses a break statement, and the other a continue statement. Can you work out what is happening?
Looping through a dictionary
languages = {
"Australia": "English",
"Brazil": "Portuguese",
"Denmark": "Danish",
"Jordan": "Arabic"
}
# Iterating over dictionary keys
print("KEYS")
for key in languages:
print(key) -> "Australia", "Brazil", "Denmark", "Jordan"
# Iterating over dictionary values
print("VALUES")
for value in languages.values():
print(value) -> "English", "Portuguese", "Danish", "Arabic"
#Iterating over dictionary keys and values
print("KEYS - VALUES")
for key, value in languages.items():
print(f"{key}: {value}") -> "Australia - English", "Brazil - Portuguese", "Denmark - Danish", "Jordan - Arabic"
The range() function
range() generates a sequence of numbers, often used in for loops.
Syntax: range(start,stop, step)
start: Start position (optional, default value = 0, included in the range)stop: End position (required, not included in the range)step: Incrimination (optional, default value = 1)
Examples
# range(stop)
for num in range(2):
print(num) -> will output 0 at the first iteration and then 1
# range(start, stop)
for num in range(2, 6):
print(num) -> 2, 3, 4, 5
# range(start, stop, step)
for num in range(2, 8, 2):
print(num) -> 2, 4, 6
# Negative step
for num in range(3, 0, -1):
print(num) -> 3, 2, 1
Logical Operators
Used to perform logical operations; return True or False.
| Operator | Description | Example | Result |
|---|---|---|---|
and |
True if both conditions are true. | a==3 and b==5 |
True |
or |
True if at least one condition is true. | a==3 or b==5 |
True |
not |
Negates the condition. | not (a==3 and b==5) |
False |
Membership Operators
Used to test if a value exists in a sequence (like strings, lists, or tuples).
| Operator | Description | Example | Result |
|---|---|---|---|
in |
True if the value exists in the sequence. | "e" in "Hello" |
True |
not in |
True if the value does not exist in the sequence. | "E" not in "Hello" |
True |
Example:
word = "PROGRAMMING"
while True:
char = input("Enter a character: ")
if len(char) == 1:
break
else:
print("Only one character, please!")
if char in word:
print("Found")
else:
print("Not Found")
Can you predict the output of the above program, if enter 'p' letter?
Bitwise Operators
Operate at the binary level - comparing bits of integers.
Bitwise operators can be used to implement algorithms such as compression, encryption, and error detection.
| Operator | Description | Example | Bitwise Level | Result | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
& |
Bitwise AND (1 if both bits are 1) | 156 & 52 |
|
20 | ||||||||||||||||||||||||||||||||||||
| |
Bitwise OR (1 if either bit is 1) | 156 | 52 |
|
188 | ||||||||||||||||||||||||||||||||||||
^ |
Bitwise XOR (1 if bits differ) | 156 ^ 52 |
|
168 | ||||||||||||||||||||||||||||||||||||
~ |
Bitwise NOT (inverts bits - returns -(n+1))Python uses two complement system to store negative numbers |
~10 |
|
-11 | ||||||||||||||||||||||||||||||||||||
<< |
Left shift (append zeros to the right) | 53 << 1 |
|
106 | ||||||||||||||||||||||||||||||||||||
>> |
Right shift (remove right bits) | 53 >> 1 |
|
26 | ||||||||||||||||||||||||||||||||||||
Note: Bitwise operations are useful for low-level programming tasks such as encryption, compression, and flags management.
For more information on two’s complement please visit: Two's complement and negative numbers for integers
Number Conversion Functions
Python includes several built-ins for converting between number bases.
| Function | Description | Example | Result |
|---|---|---|---|
hex() |
Convert decimal to hexadecimal string. | hex(255) |
'0xff' |
bin() |
Convert decimal to binary string. | bin(79) |
'0b1001111' |
int(x, base) |
Convert from given base to decimal. | int('a2', 16)int('1001111', 2) |
162 79 |
Notes:
0xprefix indicates hexadecimal,0bindicates binary.- These functions return
strvalues forbin()andhex(), andintforint().
Student Activity - Encryptor
Objective: You are required to develop a program which encrypts, and decrypts a given password.
Note: The incomplete .py file (encryptor.py) required for the activity is presented below and is located under the Session 3 Files heading on the resources page
def encrypt():
?
return encrypted_list
def decrypt():
?
return pwd
if __name__ == "__main__":
pwd = encrypt("Hello$2#")
print("Encrypt:", pwd) # Encrypt: [-73, -102, -109, -109, -112, -37, -51, -36]
print("Decrypt:", decrypt(pwd)) # Decrypt: Hello$2#
Requirements
- encrypt(): Accepts a string; converts each character to its decimal (ASCII) value, finds its two's complement, stores results in a list, and returns that list.
- decrypt(): Accepts a list of two's complement values and reverses the process, reconstructing the original string.
- Do not modify the
if __name__ == "__main__"block.
Hint: Use ord() and chr() for conversions, and remember that bitwise NOT (~) gives -(x + 1). To reverse it, use ~n again.
Extension ideas
- Add input validation and allow the user to enter a password interactively.
- Experiment with adding a shift cipher before applying two's complement.
- Explore using
bytes()andbytearray()for more robust encryption handling.