Session Overview
Welcome to our exploration of Python's foundational elements! Today, we'll dive into variables, data types, and basic operations that form the building blocks of any Python program. Understanding these concepts thoroughly will give you a solid foundation for Python development and allow you to express your ideas clearly in code.
Understanding Variables in Python
Variables are named storage locations in computer memory. Think of them as labeled containers that hold data which can be changed during program execution.
Variable Assignment
In Python, you create a variable by assigning a value to a name:
# Basic variable assignment
name = "Alice"
age = 30
height = 5.7
is_student = True
Unlike many other programming languages, Python doesn't require you to declare a variable's type before using it. The type is determined automatically based on the value assigned.
Variable Naming Rules
- Variable names must start with a letter or underscore (_)
- Variable names can only contain letters, numbers, and underscores
- Variable names are case-sensitive (
name,Name, andNAMEare different variables) - Variable names cannot be Python keywords (like
if,for,while, etc.)
Python Naming Conventions
- snake_case for variables and functions (e.g.,
user_name,calculate_total) - PascalCase for classes (e.g.,
Person,BankAccount) - SCREAMING_SNAKE_CASE for constants (e.g.,
MAX_VALUE,PI) - Leading underscore for private variables (e.g.,
_internal_value)
Analogy: Variables as Labeled Boxes
Think of variables as labeled boxes in a storage room:
- Each box has a name (the variable name) written on it
- You can put things in the box (assign values)
- You can replace the contents with something else (reassign values)
- You can look inside to see what's there (retrieve values)
- You can create new boxes or discard old ones as needed
This analogy helps understand why the same variable can hold different types of data at different times - you can put anything in a box!
Multiple Assignment
Python allows for assigning multiple variables at once:
# Assign same value to multiple variables
x = y = z = 0
# Assign multiple values to multiple variables
a, b, c = 1, 2, 3
# Swap values without a temporary variable
a, b = b, a
Variable Scope
The scope of a variable determines where in your code the variable can be accessed. Python has several scopes:
- Local scope: Variables defined within a function
- Enclosing scope: Variables defined in outer functions
- Global scope: Variables defined at the module level
- Built-in scope: Python's pre-defined names
global_var = "I'm global"
def outer_function():
outer_var = "I'm in the outer function"
def inner_function():
local_var = "I'm local"
print(local_var) # Accesses local variable
print(outer_var) # Accesses enclosing variable
print(global_var) # Accesses global variable
inner_function()
Python Data Types
Python has several built-in data types to represent different kinds of values. Unlike statically-typed languages, Python is dynamically-typed, meaning a variable can change its type during program execution.
Numeric Types
Python provides three numeric types:
# Integer (whole numbers)
age = 30
count = -5
big_number = 10000000000 # Python integers have unlimited precision
# Float (decimal numbers)
height = 5.7
pi = 3.14159
scientific = 2.5e6 # Scientific notation (2.5 million)
# Complex (numbers with real and imaginary parts)
complex_num = 2 + 3j
String Type
Strings are sequences of characters, enclosed in single, double, or triple quotes:
# Single quotes
name = 'Alice'
# Double quotes
message = "Hello, World!"
# Triple quotes for multi-line strings
description = """This is a long description
that spans multiple lines,
which is easy to read in the code."""
# Strings are immutable (cannot be changed after creation)
name = 'Alice'
# This creates a new string, doesn't modify the original
new_name = name + ' Smith'
Boolean Type
Boolean values represent truth values, either True or False:
is_student = True
has_permission = False
# Comparison operations yield boolean results
is_adult = age >= 18
is_valid = name != ""
Sequence Types
Python has several sequence types that can hold collections of items:
# Lists - ordered, mutable collections
fruits = ['apple', 'banana', 'cherry']
mixed_list = [1, 'hello', True, 3.14]
# Tuples - ordered, immutable collections
coordinates = (10.5, 20.8)
person = ('Alice', 30, 'Engineer')
# Ranges - sequence of numbers
numbers = range(10) # 0 to 9
even_numbers = range(0, 10, 2) # 0, 2, 4, 6, 8
Mapping Type
Dictionaries store key-value pairs:
# Dictionary - unordered collection of key-value pairs
person = {
'name': 'Alice',
'age': 30,
'profession': 'Engineer',
'is_student': False
}
# Accessing values
print(person['name']) # Alice
# Adding new key-value pairs
person['location'] = 'New York'
Set Types
Sets store unordered collections of unique items:
# Set - unordered collection of unique elements
fruits = {'apple', 'banana', 'cherry'}
# Adding and removing elements
fruits.add('orange')
fruits.remove('banana')
# Set operations
basket1 = {'apple', 'orange', 'banana'}
basket2 = {'pear', 'banana', 'kiwi'}
all_fruits = basket1 | basket2 # Union
common_fruits = basket1 & basket2 # Intersection
None Type
Python has a special None value that represents the absence of a value:
# None represents the absence of a value
result = None
def function_without_return():
pass # Do something but don't return a value
value = function_without_return() # value will be None
Analogy: Data Types as Different Container Types
Think of different data types as different kinds of containers:
- Integers and Floats: Like measuring cups for different measurements (whole vs. fractional)
- Strings: Like letter beads strung together on a necklace
- Lists: Like a drawer organizer with ordered compartments
- Tuples: Like a sealed package with multiple items inside
- Dictionaries: Like a filing cabinet where each file (value) has a label (key)
- Sets: Like a collection of unique stamps
Just as you wouldn't store soup in a file folder, each data type in Python is optimized for certain operations and ways of organizing data.
Checking Types
You can check the type of a variable using the type() function:
x = 42
y = "Hello"
z = [1, 2, 3]
print(type(x)) #
print(type(y)) #
print(type(z)) #
Type Conversion
Python provides functions to convert between types:
# Converting between types
age_str = "30"
age_int = int(age_str) # String to integer
age_float = float(age_int) # Integer to float
age_str_again = str(age_int) # Integer to string
# Converting collections
my_list = [1, 2, 3, 2, 1]
my_tuple = tuple(my_list) # List to tuple
my_set = set(my_list) # List to set (duplicates removed)
my_list_again = list(my_set) # Set to list
Basic Operations in Python
Arithmetic Operations
Python supports all standard arithmetic operations:
# Addition
sum = 5 + 3 # 8
# Subtraction
difference = 10 - 4 # 6
# Multiplication
product = 6 * 7 # 42
# Division (always returns float)
quotient = 12 / 4 # 3.0
# Integer Division (floors the result)
int_quotient = 13 // 5 # 2
# Modulus (remainder)
remainder = 13 % 5 # 3
# Exponentiation
power = 2 ** 3 # 8
# Combining operations with order of precedence
result = 10 + 3 * 2 # 16 (not 26, because * has higher precedence than +)
result_with_parens = (10 + 3) * 2 # 26
String Operations
Strings support concatenation, repetition, and indexing:
# Concatenation
first_name = "John"
last_name = "Doe"
full_name = first_name + " " + last_name # "John Doe"
# String repetition
stars = "*" * 10 # "**********"
# Indexing (0-based)
first_letter = full_name[0] # "J"
last_letter = full_name[-1] # "e"
# Slicing
substring = full_name[5:8] # "Doe"
first_five = full_name[:5] # "John "
from_sixth = full_name[5:] # "Doe"
# Length
name_length = len(full_name) # 8
# String methods
uppercase = full_name.upper() # "JOHN DOE"
lowercase = full_name.lower() # "john doe"
replaced = full_name.replace("John", "Jane") # "Jane Doe"
Boolean Operations
Python has logical operations for combining boolean values:
# AND operation (True if both operands are True)
result = True and False # False
# OR operation (True if at least one operand is True)
result = True or False # True
# NOT operation (inverts the boolean value)
result = not True # False
# Combining operations
complex_logic = (True or False) and not (False and True) # True
Comparison Operations
Comparison operations compare values and return boolean results:
# Equal
is_equal = 5 == 5 # True
# Not equal
is_not_equal = 5 != 10 # True
# Greater than
is_greater = 10 > 5 # True
# Less than
is_less = 5 < 10 # True
# Greater than or equal
is_greater_equal = 10 >= 10 # True
# Less than or equal
is_less_equal = 5 <= 5 # True
# Chained comparisons
is_in_range = 1 < 5 < 10 # True (equivalent to 1 < 5 and 5 < 10)
Identity and Membership Operations
Python provides operations to check identity and membership:
# Identity operations (check if objects are the same object in memory)
a = [1, 2, 3]
b = [1, 2, 3]
c = a
print(a is b) # False (different objects with the same values)
print(a is c) # True (same object)
print(a is not b) # True
# Membership operations (check if a value is in a sequence)
fruits = ['apple', 'banana', 'cherry']
print('banana' in fruits) # True
print('orange' in fruits) # False
print('orange' not in fruits) # True
Compound Assignment Operations
Python provides shortcuts for updating variables:
# Addition assignment
x = 10
x += 5 # Equivalent to x = x + 5, x is now 15
# Subtraction assignment
x -= 3 # x is now 12
# Multiplication assignment
x *= 2 # x is now 24
# Division assignment
x /= 4 # x is now 6.0
# Integer division assignment
x //= 2 # x is now 3.0
# Modulus assignment
y = 10
y %= 3 # y is now 1
# Exponentiation assignment
y **= 3 # y is now 1 (1^3 = 1)
Analogy: Operations as Kitchen Tools
Think of Python operations as different kitchen tools:
- Arithmetic operations are like basic kitchen tools (knife for cutting/subtraction, mixer for combining/addition)
- String operations are like tools for working with dough (rolling for extending, cookie cutters for slicing)
- Boolean operations are like sieves and strainers that filter based on conditions
- Comparison operations are like measuring tools that tell you relationships between ingredients
- Compound operations are like all-in-one appliances that perform multiple steps in one action
Just as a good chef knows which tool to use when, a good programmer chooses the right operations for the task at hand.
String Formatting
Python offers several ways to format strings by inserting values into string templates:
F-strings (Python 3.6+)
F-strings provide a concise and readable way to embed expressions inside string literals:
name = "Alice"
age = 30
# Basic f-string
greeting = f"Hello, {name}! You are {age} years old."
# Expressions in f-strings
greeting = f"Hello, {name.upper()}! Next year, you'll be {age + 1}."
# Formatting specifiers
pi = 3.14159265359
formatted = f"Pi to 2 decimal places: {pi:.2f}" # "Pi to 2 decimal places: 3.14"
# Alignment and padding
for i in range(1, 4):
print(f"{i:3} squared is {i**2:3}")
# Output:
# 1 squared is 1
# 2 squared is 4
# 3 squared is 9
str.format() Method
The format() method is another way to format strings:
# Basic formatting
greeting = "Hello, {}! You are {} years old.".format(name, age)
# Positional arguments
greeting = "Hello, {0}! You are {1} years old. Nice to meet you, {0}!".format(name, age)
# Named arguments
greeting = "Hello, {name}! You are {age} years old.".format(name=name, age=age)
# Formatting specifiers
formatted = "Pi to 2 decimal places: {:.2f}".format(pi) # "Pi to 2 decimal places: 3.14"
% Operator (Older Style)
The % operator is an older way to format strings, still found in legacy code:
# Basic formatting
greeting = "Hello, %s! You are %d years old." % (name, age)
# Formatting specifiers
formatted = "Pi to 2 decimal places: %.2f" % pi # "Pi to 2 decimal places: 3.14"
While all these methods work, f-strings are recommended for new code due to their readability and performance.
Operations on Collections
List Operations
Lists support many operations for adding, removing, and modifying elements:
fruits = ['apple', 'banana', 'cherry']
# Adding elements
fruits.append('orange') # ['apple', 'banana', 'cherry', 'orange']
fruits.insert(1, 'blueberry') # ['apple', 'blueberry', 'banana', 'cherry', 'orange']
fruits.extend(['grape', 'kiwi']) # ['apple', 'blueberry', 'banana', 'cherry', 'orange', 'grape', 'kiwi']
# Removing elements
removed = fruits.pop() # Removes and returns 'kiwi'
fruits.pop(1) # Removes element at index 1 ('blueberry')
fruits.remove('banana') # Removes the first occurrence of 'banana'
# Finding elements
index = fruits.index('cherry') # Gets the index of 'cherry'
count = fruits.count('apple') # Counts how many 'apple' items are in the list
# Sorting
fruits.sort() # Sorts the list in place
fruits.sort(reverse=True) # Sorts in descending order
sorted_fruits = sorted(fruits) # Returns a new sorted list, leaving the original unchanged
# Reversing
fruits.reverse() # Reverses the list in place
reversed_fruits = list(reversed(fruits)) # Returns a new reversed list
Dictionary Operations
Dictionaries store key-value pairs and provide efficient lookups:
person = {'name': 'Alice', 'age': 30}
# Adding or updating entries
person['location'] = 'New York' # Adds a new key-value pair
person['age'] = 31 # Updates an existing value
# Accessing values
name = person['name'] # Gets the value for key 'name'
# Safely get a value with a default if the key doesn't exist
location = person.get('job', 'Unknown') # Returns 'Unknown' if 'job' key doesn't exist
# Removing entries
removed_age = person.pop('age') # Removes the key and returns its value
person.popitem() # Removes and returns the last inserted key-value pair
# Checking for keys
has_name = 'name' in person # Checks if 'name' is a key in the dictionary
# Getting keys, values, and items
keys = list(person.keys()) # Gets all keys
values = list(person.values()) # Gets all values
items = list(person.items()) # Gets all key-value pairs as tuples
# Merging dictionaries
person.update({'job': 'Engineer', 'email': 'alice@example.com'}) # Adds/updates from another dict
Set Operations
Sets provide mathematical set operations:
set1 = {1, 2, 3, 4, 5}
set2 = {4, 5, 6, 7, 8}
# Adding and removing elements
set1.add(6) # Adds an element
set1.remove(1) # Removes an element (raises error if not found)
set1.discard(10) # Removes an element if present (no error if not found)
popped = set1.pop() # Removes and returns an arbitrary element
# Set operations
union = set1 | set2 # Elements in either set
intersection = set1 & set2 # Elements in both sets
difference = set1 - set2 # Elements in set1 but not in set2
symmetric_difference = set1 ^ set2 # Elements in either set but not both
# Checking membership
is_in_set = 3 in set1
# Checking subset/superset relationships
is_subset = set1 <= set2 # Is set1 a subset of set2?
is_superset = set1 >= set2 # Is set1 a superset of set2?
Advanced Topics
List Comprehensions
List comprehensions provide a concise way to create lists:
# Create a list of squares
squares = [x**2 for x in range(10)] # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# Filtering with a condition
even_squares = [x**2 for x in range(10) if x % 2 == 0] # [0, 4, 16, 36, 64]
# Nested loops
coordinates = [(x, y) for x in range(3) for y in range(2)]
# [(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)]
Dictionary Comprehensions
Similar to list comprehensions, but for creating dictionaries:
# Create a dictionary of squares
squares_dict = {x: x**2 for x in range(5)} # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
# Filtering with a condition
even_squares_dict = {x: x**2 for x in range(10) if x % 2 == 0}
# {0: 0, 2: 4, 4: 16, 6: 36, 8: 64}
# Transforming keys and values
name_lengths = {name: len(name) for name in ['Alice', 'Bob', 'Charlie']}
# {'Alice': 5, 'Bob': 3, 'Charlie': 7}
Set Comprehensions
Create sets with a similar syntax:
# Create a set of squares
squares_set = {x**2 for x in range(10)} # {0, 1, 4, 9, 16, 25, 36, 49, 64, 81}
# Filtering with a condition
even_squares_set = {x**2 for x in range(10) if x % 2 == 0}
# {0, 4, 16, 36, 64}
Unpacking
Unpacking allows you to assign multiple variables from collections:
# Unpacking a list
numbers = [1, 2, 3]
a, b, c = numbers # a=1, b=2, c=3
# Unpacking with * to collect remaining items
first, *rest = [1, 2, 3, 4, 5] # first=1, rest=[2, 3, 4, 5]
*beginning, last = [1, 2, 3, 4, 5] # beginning=[1, 2, 3, 4], last=5
first, *middle, last = [1, 2, 3, 4, 5] # first=1, middle=[2, 3, 4], last=5
# Unpacking dictionaries with ** (in function calls)
person = {'name': 'Alice', 'age': 30}
print("%(name)s is %(age)d years old." % person) # "Alice is 30 years old."
Practical Examples
Temperature Converter
def celsius_to_fahrenheit(celsius):
"""Convert Celsius to Fahrenheit."""
return (celsius * 9/5) + 32
def fahrenheit_to_celsius(fahrenheit):
"""Convert Fahrenheit to Celsius."""
return (fahrenheit - 32) * 5/9
# Using the functions
celsius = 25
fahrenheit = celsius_to_fahrenheit(celsius)
print(f"{celsius}°C is {fahrenheit:.1f}°F")
fahrenheit = 98.6
celsius = fahrenheit_to_celsius(fahrenheit)
print(f"{fahrenheit}°F is {celsius:.1f}°C")
Contact List Manager
contacts = {}
def add_contact(name, phone, email=None):
"""Add a contact to the contacts dictionary."""
contacts[name] = {'phone': phone, 'email': email}
print(f"Added contact: {name}")
def display_contact(name):
"""Display a contact's information."""
if name in contacts:
contact = contacts[name]
print(f"Name: {name}")
print(f"Phone: {contact['phone']}")
if contact['email']:
print(f"Email: {contact['email']}")
else:
print(f"No contact found with name: {name}")
def list_contacts():
"""List all contacts."""
if contacts:
print("Contacts:")
for name in sorted(contacts.keys()):
print(f"- {name}: {contacts[name]['phone']}")
else:
print("No contacts saved.")
# Using the functions
add_contact("Alice", "555-1234", "alice@example.com")
add_contact("Bob", "555-5678")
list_contacts()
display_contact("Alice")
display_contact("Charlie") # Not found
Word Frequency Counter
def count_word_frequency(text):
"""Count the frequency of each word in a text."""
# Convert to lowercase and split into words
words = text.lower().split()
# Remove punctuation from words
cleaned_words = []
for word in words:
cleaned_word = word.strip('.,!?:;()"\'')
if cleaned_word: # Skip empty strings
cleaned_words.append(cleaned_word)
# Count word frequencies
frequencies = {}
for word in cleaned_words:
if word in frequencies:
frequencies[word] += 1
else:
frequencies[word] = 1
return frequencies
def display_word_frequencies(frequencies):
"""Display word frequencies sorted by most common."""
# Sort by frequency (descending) and then by word (ascending)
sorted_frequencies = sorted(frequencies.items(),
key=lambda x: (-x[1], x[0]))
print("Word frequencies:")
for word, count in sorted_frequencies:
print(f"{word}: {count}")
# Example text
text = """
Python is a programming language that lets you work quickly
and integrate systems more effectively. Python is easy to learn,
yet powerful programming language. Its efficient high-level data structures
and a simple but effective approach to object-oriented programming.
"""
frequencies = count_word_frequency(text)
display_word_frequencies(frequencies)
Practice Exercises
Exercise 1: Basic Operations
- Create variables for your name, age, and favorite number
- Calculate and store your age in days
- Create a string that says "My name is [your name], I am [your age] years old, and my favorite number is [your favorite number]"
- Print the length of your name
- Check if your age is greater than your favorite number and store the result in a boolean variable
Exercise 2: Collections
- Create a list of 5 fruits
- Create a dictionary with information about yourself (name, age, city, etc.)
- Create a set of 3 hobbies
- Add a new fruit to your list and a new hobby to your set
- Update your age in the dictionary
- Print the second fruit in your list
- Check if a specific fruit is in your list
Exercise 3: BMI Calculator
Create a Body Mass Index (BMI) calculator program that:
- Asks the user for their weight in kilograms and height in meters
- Calculates the BMI using the formula: BMI = weight / (height * height)
- Displays the BMI value and a message based on the following categories:
- Below 18.5: Underweight
- 18.5 - 24.9: Normal weight
- 25 - 29.9: Overweight
- 30 and above: Obesity
Wrapping Up and Next Steps
Today we've covered the foundational building blocks of Python programming: variables, data types, and basic operations. These concepts form the basis for all Python programming, and mastering them is essential for your journey as a Python developer.
Key Takeaways
- Variables are named storage locations that can hold different types of data
- Python has several built-in data types, including numeric types, strings, boolean, and collections
- Python provides a rich set of operations for working with different data types
- String formatting allows you to create dynamic text with embedded values
- Collections (lists, dictionaries, sets) provide powerful ways to organize and manipulate data
- Comprehensions offer concise syntax for creating and transforming collections
Where to Go from Here
In our next session, we'll build on these fundamentals as we explore control structures in Python - the tools that allow us to make decisions and repeat actions in our programs. We'll cover conditional statements, loops, and more advanced flow control techniques.