Chapter 05: Values, Variables, and Types — Exercises¶
Overview¶
These exercises help you understand how Python stores and manages data: values, variables, types, and the difference between mutable and immutable objects. By the end, you will confidently work with Python's type system and avoid common pitfalls.
How to Use These Exercises¶
- Create a folder called
chapter-05in yourpython-learningdirectory. - Write each program in a separate
.pyfile. - Run each program and observe the output.
- Experiment with variations to deepen your understanding.
Warm-up Exercises¶
Exercise 1: Explore Types with type()¶
Create a file called explore_types.py:
# Test the type() function with different values
print(type(42))
print(type(3.14))
print(type("hello"))
print(type(True))
print(type(None))
print(type([1, 2, 3]))
print(type((1, 2, 3)))
print(type({1, 2, 3}))
print(type({"name": "Alice"}))
Run it and write down the output for each. Notice the pattern: each value has a type.
Exercise 2: Understand Dynamic Typing¶
Create a file called dynamic_typing.py:
x = 10
print(f"x = {x}, type = {type(x)}")
x = "hello"
print(f"x = {x}, type = {type(x)}")
x = [1, 2, 3]
print(f"x = {x}, type = {type(x)}")
x = None
print(f"x = {x}, type = {type(x)}")
Run it. Notice how x can hold different types at different times. This is dynamic typing.
Exercise 3: Convert Between Types¶
Create a file called type_conversion.py:
# String to integer
num_str = "42"
num_int = int(num_str)
print(f"'{num_str}' as int: {num_int}")
# Integer to string
num = 42
num_str = str(num)
print(f"{num} as string: '{num_str}'")
# String to float
price_str = "19.99"
price_float = float(price_str)
print(f"'{price_str}' as float: {price_float}")
# Float to integer (truncates, does not round)
value = 3.9
truncated = int(value)
print(f"{value} as int (truncated): {truncated}")
# Integer to boolean
print(f"int(0) as bool: {bool(0)}")
print(f"int(1) as bool: {bool(1)}")
print(f"int(42) as bool: {bool(42)}")
# String to list
text = "hello"
chars = list(text)
print(f"'{text}' as list: {chars}")
Run it and observe the conversions.
Practice Exercises¶
Exercise 4: Understand Mutability¶
Create a file called mutability.py:
# Immutable: strings
s1 = "hello"
s2 = s1
s2 = s2.upper() # creates a new string
print(f"s1: {s1}") # still "hello"
print(f"s2: {s2}") # "HELLO"
print(f"s1 is s2: {s1 is s2}") # False — different objects
# Mutable: lists
list1 = [1, 2, 3]
list2 = list1
list2.append(4) # modifies the existing list
print(f"list1: {list1}") # [1, 2, 3, 4] — affected!
print(f"list2: {list2}") # [1, 2, 3, 4]
print(f"list1 is list2: {list1 is list2}") # True — same object
# Fix: make a copy
list3 = [1, 2, 3]
list4 = list3.copy() # independent copy
list4.append(4)
print(f"list3: {list3}") # [1, 2, 3] — not affected
print(f"list4: {list4}") # [1, 2, 3, 4]
Run it and observe the difference between mutable and immutable types.
Exercise 5: Use is vs ==¶
Create a file called is_vs_equals.py:
# Value equality with ==
a = [1, 2, 3]
b = [1, 2, 3]
print(f"a == b: {a == b}") # True — same values
print(f"a is b: {a is b}") # False — different objects
# Identity with is
c = a
print(f"a is c: {a is c}") # True — same object
# With None (always use is)
x = None
print(f"x is None: {x is None}") # True
print(f"x == None: {x == None}") # True (works, but not idiomatic)
# With small integers (CPython caches them)
n1 = 100
n2 = 100
print(f"n1 is n2: {n1 is n2}") # True (implementation detail)
m1 = 1000
m2 = 1000
print(f"m1 is m2: {m1 is m2}") # False (not cached)
# Rule: use == for values, is for None/True/False
Run it and observe the difference between is and ==.
Exercise 6: Multiple Assignment and Unpacking¶
Create a file called unpacking.py:
# Assign the same value to multiple variables
x = y = z = 0
print(f"x={x}, y={y}, z={z}")
# Unpack a tuple
a, b = 10, 20
print(f"a={a}, b={b}")
# Swap without a temporary variable
a, b = b, a
print(f"After swap: a={a}, b={b}")
# Unpack from a list
first, second, third = [1, 2, 3]
print(f"first={first}, second={second}, third={third}")
# Extended unpacking with *
numbers = [1, 2, 3, 4, 5]
head, *middle, tail = numbers
print(f"head={head}, middle={middle}, tail={tail}")
# Ignore values with _
x, _, z = (1, 2, 3)
print(f"x={x}, z={z}")
Run it and experiment with different unpacking patterns.
Exercise 7: Understand Variable Scope¶
Create a file called scope.py:
# Global variable
global_var = "I am global"
def my_function():
# Local variable
local_var = "I am local"
print(f"Inside function: {local_var}")
print(f"Inside function: {global_var}")
my_function()
print(f"Outside function: {global_var}")
# print(f"Outside function: {local_var}") # This would cause NameError
Run it. Notice that local_var is not accessible outside the function, but global_var is.
Challenge Exercises¶
Challenge 1: Safe Type Conversion from User Input¶
Create a file called safe_input.py:
def get_integer(prompt):
"""Ask for an integer, return it or None if invalid."""
raw = input(prompt)
try:
return int(raw)
except ValueError:
print(f"Error: '{raw}' is not a valid integer.")
return None
def get_float(prompt):
"""Ask for a float, return it or None if invalid."""
raw = input(prompt)
try:
return float(raw)
except ValueError:
print(f"Error: '{raw}' is not a valid number.")
return None
if __name__ == "__main__":
age = get_integer("Enter your age: ")
if age is not None:
print(f"In 10 years you will be {age + 10}.")
price = get_float("Enter a price: ")
if price is not None:
tax = price * 0.08
print(f"Price: ${price:.2f}, Tax: ${tax:.2f}")
Run it and test with valid and invalid inputs.
Challenge 2: Explore Truthiness¶
Create a file called truthiness.py:
def check_truthiness(value):
"""Print whether a value is truthy or falsy."""
if value:
print(f"{value!r} is truthy")
else:
print(f"{value!r} is falsy")
# Test various values
check_truthiness(True)
check_truthiness(False)
check_truthiness(0)
check_truthiness(1)
check_truthiness(42)
check_truthiness("")
check_truthiness("hello")
check_truthiness([])
check_truthiness([1, 2, 3])
check_truthiness(())
check_truthiness((1,))
check_truthiness({})
check_truthiness({"key": "value"})
check_truthiness(None)
Run it and observe which values are truthy and which are falsy.
Challenge 3: Demonstrate Mutable vs Immutable¶
Create a file called mutable_demo.py:
def modify_immutable(value):
"""Try to modify an immutable value."""
value = value + " modified"
return value
def modify_mutable(items):
"""Modify a mutable list."""
items.append("new item")
# Test with immutable
original_str = "hello"
result = modify_immutable(original_str)
print(f"Original string: {original_str}")
print(f"Returned value: {result}")
# Test with mutable
original_list = [1, 2, 3]
modify_mutable(original_list)
print(f"Original list: {original_list}")
Run it and observe how immutable and mutable types behave differently.
Challenge 4: Use isinstance() for Type Checking¶
Create a file called type_checking.py:
def process_value(value):
"""Process a value based on its type."""
if isinstance(value, int):
print(f"{value} is an integer. Doubled: {value * 2}")
elif isinstance(value, float):
print(f"{value} is a float. Rounded: {round(value)}")
elif isinstance(value, str):
print(f"'{value}' is a string. Uppercase: {value.upper()}")
elif isinstance(value, list):
print(f"{value} is a list. Length: {len(value)}")
elif isinstance(value, bool):
print(f"{value} is a boolean.")
elif value is None:
print("Value is None.")
else:
print(f"Unknown type: {type(value)}")
# Test with different types
process_value(42)
process_value(3.14)
process_value("hello")
process_value([1, 2, 3])
process_value(True)
process_value(None)
Run it and observe how isinstance() handles different types.
Challenge 5: Create a Type Converter Function¶
Create a file called converter.py:
def convert_to_type(value, target_type):
"""
Convert a value to a target type.
Args:
value: The value to convert
target_type: The target type ('int', 'float', 'str', 'bool', 'list')
Returns:
The converted value, or None if conversion fails
"""
try:
if target_type == 'int':
return int(value)
elif target_type == 'float':
return float(value)
elif target_type == 'str':
return str(value)
elif target_type == 'bool':
return bool(value)
elif target_type == 'list':
return list(value)
else:
print(f"Unknown type: {target_type}")
return None
except (ValueError, TypeError) as e:
print(f"Conversion failed: {e}")
return None
# Test conversions
print(convert_to_type("42", 'int'))
print(convert_to_type("3.14", 'float'))
print(convert_to_type(42, 'str'))
print(convert_to_type("hello", 'list'))
print(convert_to_type("not a number", 'int'))
Run it and test various conversions.
Hints¶
ValueError when converting → The string cannot be converted to that type. Check the format.
NameError for a variable → The variable is out of scope or not defined. Check where it was created.
Unexpected mutation → You assigned a mutable object to another variable. Use .copy() to make an independent copy.
is returning unexpected results → Remember that is checks object identity, not value equality. Use == for values.
What to Review If You Get Stuck¶
- Values and variables → Handbook section 3.1
- Dynamic typing → Handbook section 3.2
- The
type()function → Handbook section 3.3 - Built-in types → Handbook section 3.4
- Type conversion → Handbook section 3.6
isinstance()vstype()→ Handbook section 3.7- Variables are references → Handbook section 3.8
- Mutability → Handbook section 3.8
- Multiple assignment → Handbook section 3.9
- Variable scope → Handbook section 3.12
Key Takeaways¶
After completing these exercises, you should be able to:
- Understand Python's type system and dynamic typing
- Convert between types safely
- Distinguish between mutable and immutable types
- Use
isand==correctly - Unpack values from sequences
- Understand variable scope
- Handle type conversion errors gracefully