Strings and String Methods
Strings are one of the most important and commonly used data structures in Python. A string is a sequence of characters, such as letters, numbers, or symbols, enclosed in single ('), double (") or triple quotes (''' / """). Strings are widely used for text processing, user input, file handling, and much more.
Creating Strings
Strings can be defined in multiple ways:
str1 = 'Hello'
str2 = "World"
str3 = """This is
a multi-line string"""
- Single or double quotes work the same.
- Triple quotes allow multi-line text.
Basic String Operations
Python strings support many useful operations.
- Concatenation (joining):
greeting = "Hello" + " " + "Python"
print(greeting) # Output: Hello Python
- Repetition:
laugh = "ha" * 3
print(laugh) # Output: hahaha
- Indexing:
word = "Python"
print(word[0]) # Output: P
print(word[-1]) # Output: n
- Slicing:
print(word[0:3]) # Output: Pyt
print(word[2:]) # Output: thon
Common String Methods
Python provides many built-in methods to work with strings.
- Changing case:
text = "python"
print(text.upper()) # Output: PYTHON
print(text.capitalize()) # Output: Python
- Searching:
sentence = "I love Python"
print(sentence.find("love")) # Output: 2
print("Python" in sentence) # Output: True
- Replacing:
print(sentence.replace("Python", "coding"))
# Output: I love coding
- Splitting and joining:
words = sentence.split()
print(words) # ['I', 'love', 'Python']
joined = "-".join(words)
print(joined) # I-love-Python
- Stripping whitespace:
name = " Amr "
print(name.strip()) # Output: Amr
String Formatting
Python provides powerful ways to insert variables into strings.
- f-strings (modern way):
name = "Amr"
age = 30
print(f"My name is {name} and I am {age} years old.")
- format method:
print("My name is {} and I am {} years old.".format(name, age))
These make output dynamic and user-friendly.
Lists and List Operations
A list in Python is an ordered collection that can store multiple items in a single variable. Unlike strings, lists are mutable, meaning you can change, add, or remove elements after creating them. Lists are one of the most flexible and widely used data structures in Python.
Creating Lists
Lists are defined using square brackets [].
numbers = [1, 2, 3, 4, 5]
fruits = ["apple", "banana", "cherry"]
mixed = [1, "hello", 3.14, True]
empty = []
- A list can contain elements of different data types.
- Lists can also be nested, meaning one list inside another.
Accessing List Elements
Lists support indexing and slicing, similar to strings.
fruits = ["apple", "banana", "cherry"]
print(fruits[0]) # Output: apple
print(fruits[-1]) # Output: cherry
print(fruits[0:2]) # Output: ['apple', 'banana']
- Indexing starts at 0.
- Negative indices count from the end.
Modifying Lists
Since lists are mutable, you can change elements directly.
fruits[1] = "blueberry"
print(fruits) # ['apple', 'blueberry', 'cherry']
- You can also add or remove elements dynamically.
Adding Elements
Python provides multiple ways to add items to a list.
fruits.append("orange") # Add to the end
fruits.insert(1, "mango") # Insert at position 1
fruits.extend(["kiwi", "melon"]) # Add multiple items
print(fruits)
Removing Elements
Lists allow flexible removal of items.
fruits.remove("apple") # Removes first occurrence
popped = fruits.pop() # Removes last element
del fruits[0] # Deletes element at index 0
print(fruits)
pop()can also remove by index:fruits.pop(1).
Iterating Over Lists
You can loop through list elements easily.
for fruit in fruits:
print(fruit)
- Useful for processing items in bulk.
Useful List Methods
Python lists come with many built-in methods.
numbers = [5, 2, 9, 1]
print(len(numbers)) # Length → 4
print(max(numbers)) # Maximum → 9
print(min(numbers)) # Minimum → 1
numbers.sort()
print(numbers) # Sorted → [1, 2, 5, 9]
numbers.reverse()
print(numbers) # Reversed → [9, 5, 2, 1]
Tuples and Immutability
A tuple in Python is an ordered collection of elements, similar to a list. However, unlike lists, tuples are immutable, meaning once created, their elements cannot be changed, added, or removed. This immutability makes tuples useful for storing fixed collections of data that should remain constant throughout the program.
Creating Tuples
Tuples are created using parentheses ().
numbers = (1, 2, 3)
fruits = ("apple", "banana", "cherry")
mixed = (1, "hello", 3.14, True)
single = (5,) # Note the comma for a single-element tuple
empty = ()
- Without the comma,
(5)would be treated as an integer, not a tuple.
Accessing Tuple Elements
Tuples support indexing and slicing, just like lists.
fruits = ("apple", "banana", "cherry")
print(fruits[0]) # Output: apple
print(fruits[-1]) # Output: cherry
print(fruits[0:2]) # Output: ('apple', 'banana')
- Elements can be accessed but not modified.
Immutability of Tuples
Tuples cannot be changed after creation.
fruits = ("apple", "banana", "cherry")
# fruits[1] = "mango" # This will raise a TypeError
- This immutability makes tuples safe and reliable for storing data that should remain constant.
- However, if a tuple contains a mutable object (like a list), that object can still be modified.
nested = (1, [2, 3], 4)
nested[1].append(5)
print(nested) # Output: (1, [2, 3, 5], 4)
Tuple Operations
Although immutable, tuples still support useful operations.
colors = ("red", "green", "blue")
print(len(colors)) # Length → 3
print("green" in colors) # Membership → True
print(colors + ("yellow",)) # Concatenation → ('red', 'green', 'blue', 'yellow')
print(colors * 2) # Repetition → ('red', 'green', 'blue', 'red', 'green', 'blue')
Tuple Unpacking
Tuples can be unpacked directly into variables, making assignments concise.
person = ("Amr", 30, "Engineer")
name, age, job = person
print(name) # Amr
print(age) # 30
print(job) # Engineer
- This feature is often used in returning multiple values from functions.
Sets and Set Operations
A set in Python is an unordered collection of unique elements. Unlike lists and tuples, sets do not allow duplicates, and the order of elements is not preserved. Sets are very useful for mathematical operations like unions and intersections, as well as tasks such as removing duplicates from data.
Creating Sets
Sets are created using curly braces {} or the set() function.
numbers = {1, 2, 3, 4}
fruits = {"apple", "banana", "cherry"}
empty = set() # Correct way to create an empty set
- Writing
{}creates an empty dictionary, not a set. - Duplicate values are automatically removed:
nums = {1, 2, 2, 3}
print(nums) # Output: {1, 2, 3}
Accessing Elements in Sets
Since sets are unordered, elements cannot be accessed by index.
- You can loop through a set:
for fruit in fruits:
print(fruit)
- Membership testing is very fast:
print("apple" in fruits) # True
print("mango" not in fruits) # True
Adding and Removing Elements
Sets are mutable, so you can add or remove items.
fruits.add("orange") # Add a single element
fruits.update(["kiwi", "melon"]) # Add multiple elements
fruits.remove("banana") # Removes "banana" (raises error if not found)
fruits.discard("pear") # Safe remove (no error if not found)
print(fruits)
pop()removes and returns a random element (since sets are unordered).
Set Operations
Sets support powerful mathematical-style operations.
A = {1, 2, 3, 4}
B = {3, 4, 5, 6}
print(A | B) # Union → {1, 2, 3, 4, 5, 6}
print(A & B) # Intersection → {3, 4}
print(A - B) # Difference → {1, 2}
print(A ^ B) # Symmetric difference → {1, 2, 5, 6}
- Union (
|) combines all elements. - Intersection (
&) finds common elements. - Difference (
-) finds items in one set but not the other. - Symmetric difference (
^) finds items in either set but not both.
Useful Set Methods
Sets include additional helpful methods.
nums = {1, 2, 3}
nums.clear() # Removes all elements
print(len(nums)) # Length of the set
- These methods make sets excellent for managing collections of unique values.
Dictionaries (key–value pairs)
Dictionaries are one of the most important and flexible data structures in Python. They allow you to store and organize data as key–value pairs, where each key acts like a label that maps to a value. Unlike lists, which are ordered by index, dictionaries are optimized for fast lookups based on keys.
What are Dictionaries?
- A dictionary is an unordered, mutable collection of items stored as key–value pairs.
- Keys: must be unique and immutable (e.g., strings, numbers, tuples).
- Values: can be of any type (string, number, list, dict, etc.), and may be repeated.
- Since Python 3.7, dictionaries maintain the insertion order of keys (in practice, they are ordered).
student = {
"id": 101,
"name": "Amr",
"age": 22,
"courses": ["Math", "Physics"],
"is_active": True
}
Creating Dictionaries
Dictionaries can be created in several ways.
- **Using curly braces `{}
person = {"name": "Sara", "age": 25}
- Using the
dict()constructor
employee = dict(name="Ali", position="Engineer")
- From a list of tuples
pairs = [("x", 10), ("y", 20)]
coordinates = dict(pairs) # {"x": 10, "y": 20}
- Empty dictionary
empty = {}
Accessing and Updating Values
You retrieve or modify values using their keys.
- Accessing values
student = {"name": "Amr", "age": 22}
print(student["name"]) # Output: Amr
- **Safe access with `.get()
print(student.get("grade", "Not Assigned")) # Output: Not Assigned
- Updating values
student["age"] = 23
- Adding new key–value pairs
student["grade"] = "A"
Dictionary Methods
Dictionaries come with many useful methods:
.keys()→ returns all keys.values()→ returns all values.items()→ returns key–value pairs.update({...})→ merges another dictionary.pop(key)→ removes a key and returns its value.popitem()→ removes the last inserted pair.clear()→ removes everything
info = {"a": 1, "b": 2}
print(info.keys()) # dict_keys(['a', 'b'])
print(info.values()) # dict_values([1, 2])
print(info.items()) # dict_items([('a', 1), ('b', 2)])
Iterating over Dictionaries
You can loop through keys, values, or both.
user = {"id": 1, "name": "Sara", "role": "Admin"}
for key in user: # keys
print(key)
for value in user.values(): # values
print(value)
for key, value in user.items(): # pairs
print(key, ":", value)
Nested Dictionaries
Dictionaries can contain other dictionaries, allowing complex data structures.
company = {
"IT": {"manager": "Amr", "employees": 25},
"HR": {"manager": "Sara", "employees": 10}
}
print(company["IT"]["manager"]) # Output: Amr
Dictionary Comprehensions
You can build dictionaries in one line using comprehensions.
squares = {x: x**2 for x in range(5)}
print(squares) # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
Example with conditions:
prices = {"apple": 2, "banana": 1, "pear": 3}
discounted = {item: price*0.9 for item, price in prices.items() if price > 1}
print(discounted) # {'apple': 1.8, 'pear': 2.7}
Common Pitfalls
- Unhashable keys: Lists and dicts cannot be used as keys. Tuples are fine if they only contain hashable types.
- Duplicate keys: Later assignments overwrite earlier ones.
d = {"a": 1, "a": 2}
print(d) # {"a": 2}
- Shared mutable values: Avoid reusing the same list for multiple keys.
Real-world Uses
- JSON-like data: APIs and configs often return data as dicts.
- Counting frequencies:
text = "banana"
count = {}
for ch in text:
count[ch] = count.get(ch, 0) + 1
print(count) # {'b':1, 'a':3, 'n':2}
- Fast lookup tables:
countries = {"NL": "Netherlands", "EG": "Egypt"}
print(countries["EG"]) # Output: Egypt
- Grouping data:
records = [("EU","NL"), ("EU","DE"), ("US","CA")]
groups = {}
for region, country in records:
groups.setdefault(region, []).append(country)
print(groups) # {'EU': ['NL', 'DE'], 'US': ['CA']}
Nesting and Comprehensions (List, Dict, Set)
Comprehensions are one of Python’s most elegant features. They let you build new collections (lists, dicts, sets) in a single, readable line, often replacing multiple loops. Combined with nesting, they become powerful tools for data transformation.
1. List Comprehensions
A list comprehension creates a new list by applying an expression to each item of an iterable.
# Basic form
[expression for item in iterable if condition]
- Without comprehension
squares = []
for x in range(5):
squares.append(x**2)
- With comprehension
squares = [x**2 for x in range(5)]
print(squares) # [0, 1, 4, 9, 16]
- With condition
even_squares = [x**2 for x in range(10) if x % 2 == 0]
print(even_squares) # [0, 4, 16, 36, 64]
2. Dictionary Comprehensions
A dictionary comprehension builds dictionaries concisely.
# Create mapping: number → square
squares = {x: x**2 for x in range(5)}
print(squares) # {0:0, 1:1, 2:4, 3:9, 4:16}
- With condition
prices = {"apple": 2, "banana": 1, "pear": 3}
discounted = {k: v*0.9 for k, v in prices.items() if v > 1}
print(discounted) # {'apple': 1.8, 'pear': 2.7}
3. Set Comprehensions
A set comprehension builds sets, automatically removing duplicates.
nums = [1, 2, 2, 3, 4, 4, 5]
unique_squares = {x**2 for x in nums}
print(unique_squares) # {1, 4, 9, 16, 25}
4. Nesting with Comprehensions
Comprehensions can be nested, replacing multiple loops.
- Nested loops in list comprehension
pairs = [(x, y) for x in [1, 2] for y in [3, 4]]
print(pairs) # [(1,3), (1,4), (2,3), (2,4)]
- Flattening nested lists
matrix = [[1,2,3], [4,5,6], [7,8,9]]
flat = [num for row in matrix for num in row]
print(flat) # [1,2,3,4,5,6,7,8,9]
- Nested condition
even_pairs = [(x, y) for x in range(3) for y in range(3) if (x+y) % 2 == 0]
print(even_pairs) # [(0,0), (0,2), (1,1), (2,0), (2,2)]
5. Common Use Cases
- Transforming data
names = ["Amr", "Sara", "Ali"]
lower = [n.lower() for n in names]
- Filtering
nums = [10, 15, 20, 25]
even = [n for n in nums if n % 2 == 0]
- Building dict from two lists
keys = ["a", "b", "c"]
values = [1, 2, 3]
mapping = {k: v for k, v in zip(keys, values)}
- Set of vowels in a word
word = "comprehension"
vowels = {ch for ch in word if ch in "aeiou"}
print(vowels) # {'o', 'e', 'i'}
6. Pitfalls
- Readability: Don’t overuse nesting; complex comprehensions can be harder to understand.
- Memory use: For very large ranges, prefer generator expressions with
()instead of[].
# Generator (lazy evaluation)
squares = (x**2 for x in range(1000000))