Python Detailed Notes
Python Detailed Notes
1. Hello Python!
Explanation
"Hello Python!" is a traditional first program in many programming languages. Its purpose is to
demonstrate the simplest possible way to get the language to produce output, often a simple
message like "Hello, World!". In Python, this is achieved using the print() function.
Syntax
Python
print("Your message here")
Code Example
Python
print("Hello, Python!")
Building on "Hello Python!", your first Python code typically involves executing this simple
command. Python code is executed line by line. When you run a Python script, the interpreter
reads each line and performs the action specified. The print() function is a built-in function that
displays the given argument(s) to the console.
Syntax
Python
# A simple statement to execute
print("Text or variable to display")
Code Example
Python
# This is your first Python code!
print("Learning Python is fun!")
print("Welcome to the world of programming.")
3. Python as a calculator
Explanation
One of the most fundamental uses of Python is performing mathematical calculations. Python's
interpreter can act like a powerful calculator, handling basic arithmetic operations directly. It
follows the standard order of operations (PEMDAS/BODMAS).
Syntax
● +: Addition
● -: Subtraction
● *: Multiplication
● /: Division (results in float)
● //: Floor Division (results in integer, discards remainder)
● %: Modulo (returns the remainder of a division)
● **: Exponentiation (power)
Code Example
Python
# Addition
result_add = 5 + 3
print(f"5 + 3 = {result_add}") # Output: 5 + 3 = 8
# Subtraction
result_sub = 10 - 4
print(f"10 - 4 = {result_sub}") # Output: 10 - 4 = 6
# Multiplication
result_mult = 6 * 7
print(f"6 * 7 = {result_mult}") # Output: 6 * 7 = 42
# Division
result_div = 15 / 2
print(f"15 / 2 = {result_div}") # Output: 15 / 2 = 7.5
# Floor Division
result_floor_div = 15 // 2
print(f"15 // 2 = {result_floor_div}") # Output: 15 // 2 = 7
# Modulo
result_modulo = 15 % 2
print(f"15 % 2 = {result_modulo}") # Output: 15 % 2 = 1
# Exponentiation
result_exp = 2 ** 3
print(f"2 ** 3 = {result_exp}") # Output: 2 ** 3 = 8
# Order of operations
complex_calc = (2 + 3) * 4 / 2
print(f"(2 + 3) * 4 / 2 = {complex_calc}") # Output: (2 + 3) * 4 / 2 = 10.0
In Python, variables are named locations used to store data in computer memory. They act as
labels for values. Every piece of data in Python has a specific "type" that determines what kind
of value it is (e.g., a whole number, a decimal number, text, etc.) and what operations can be
performed on it. Python is dynamically typed, meaning you don't need to declare a variable's
type before assigning a value to it; the type is inferred at runtime.
Syntax
Variables are created by assigning a value to a name using the assignment operator =.
Python
variable_name = value
You can check the type of a variable using the type() function:
Python
type(variable_name)
Code Example
Python
# Integer variable
age = 30
print(f"Age: {age}, Type: {type(age)}") # Output: Age: 30, Type: <class 'int'>
# Float variable
price = 19.99
print(f"Price: {price}, Type: {type(price)}") # Output: Price: 19.99, Type: <class 'float'>
# String variable
name = "Alice"
print(f"Name: {name}, Type: {type(name)}") # Output: Name: Alice, Type: <class 'str'>
# Boolean variable
is_active = True
print(f"Is Active: {is_active}, Type: {type(is_active)}") # Output: Is Active: True, Type: <class
'bool'>
5. Variable Assignment
Explanation
Variable assignment is the process of binding a name (the variable) to a specific value in
memory. In Python, the single equals sign (=) is the assignment operator. When a variable is
assigned a new value, the old value it referred to (if any) is no longer accessible via that variable
name. Python supports chained assignment and assigning multiple variables simultaneously.
Syntax
Python
variable_name = value
variable1 = variable2 = value # Chained assignment
var1, var2, var3 = val1, val2, val3 # Multiple assignment
Code Example
Python
# Basic assignment
my_number = 10
my_text = "Python"
print(f"my_number: {my_number}")
print(f"my_text: {my_text}")
# Reassignment
my_number = 20
print(f"my_number after reassignment: {my_number}")
# Chained assignment
x = y = z = 100
print(f"x: {x}, y: {y}, z: {z}")
# Multiple assignment
a, b = 5, 10
print(f"a: {a}, b: {b}")
Once values are stored in variables, you can use these variables in arithmetic expressions just
as you would use raw numbers. Python substitutes the current value of the variable into the
calculation. This makes your code more readable, flexible, and maintainable, as you can
change a value in one place (the variable assignment) and have it affect all calculations where
that variable is used.
Syntax
Python
result_variable = var1 operator var2
Code Example
Python
# Define variables
num1 = 25
num2 = 7
pi_value = 3.14159
Syntax
Code Example
Python
# List
my_list = [1, "apple", 3.14, True]
print(f"my_list: {my_list}, Type: {type(my_list)}") # Output: my_list: [1, 'apple', 3.14, True], Type:
<class 'list'>
# Tuple
my_tuple = (10, "banana", False)
print(f"my_tuple: {my_tuple}, Type: {type(my_tuple)}") # Output: my_tuple: (10, 'banana', False),
Type: <class 'tuple'>
# Dictionary
my_dict = {"name": "Charlie", "age": 25, "city": "New York"}
print(f"my_dict: {my_dict}, Type: {type(my_dict)}") # Output: my_dict: {'name': 'Charlie', 'age': 25,
'city': 'New York'}, Type: <class 'dict'>
# Set
my_set = {1, 2, 3, 2, 1} # Duplicates are automatically removed
print(f"my_set: {my_set}, Type: {type(my_set)}") # Output: my_set: {1, 2, 3}, Type: <class 'set'>
# NoneType
no_value = None
print(f"no_value: {no_value}, Type: {type(no_value)}") # Output: no_value: None, Type: <class
'NoneType'>
Different data types support different operations. While you can perform arithmetic on numbers,
strings support concatenation and repetition, and booleans are used in logical operations.
Understanding how to interact between different types, especially through type conversion
(casting), is fundamental. Python will raise TypeError if you try to perform an operation that is
not supported between specific types.
Syntax
Code Example
Python
# String Concatenation
greeting = "Hello"
name = "World"
full_message = greeting + " " + name + "!"
print(f"Concatenated string: {full_message}") # Output: Concatenated string: Hello World!
# String Repetition
star_line = "*" * 10
print(f"Repeated string: {star_line}") # Output: Repeated string: **********
# Integer to Float
int_num = 10
float_from_int = float(int_num)
print(f"Int to Float: {float_from_int}, Type: {type(float_from_int)}") # Output: Int to Float: 10.0,
Type: <class 'float'>
# String to Integer/Float
str_num_int = "123"
int_from_str = int(str_num_int)
print(f"String to Int: {int_from_str}, Type: {type(int_from_str)}") # Output: String to Int: 123, Type:
<class 'int'>
str_num_float = "45.67"
float_from_str = float(str_num_float)
print(f"String to Float: {float_from_str}, Type: {type(float_from_str)}") # Output: String to Float:
45.67, Type: <class 'float'>
# Boolean conversion
bool_from_int_zero = bool(0)
bool_from_int_nonzero = bool(5)
bool_from_empty_str = bool("")
bool_from_nonempty_str = bool("abc")
print(f"Bool from 0: {bool_from_int_zero}") # Output: Bool from 0: False
print(f"Bool from 5: {bool_from_int_nonzero}") # Output: Bool from 5: True
print(f"Bool from '': {bool_from_empty_str}") # Output: Bool from '': False
print(f"Bool from 'abc': {bool_from_nonempty_str}") # Output: Bool from 'abc': True
9. Python Lists
Explanation
Lists are one of the most versatile and widely used data structures in Python. A list is an
ordered collection of items, and it is mutable, meaning you can change its content (add,
remove, or modify elements) after it's created. List items are enclosed in square brackets [] and
separated by commas. Lists can contain items of different data types.
Syntax
Python
my_list = [item1, item2, item3, ...]
Code Example
Python
# Creating an empty list
empty_list = []
print(f"Empty list: {empty_list}, Type: {type(empty_list)}")
Creating a list is straightforward in Python. You simply enclose the items you want in the list
within square brackets [], separating each item with a comma. The items can be of any data
type.
Syntax
Python
list_name = [element1, element2, element3, ...]
Code Example
Python
# A list of numbers
temperatures = [22, 25, 19, 28, 21]
print(f"Temperatures: {temperatures}")
# A list of strings
names = ["Alice", "Bob", "Charlie", "David"]
print(f"Names: {names}")
# An empty list
shopping_list = []
print(f"Shopping list (empty): {shopping_list}")
One of the powerful features of Python lists is their ability to store items of different data types
within the same list. This heterogeneity allows you to represent complex data structures where
related information of varying kinds needs to be grouped together.
Syntax
Python
heterogeneous_list = [integer_value, float_value, "string_value", True, None, other_list, ...]
Code Example
Python
# A list containing an integer, a float, a string, and a boolean
mixed_data = [10, 3.14, "Hello", True]
print(f"Mixed data list: {mixed_data}")
Lists can contain other lists as their elements. This creates a nested structure, often used to
represent tabular data, matrices, or multi-dimensional arrays. Each inner list can be thought of
as a row or a sub-collection.
Syntax
Python
list_of_lists = [
[inner_list_item1, inner_list_item2],
[inner_list_item3, inner_list_item4],
# ...
]
Code Example
Python
# A simple 2x2 matrix
matrix = [
[1, 2],
[3, 4]
]
print(f"Matrix: {matrix}")
Subsetting a list means selecting one or more elements from it. In Python, list elements are
accessed using zero-based indexing, where the first element is at index 0, the second at index
1, and so on. Negative indexing can be used to access elements from the end of the list, with -1
referring to the last element, -2 to the second to last, etc.
Syntax
Code Example
Python
my_list = ["apple", "banana", "cherry", "date", "elderberry"]
Syntax
(This is a conceptual topic, syntax is covered in "Subsetting Lists" and "Slicing and dicing")
Code Example
Python
# Example: We have a list of daily temperatures
daily_temperatures = [18, 20, 22, 23, 21, 19, 20, 24, 26, 25] # 10 days of data
# "Conquer" a specific problem: Find the temperature on the 5th day (index 4)
temp_day_5 = daily_temperatures[4]
print(f"Temperature on day 5: {temp_day_5}") # Output: Temperature on day 5: 21
# "Conquer" a problem related to the last few days (slicing, covered next)
# Last three days of data
last_three_days = daily_temperatures[-3:]
print(f"Temperatures of the last three days: {last_three_days}") # Output: Temperatures of the
last three days: [24, 26, 25]
# This illustrates using subsetting to focus on relevant data for specific tasks.
Slicing allows you to extract a sub-list (a "slice") from an existing list. It creates a new list
containing a contiguous sequence of elements from the original list. The syntax uses a colon (:).
The slice includes the starting index up to (but not including) the ending index. If the start or end
index is omitted, it defaults to the beginning or end of the list, respectively.
Syntax
Python
my_list[start:end] # Elements from start up to (but not including) end
my_list[start:] # Elements from start to the end of the list
my_list[:end] # Elements from the beginning up to (but not including) end
my_list[:] # A copy of the entire list
my_list[start:end:step] # Elements from start to end, with a specified step size
Code Example
Python
letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']
When you have a list of lists (a nested list), you can subset it by applying indexing multiple
times. The first index selects the inner list (or "row"), and the second index then selects an
element within that chosen inner list. This allows you to pinpoint specific data points in tabular or
matrix-like structures.
Syntax
Python
list_of_lists[row_index][column_index]
Python
list_of_lists[row_slice]
And then apply column indexing/slicing to the result, but remember that a slice of a list of lists
will return a list of lists, not a single list to which you can apply a single column index directly.
Code Example
Python
# Student data: [Name, Age, Grade]
student_data = [
["Alice", 20, "A"],
["Bob", 22, "B"],
["Charlie", 21, "A+"],
["Diana", 23, "C"]
]
# Slicing rows
# Get the records for Bob and Charlie
bob_charlie_records = student_data[1:3]
print(f"Records for Bob and Charlie: {bob_charlie_records}")
# Output: Records for Bob and Charlie: [['Bob', 22, 'B'], ['Charlie', 21, 'A+']]
# Get only the names of all students (requires a loop, or list comprehension for more advanced)
# For now, illustrating access:
# For Alice's name from a slice:
print(f"Alice's name from first record: {student_data[0][0]}")
Lists are mutable, meaning their contents can be changed after creation. This allows for
dynamic manipulation, including adding, removing, or changing elements. This flexibility is a
core reason why lists are so widely used in Python.
Syntax
● Adding elements:
○ list.append(item): Adds an item to the end of the list.
○ list.insert(index, item): Inserts an item at a specific index.
○ list.extend(another_list): Appends all items from another iterable (like another
list) to the end of the current list.
● Removing elements:
○ list.remove(value): Removes the first occurrence of a specified value.
○ list.pop(index): Removes and returns the item at a given index (or the last item
if no index is specified).
○ del list[index] or del list[start:end]: Deletes item(s) at a specified index or
slice.
● Modifying elements:
○ list[index] = new_value: Changes the element at a specific index.
○ list[start:end] = new_sublist: Replaces a slice with a new sublist.
Code Example
Python
my_list = ['a', 'b', 'c']
print(f"Original list: {my_list}") # Output: Original list: ['a', 'b', 'c']
# 1. Add elements
my_list.append('d')
print(f"After append('d'): {my_list}") # Output: After append('d'): ['a', 'b', 'c', 'd']
my_list.insert(1, 'x')
print(f"After insert(1, 'x'): {my_list}") # Output: After insert(1, 'x'): ['a', 'x', 'b', 'c', 'd']
# 2. Modify elements
my_list[2] = 'B'
print(f"After my_list[2] = 'B': {my_list}") # Output: After my_list[2] = 'B': ['a', 'x', 'B', 'c', 'd']
# 3. Remove elements
removed_item_pop = my_list.pop(3) # Removes 'c'
print(f"After pop(3), removed: '{removed_item_pop}': {my_list}") # Output: After pop(3), removed:
'c': ['Z', 'Y', 'B', 'd']
my_list.remove('Y')
print(f"After remove('Y'): {my_list}") # Output: After remove('Y'): ['Z', 'B', 'd']
del my_list[0]
print(f"After del my_list[0]: {my_list}") # Output: After del my_list[0]: ['B', 'd']
# Using extend
list1 = [1, 2]
list2 = [3, 4]
list1.extend(list2)
print(f"After list1.extend(list2): {list1}") # Output: After list1.extend(list2): [1, 2, 3, 4]
# Note: `+` operator for lists creates a new list, doesn't modify in place
list_concat = [1, 2] + [3, 4]
print(f"List concatenation: {list_concat}") # Output: List concatenation: [1, 2, 3, 4]
Replacing elements in a list involves assigning a new value to an existing index or a slice of the
list. This directly modifies the list in place, making it a very efficient operation for updating data.
Syntax
Code Example
Python
fruits = ["apple", "banana", "cherry", "date"]
print(f"Original fruits: {fruits}") # Output: Original fruits: ['apple', 'banana', 'cherry', 'date']
Syntax
Python
my_list.extend(iterable_to_add)
Code Example
Python
primary_colors = ["red", "yellow", "blue"]
secondary_colors = ["orange", "green", "purple"]
print(f"Primary colors: {primary_colors}")
print(f"Secondary colors: {secondary_colors}")
list_a.append(list_b)
print(f"Using append: {list_a}") # Output: Using append: [1, 2, [3, 4]] (list_b becomes a single
element)
list_c = [1, 2]
list_c.extend(list_b)
print(f"Using extend: {list_c}") # Output: Using extend: [1, 2, 3, 4] (elements of list_b are added
individually)
Deleting elements from a list can be done in several ways, depending on whether you know the
element's value, its index, or a range of indices. These operations modify the list in place.
Syntax
Python
my_list.remove(value_to_remove)
removed_item = my_list.pop(index_to_remove) # index is optional
del my_list[index_to_delete]
del my_list[start:end] # Delete a slice
Code Example
Python
programming_languages = ["Python", "Java", "C++", "JavaScript", "Java"]
print(f"Original list: {programming_languages}")
# Using remove()
programming_languages.remove("Java") # Removes the first 'Java'
print(f"After remove('Java'): {programming_languages}") # Output: After remove('Java'):
['Python', 'C++', 'JavaScript', 'Java']
# Using pop()
removed_lang = programming_languages.pop(1) # Removes 'C++'
print(f"After pop(1), removed: '{removed_lang}': {programming_languages}") # Output: After
pop(1), removed: 'C++': ['Python', 'JavaScript', 'Java']
# Using del
del programming_languages[0] # Deletes 'Python'
print(f"After del programming_languages[0]: {programming_languages}") # Output: After del
programming_languages[0]: ['JavaScript']
Understanding the "inner workings" of lists involves grasping how Python stores and manages
them, especially regarding mutability and object references.
● Ordered Sequence: Lists maintain the order of elements as they are inserted.
● Dynamic Size: They can grow or shrink as elements are added or removed.
● Heterogeneous: Can store items of different data types.
● Mutable: Contents can be changed in place.
● Memory References: When you assign one list to another variable (e.g., list_b =
list_a), both variables refer to the same list object in memory. Modifying list_a will also
affect list_b. To create a copy that is independent, you need to use slicing (list_b =
list_a[:]) or the copy() method (list_b = list_a.copy()). This concept is crucial for
avoiding unexpected side effects.
Syntax
Code Example
Python
# 1. Assignment creates a reference
original_list = [1, 2, 3]
reference_list = original_list # reference_list points to the same object as original_list
print(f"Original: {original_list}, Reference: {reference_list}")
list_b.append(40)
print(f"List A after B's modification: {list_a}") # Output: List A after B's modification: [10, 20, 30]
print(f"List B after B's modification: {list_b}") # Output: List B after B's modification: [10, 20, 30,
40]
print(f"Are they the same object? {list_a is list_b}") # Output: Are they the same object? False
22. Functions
Explanation
A function is a block of organized, reusable code that performs a single, related action.
Functions provide better modularity for your application and a high degree of code reusing.
Python has many built-in functions, and you can also define your own. When you "call" a
function, you execute the code within it.
Syntax
Python
# Calling a built-in function
function_name(argument1, argument2, ...)
Code Example
Python
# Using built-in functions
my_list = [10, 20, 5, 30, 15]
length = len(my_list) # len() gets the number of items
print(f"Length of my_list: {length}") # Output: Length of my_list: 5
total = add_numbers(5, 7)
print(f"Sum of 5 and 7: {total}") # Output: Sum of 5 and 7: 12
Python provides a rich set of built-in functions that are readily available for common tasks
without needing to import any modules. You've already encountered some of them. Becoming
familiar with these functions can significantly speed up your coding and make your code more
concise.
Syntax
Python
function_name(argument(s))
Code Example
Python
data_points = [10, 5, 8, 12, 3, 7]
text = "Python Programming"
# len()
list_length = len(data_points)
string_length = len(text)
print(f"Length of data_points list: {list_length}") # Output: Length of data_points list: 6
print(f"Length of text string: {string_length}") # Output: Length of text string: 18
# type()
print(f"Type of data_points: {type(data_points)}") # Output: Type of data_points: <class 'list'>
print(f"Type of text: {type(text)}") # Output: Type of text: <class 'str'>
# Type conversion
num_str = "123"
converted_int = int(num_str)
print(f"'{num_str}' as int: {converted_int}, Type: {type(converted_int)}") # Output: '123' as int:
123, Type: <class 'int'>
When working with Python, you'll frequently need to understand how functions, methods, or
objects work. Python's built-in help() function is invaluable for this. It provides access to the
documentation (docstrings) of Python objects, detailing their purpose, arguments, and return
values. This is a primary tool for self-help and exploration in Python.
Syntax
Python
help(object_name)
You can pass the function name, method name, or even a data type to help().
Code Example
Python
# Get help on the print() function
print("Getting help for print() function:")
help(print)
# Output:
# Help on built-in function print in module builtins:
#
# print(...)
# print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
#
# Prints the values to a stream, or to sys.stdout by default.
# Optional keyword arguments:
# file: a file-like object (stream); defaults to the current sys.stdout.
# sep: string inserted between values, default a space.
# end: string appended after the last value, default a newline.
# flush: whether to forcibly flush the stream.
# (The output will continue with more details)
Many Python functions are designed to accept multiple arguments (also known as parameters)
to perform their task. These arguments provide the necessary input for the function to operate.
Arguments can be passed positionally (order matters) or as keyword arguments (name
matters).
Syntax
Python
function_name(positional_arg1, positional_arg2, keyword_arg=value, ...)
Code Example
Python
# The print() function is a good example of multiple arguments
print("Hello", "Python", "World", sep="-", end="!")
# Output: Hello-Python-World! (sep separates arguments, end is appended at the end)
room_area = calculate_area(5, 8)
print(f"\nArea of the room: {room_area} sq units") # Output: Area of the room: 40 sq units
# Example of function with varying number of arguments (*args and **kwargs) - advanced
def print_args(*args, **kwargs):
print("Positional arguments:", args)
print("Keyword arguments:", kwargs)
26. Methods
Explanation
In Python, a method is a function that "belongs" to an object. It's a function that is associated
with a specific data type (like a string, list, dictionary, etc.) and can be called on instances of that
type. Methods perform operations specifically relevant to the object they are called on. They are
accessed using dot notation (object.method_name()).
Syntax
Python
object_name.method_name(arguments_if_any)
Code Example
Python
# Example with a string object
my_string = "python programming"
print(f"Original string: '{my_string}'")
Strings are immutable sequences of characters. Python provides a rich set of built-in methods
that allow you to manipulate, analyze, and format strings. Since strings are immutable, these
methods typically return a new string with the desired changes, rather than modifying the
original string in place.
Syntax
Python
my_string.method_name(arguments_if_any)
Code Example
Python
my_string = " Hello Python Learners! "
print(f"Original string: '{my_string}'")
csv_data = "apple,banana,cherry"
fruits_list = csv_data.split(',')
print(f"Split CSV data: {fruits_list}") # Output: Split CSV data: ['apple', 'banana', 'cherry']
# .join(iterable): Joins elements of an iterable (e.g., list of strings) with the string itself as a
separator
joined_string = "-".join(["A", "B", "C"])
print(f"Joined string: {joined_string}") # Output: Joined string: A-B-C
28. List Methods
Explanation
Lists, being mutable objects, have a set of methods that allow you to modify their content
directly (in-place) or retrieve information about them. These methods are typically called on a list
object using dot notation.
Syntax
Python
my_list.method_name(arguments_if_any)
Code Example
Python
numbers = [4, 1, 3, 2, 1, 5]
print(f"Original list: {numbers}")
This section continues to explore more list methods, particularly those that are often used for
common list manipulations and queries. While some of these were touched upon in the previous
section or "Manipulating Lists", emphasizing them separately helps reinforce their specific use
cases.
Syntax
Python
my_list.method_name(arguments_if_any)
Code Example
Python
# Re-initializing for fresh examples
elements = ['x', 'b', 'c', 'a', 'b', 'd']
print(f"Initial list: {elements}")
# But for nested lists, changes still affect both (shallow copy behavior)
copied_list[1].append(6)
print(f"Original after copied_list nested append: {original_list}") # [1, [2, 3, 6], 4]
print(f"Copied after nested append: {copied_list}") # [1, [2, 3, 6], 4, 5]
count_of_5 = my_numbers.count(5)
print(f"Count of '5': {count_of_5}") # Output: Count of '5': 0
30. Packages
Explanation
In Python, a package is a way of organizing related modules (Python files) into a directory
hierarchy. It's essentially a folder containing Python scripts and possibly sub-folders (sub-
packages). Packages are used to modularize code, making it easier to manage, reuse, and
distribute larger applications. The Python Standard Library itself is organized into packages, and
many external functionalities are provided as third-party packages.
Syntax
(No direct code to "create" a package here, but an example of importing a standard one)
Python
# To use mathematical functions beyond basic arithmetic,
# you can import the 'math' package from the Python Standard Library.
square_root_of_16 = math.sqrt(16)
print(f"Square root of 16: {square_root_of_16}") # Output: Square root of 16: 4.0
To use functions, classes, or variables defined in a module or package, you must first import
them into your current Python script. The import statement makes the contents of the
module/package available.
Syntax
Python
import package_name
Code Example
Python
# Import the random package to generate random numbers
import random
Instead of importing an entire package, you can selectively import specific functions, classes, or
variables from a module within a package. This is done using the from ... import ... syntax.
This approach avoids cluttering your namespace with the entire package's contents and allows
you to use the imported items directly without the package_name. prefix.
Syntax
Python
from package_name import specific_item1, specific_item2
Code Example
Python
# Instead of `import math`, import only `pi` and `sqrt`
from math import pi, sqrt
radius = 7
area = pi * (radius ** 2) # Use pi directly
print(f"Area of circle with radius {radius} (using direct pi): {area}")
today = date.today()
print(f"Today's date: {today}")
Python offers a few variations for importing modules and packages, each with its own use case
and implications for your code's readability and potential for naming conflicts.
Syntax
Python
import package_name
from package_name import item
import package_name as alias
from package_name import * # Avoid this!
Code Example
Python
# 1. Standard Import
import sys
print(f"Python version (standard import): {sys.version.split(' ')[0]}")
# 2. Selective Import
from os import getcwd, listdir # Import specific functions from the 'os' module
print(f"Current working directory (selective import): {getcwd()}")
# print(f"Contents of current directory: {listdir()}") # Potentially long output
NumPy (Numerical Python) is the fundamental package for scientific computing with Python. It
provides a high-performance multidimensional array object (ndarray), and tools for working
with these arrays. NumPy arrays are significantly more efficient than Python lists for numerical
operations, especially with large datasets, because they are implemented in C and Fortran. It's
the backbone for many other scientific libraries in Python (like pandas, SciPy, scikit-learn).
● Homogeneous: All elements in a NumPy array must be of the same data type.
● Vectorized operations: Operations are applied element-wise, making calculations
much faster than manual loops over Python lists.
● Fixed size: Once created, the size of a NumPy array cannot change (though you can
create new ones from existing data).
Syntax
Python
import numpy as np
Python
np.array(python_list)
Code Example
Python
import numpy as np
Creating your first NumPy array is a crucial step to leveraging NumPy's power. The most
common way to create an ndarray is by passing a Python list (or nested lists for multi-
dimensional arrays) to the np.array() function. Remember that all elements in a NumPy array
will be forced to a single, common data type.
Syntax
Python
import numpy as np
my_array = np.array(list_or_nested_list)
Code Example
Python
import numpy as np
# Create a 1D NumPy array from a simple list
heights_cm = [170, 180, 175, 190, 165]
np_heights = np.array(heights_cm)
print(f"1D NumPy array: {np_heights}")
print(f"Shape of 1D array: {np_heights.shape}") # (5,) means 5 elements, 1 dimension
print(f"Type of elements: {np_heights.dtype}") # Output: Type of elements: int64 (or int32)
This is a specific application scenario to demonstrate working with NumPy arrays. It implies
having a dataset of baseball players' heights, likely as a list, and then converting it to a NumPy
array to perform numerical operations efficiently. This example serves to provide a concrete
context for applying np.array() and subsequent numerical operations.
Syntax
Code Example
Python
import numpy as np
The "side effects" typically refer to the implicit type conversion that NumPy performs when
creating an array from mixed-type Python lists. Because NumPy arrays are homogeneous (all
elements must be of the same type), if you pass a list containing different types, NumPy will
automatically "upcast" all elements to the most general (or "largest") compatible type to avoid
data loss. For example, if an array contains integers and floats, all integers will be converted to
floats. If it contains numbers and strings, all numbers might be converted to strings.
Another "side effect" (or important characteristic) is that many NumPy operations return new
arrays, rather than modifying the original in-place, especially when dealing with arithmetic
operations.
Syntax
(No specific syntax, but understanding the behavior of np.array() and operations)
Code Example
Python
import numpy as np
Subsetting NumPy arrays allows you to select specific elements or slices of the array, similar to
Python lists but with more advanced capabilities. NumPy's subsetting is very powerful for data
manipulation and analysis.
Syntax
Code Example
Python
import numpy as np
my_array = np.array([10, 20, 30, 40, 50, 60, 70, 80, 90])
print(f"Original NumPy array: {my_array}")
fifth_element = my_array[4]
print(f"Fifth element: {fifth_element}") # Output: Fifth element: 50
last_element = my_array[-1]
print(f"Last element: {last_element}") # Output: Last element: 90
# 2. Slicing 1D arrays
slice1 = my_array[2:6] # Elements from index 2 up to (but not including) 6
print(f"Slice from index 2 to 5: {slice1}") # Output: Slice from index 2 to 5: [30 40 50 60]
A 2D NumPy array is an array of arrays, effectively representing a matrix or a table with rows
and columns. It's crucial for working with tabular data in scientific computing and data analysis.
Like 1D arrays, all elements in a 2D array must have the same data type.
Syntax
Python
import numpy as np
two_d_array = np.array([
[row1_col1, row1_col2, ...],
[row2_col1, row2_col2, ...],
# ...
])
Code Example
Python
import numpy as np
This topic specifically targets the creation of your initial 2D NumPy array, building on the general
concept of 2D arrays. It emphasizes the direct conversion of a "list of lists" (where each inner list
is a row) into a NumPy ndarray. This is a very common way to represent tabular data in
NumPy.
Syntax
Python
import numpy as np
my_2d_array = np.array([
[value_r0_c0, value_r0_c1, ...],
[value_r1_c0, value_r1_c1, ...],
# ...
])
Code Example
Python
import numpy as np
Syntax
(Creation and basic access remain the same as "Your First 2D NumPy Array")
Code Example
Python
import numpy as np
# Now you can easily perform operations on columns (e.g., convert all weights to kg)
# 1 lb = 0.453592 kg
np_baseball_kg = np_baseball[:, 1] * 0.453592 # Select all rows, only the second column
(weight)
print(f"\nWeights in kg: {np_baseball_kg}")
# Output: Weights in kg: [ 81.64656 97.52228 95.25432 79.3786 90.7184 ]
# Or convert all heights to meters
# 1 inch = 0.0254 meters
np_baseball_m = np_baseball[:, 0] * 0.0254
print(f"Heights in meters: {np_baseball_m}")
Subsetting 2D NumPy arrays requires specifying indices for both rows and columns. You can
select single elements, entire rows/columns, or rectangular slices. This is done by providing
comma-separated indices/slices within the square brackets.
Syntax
Python
my_2d_array[row_index, column_index] # Single element
my_2d_array[row_index, :] # Entire row
my_2d_array[:, column_index] # Entire column
my_2d_array[row_start:row_end, col_start:col_end] # Rectangular slice
You can also use boolean indexing for rows or columns, or a combination.
Code Example
Python
import numpy as np
43. 2D Arithmetic
Explanation
NumPy's power truly shines with 2D arithmetic. Just like 1D arrays, operations on 2D arrays are
element-wise by default. This means that if you add two 2D arrays, the corresponding elements
are added together. If you multiply a 2D array by a scalar, every element in the array is
multiplied by that scalar. This vectorized approach is significantly faster than using nested loops
with Python lists.
Syntax
Python
# Assuming two_d_array_A and two_d_array_B are 2D NumPy arrays of compatible shapes
result_array = two_d_array_A + two_d_array_B
result_array = two_d_array_A * scalar_value
result_array = two_d_array_A / two_d_array_B # Element-wise division
Code Example
Python
import numpy as np
exam_scores_term2 = np.array([
[75, 82],
[80, 95]
])
print(f"Term 1 Scores:\n{exam_scores_term1}")
print(f"\nTerm 2 Scores:\n{exam_scores_term2}")
# 1. Element-wise addition: Total score for each subject per student
total_scores = exam_scores_term1 + exam_scores_term2
print(f"\nTotal Scores (Term1 + Term2):\n{total_scores}")
# Output:
# Total Scores (Term1 + Term2):
# [[145 162]
# [165 185]]
Syntax
Python
np.mean(array)
np.median(array)
np.std(array)
np.sum(array)
np.min(array)
np.max(array)
Code Example
Python
import numpy as np
min_score = np.min(scores)
max_score = np.max(scores)
print(f"Minimum score: {min_score}") # Output: Minimum score: 70
print(f"Maximum score: {max_score}") # Output: Maximum score: 95
When analyzing data, both the average (mean) and the median are measures of central
tendency, but they provide different insights, especially when dealing with skewed data or
outliers.
● Average (Mean): Calculated by summing all values and dividing by the count of values.
It is sensitive to extreme values (outliers).
● Median: The middle value in a dataset when the values are ordered from least to
greatest. If there's an even number of values, it's the average of the two middle values.
The median is robust to outliers, meaning it's less affected by extremely high or low
values.
Choosing between mean and median depends on the nature of your data and what you want to
represent. For example, income data is often skewed by a few very high earners, making the
median a more representative measure of typical income.
Syntax
Python
np.mean(array)
np.median(array)
Code Example
Python
import numpy as np
This is a continuation of the "Baseball data in 2D form" topic, focusing on applying the statistical
functions you just learned (mean, median, etc.) to a real-world dataset. The goal is to extract
meaningful insights from the data, such as average height, median weight, or the standard
deviation of certain measurements.
Syntax
(Application of np.mean(), np.median(), np.std() on specific columns of a 2D NumPy array)
Code Example
Python
import numpy as np
Comparison operators (also known as relational operators) are used to compare two values.
They evaluate to a Boolean value (True or False) based on whether the comparison is true or
false. These operators are fundamental for creating conditional statements and for filtering data.
Syntax
● ==: Equal to
● !=: Not equal to
● >: Greater than
● <: Less than
● >=: Greater than or equal to
● <=: Less than or equal to
Code Example
Python
# Variables for comparison
a = 10
b = 20
c = 10
text1 = "Python"
text2 = "python"
# Equality (==)
print(f"Is a equal to b? {a == b}") # Output: False
print(f"Is a equal to c? {a == c}") # Output: True
print(f"Is text1 equal to text2? {text1 == text2}") # Output: False (case-sensitive)
48. Equality
Explanation
The equality operator == checks if two values are the same. It returns True if they are equal
and False otherwise. It's important to distinguish == (comparison) from = (assignment).
Python is case-sensitive for string comparisons.
Syntax
Python
value1 == value2
Code Example
Python
num1 = 100
num2 = 100
num3 = 200
string1 = "hello"
string2 = "hello"
string3 = "Hello"
list1 = [1, 2, 3]
list2 = [1, 2, 3]
list3 = [3, 2, 1]
# Comparing numbers
print(f"Is num1 == num2? {num1 == num2}") # Output: True
print(f"Is num1 == num3? {num1 == num3}") # Output: False
# Comparing different types (usually False, but Python tries to convert sometimes)
print(f"Is 10 == 10.0? {10 == 10.0}") # Output: True (Python converts int to float for comparison)
print(f"Is '10' == 10? {'10' == 10}") # Output: False (no automatic conversion for string vs int)
The > (greater than) and < (less than) operators are used to determine the relative order of two
values. They are fundamental for sorting, filtering, and controlling program flow. They return
True if the condition is met, and False otherwise.
Syntax
Python
value1 > value2
value1 < value2
Similar syntax applies to >= (greater than or equal to) and <= (less than or equal to).
Code Example
Python
temp_celsius = 25
temp_fahrenheit = 77
# Greater than (>)
print(f"Is {temp_celsius}C > 20C? {temp_celsius > 20}") # Output: True
print(f"Is {temp_fahrenheit}F > 80F? {temp_fahrenheit > 80}") # Output: False
NumPy allows you to apply comparison operators directly to arrays. When you compare two
NumPy arrays (or an array and a scalar), the comparison is performed element-wise. The
result is a new NumPy array of boolean values, where each element is True or False
depending on the result of the comparison for the corresponding elements. This is incredibly
powerful for filtering and selecting data.
Syntax
Python
np_array1 == np_array2
np_array > scalar_value
np_array_A <= np_array_B
Shapes must be compatible for element-wise comparison.
Code Example
Python
import numpy as np
# 1D arrays
heights = np.array([170, 180, 175, 190, 165])
threshold_height = 175
# 2D arrays
scores1 = np.array([
[85, 90],
[70, 75]
])
scores2 = np.array([
[80, 92],
[70, 70]
])
print(f"\nScores 1:\n{scores1}")
print(f"Scores 2:\n{scores2}")
Boolean operators (and, or, not) are used to combine or modify boolean expressions
(True/False values). They are crucial for building complex conditions in if statements, loops,
and data filtering, allowing you to check for multiple criteria simultaneously.
Syntax
Code Example
Python
is_sunny = True
is_warm = False
has_hat = True
# 1. 'and' operator
# Both conditions must be True
print(f"Is it sunny AND warm? {is_sunny and is_warm}") # Output: False
print(f"Is it sunny AND I have a hat? {is_sunny and has_hat}") # Output: True
# 2. 'or' operator
# At least one condition must be True
print(f"Is it sunny OR warm? {is_sunny or is_warm}") # Output: True
print(f"Is it warm OR I have a hat? {is_warm or has_hat}") # Output: True
print(f"Is it warm OR I don't have a hat? {is_warm or not has_hat}") # Output: False (False or
False is False)
# 3. 'not' operator
# Inverts the boolean value
print(f"Is it NOT warm? {not is_warm}") # Output: True
print(f"Is it NOT sunny? {not is_sunny}") # Output: False
# Combining operators
# Example: If it's sunny AND (warm OR I have a hat)
complex_condition = is_sunny and (is_warm or has_hat)
print(f"Complex condition (sunny AND (warm OR hat)): {complex_condition}") # Output: True
(True and (False or True) -> True and True -> True)
This topic specifically re-emphasizes the core usage of the logical operators and, or, and not
with simple boolean values or expressions. Understanding their truth tables is key:
Syntax
Python
expression1 and expression2
expression1 or expression2
not expression
Code Example
Python
# Simple boolean variables
bool_a = True
bool_b = False
bool_c = True
# Using 'and'
print(f"True and True: {bool_a and bool_c}") # Output: True
print(f"True and False: {bool_a and bool_b}") # Output: False
print(f"False and False: {bool_b and bool_b}") # Output: False
# Using 'or'
print(f"True or True: {bool_a or bool_c}") # Output: True
print(f"True or False: {bool_a or bool_b}") # Output: True
print(f"False or False: {bool_b or bool_b}") # Output: False
# Using 'not'
print(f"not True: {not bool_a}") # Output: False
print(f"not False: {not bool_b}") # Output: True
This continuation delves slightly deeper into the behavior of and and or beyond just returning
True/False. Python's and and or operators use short-circuit evaluation:
● and: If the first operand is False, it immediately returns the first operand without
evaluating the second. Otherwise, it returns the second operand.
● or: If the first operand is True, it immediately returns the first operand without evaluating
the second. Otherwise, it returns the second operand.
This behavior is important for efficiency and sometimes for control flow, especially when the
second operand might involve a costly computation or a potential error. Also, Python considers
certain "falsy" values (like 0, None, "", [], {}) as False in a boolean context, and "truthy"
values as True.
Syntax
Code Example
Python
# Short-circuiting with 'and'
print(f"False and (1 / 0): {False and (1 / 0)}")
# Output: False (1/0 is not evaluated because False is already determined)
# print(f"True and (1 / 0): {True and (1 / 0)}") # This would cause a ZeroDivisionError
# Output: ZeroDivisionError: division by zero (because True is evaluated, then it tries to
evaluate 1/0)
When performing boolean operations (and, or, not) directly on NumPy arrays, you cannot use
the Python keywords and, or, not. These keywords operate on single boolean values. For
element-wise boolean operations on NumPy arrays, you must use the bitwise logical
operators:
These operators return a new boolean NumPy array where the operation has been applied to
each corresponding element. They are crucial for complex filtering conditions on numerical data.
Syntax
Python
(condition_array_1) & (condition_array_2) # Element-wise AND
(condition_array_1) | (condition_array_2) # Element-wise OR
~(condition_array) # Element-wise NOT
Important: Always use parentheses around individual comparison expressions when combining
them with & or | because of operator precedence.
Code Example
Python
import numpy as np
# 2. Element-wise OR (`|`)
# People who are younger than 18 OR older than 35
extreme_ages = (ages < 18) | (ages > 35)
print(f"Extreme ages (age < 18 OR age > 35): {extreme_ages}")
# Output: Extreme ages (age < 18 OR age > 35): [ True False False False True False True]
print(f"Ages with extreme values: {ages[extreme_ages]}") # Output: Ages with extreme values:
[15 17 40]
if, elif (else if), and else statements are control flow constructs that allow your program to
execute different blocks of code based on certain conditions. This enables your programs to
make decisions and respond dynamically to varying inputs or states.
● if: The basic conditional statement. If its condition is True, the code block inside the if
statement is executed.
● elif: Short for "else if." It's used to check additional conditions if the preceding if or elif
conditions were False. You can have multiple elif blocks.
● else: An optional block that executes if none of the preceding if or elif conditions were
True. It serves as a default path.
Syntax
Python
if condition1:
# Code to execute if condition1 is True
elif condition2:
# Code to execute if condition1 is False AND condition2 is True
else:
# Code to execute if all preceding conditions are False
Code Example
Python
temperature = 28
time_of_day = "morning"
# 2. `if-else` statement
if time_of_day == "morning":
print("Good morning!") # Output: Good morning!
else:
print("Hello!")
# 3. `if-elif-else` chain
score = 85
This is a gentle introduction or practice scenario before diving deep into if, elif, else. The idea
is to present a simple problem that can be solved using basic conditional logic. It helps solidify
the understanding of comparison operators and basic if statements.
Syntax
Code Example
Python
# Warmup Scenario: Check if a number is positive.
number = 10
if number > 0:
print("The number is positive.") # Output: The number is positive.
number = -5
if number > 0:
print("The number is positive.") # This line won't be printed
short_password = "short"
if len(short_password) >= min_length:
print("Password meets minimum length requirement.") # This line won't be printed
57. if
Explanation
The if statement is the most basic form of conditional execution. It allows you to execute a block
of code only if a specified condition evaluates to True. If the condition is False, the code block
associated with the if statement is simply skipped, and the program continues with the code
after the if block.
Syntax
Python
if condition:
# This code block executes if 'condition' is True
statement1
statement2
# ...
The condition can be any expression that evaluates to a boolean (True or False) value.
Code Example
Python
# Scenario: Check if it's raining to decide if you need an umbrella.
is_raining = True
if is_raining:
print("Don't forget your umbrella!") # Output: Don't forget your umbrella!
print("It's wet outside.")
if is_raining:
print("Don't forget your umbrella!") # This won't print
print("It's wet outside.")
The else statement provides an alternative path of execution when the condition in the
preceding if statement (or if-elif chain) evaluates to False. It ensures that one of the code
blocks will always be executed: either the if block (if the condition is True) or the else block (if
the condition is False).
Syntax
Python
if condition:
# Code to execute if condition is True
else:
# Code to execute if condition is False
Code Example
Python
# Scenario: Check if a number is even or odd.
number = 7
number = 12
if number % 2 == 0:
print(f"{number} is an even number.") # Output: 12 is an even number.
else:
print(f"{number} is an odd number.")
if stock_count > 0:
print("Item is in stock. You can purchase.")
else:
print("Item is out of stock.") # Output: Item is out of stock.
if is_logged_in:
print("Access granted to user profile.")
else:
print("Please log in to continue.") # Output: Please log in to continue.
Syntax
Python
if first_condition:
# Code for first_condition True
elif second_condition:
# Code for first_condition False AND second_condition True
elif third_condition:
# Code for first_condition False AND second_condition False AND third_condition True
else:
# Code if none of the above conditions are True
Code Example
Python
# Scenario: Assign a grade based on a score.
score = 75
if light_color == "green":
print("Go!")
elif light_color == "yellow":
print("Prepare to stop.") # Output: Prepare to stop.
elif light_color == "red":
print("Stop!")
else:
print("Invalid light color.")
This topic introduces how to filter data in pandas DataFrames, a core skill in data analysis.
pandas is a powerful library built on NumPy, providing data structures like DataFrames, which
are tabular (like spreadsheets or SQL tables). Filtering a DataFrame involves selecting rows (or
sometimes columns) that meet specific criteria. This is typically done using boolean indexing.
Syntax
Python
import pandas as pd
# Filtering syntax:
filtered_df = df[df['column_name'] == value]
filtered_df = df[(df['column1'] > threshold) & (df['column2'] == 'category')]
The df[...] syntax with a boolean Series inside acts as a row selector.
Code Example
Python
import pandas as pd
import numpy as np # Often used with pandas
# Create a sample DataFrame for demonstration
data = {
'Name': ['Alice', 'Bob', 'Charlie', 'David', 'Eve'],
'Age': [25, 30, 22, 35, 28],
'City': ['New York', 'London', 'New York', 'Paris', 'London'],
'Score': [85, 92, 78, 95, 88]
}
df = pd.DataFrame(data)
print(f"Original DataFrame:\n{df}\n")
This is likely a conceptual example to illustrate boolean filtering on a specific dataset related to
driving behavior or car statistics. It primes the user for applying the pandas filtering techniques
to a practical scenario. Imagine a DataFrame with columns like 'speed' or 'driving_side'.
Syntax
Code Example
Python
import pandas as pd
# Scenario: Filter for countries where people drive on the right side of the road.
# This directly translates to checking if 'drives_right' column is True.
# Direct filtering
left_hand_driving_countries = cars[cars['drives_right'] == False]
print(f"Countries that drive on the left:\n{left_hand_driving_countries}\n")
This topic continues the "Driving right" scenario, potentially adding more complexity to the
filtering, such as combining conditions or selecting specific columns after filtering. It's about
refining your data selection based on multiple criteria from the same dataset.
Syntax
Code Example
Python
import pandas as pd
# Scenario: Filter for countries where people drive on the right AND have a high number of cars
per capita (e.g., > 600).
# Let's adjust the data slightly or the condition to make a better point if desired.
# For example, if Japan had 601 cars per capita:
cars_adjusted = pd.DataFrame({
'country': ['United States', 'Canada', 'United Kingdom', 'Australia', 'Japan', 'India'],
'drives_right': [True, False, False, False, True, False],
'num_cars_per_capita': [800, 700, 500, 650, 601, 200]
})
# Now, condition_high_cars for adjusted data: cars_adjusted['num_cars_per_capita'] > 600
# Japan would be included.
# Alternative: Filter for countries that drive on the left OR have less than 500 cars per capita
condition_left_drive = cars['drives_right'] == False
condition_low_cars = cars['num_cars_per_capita'] < 500
This is another specific scenario, often used to demonstrate filtering on numerical columns in a
pandas DataFrame. "Cars per capita" is a continuous numerical variable, and you'd typically
filter it using comparison operators (>, <, >=, <=).
Syntax
Code Example
Python
import pandas as pd
# Scenario: Identify countries with more than 500 cars per capita.
# Find countries with very low cars per capita (e.g., less than 100)
low_car_countries = cars_data[cars_data['cars_per_capita'] < 100]
print(f"Countries with < 100 cars per capita:\n{low_car_countries}\n")
This topic extends the "Cars per capita" scenario, likely by adding more complex filtering logic
involving multiple conditions or by selecting specific columns from the filtered DataFrame. It
reinforces the idea of combining boolean conditions to refine data selection.
Syntax
(Combining boolean conditions on DataFrame Series and selecting columns after filtering)
Code Example
Python
import pandas as pd
# Scenario: Find countries in Asia with less than 200 cars per capita.
# Scenario: Find countries in North America OR with more than 700 cars per capita.
condition_north_america = cars_data['continent'] == 'North America'
condition_very_high_cars = cars_data['cars_per_capita'] > 700
north_america_or_very_high_cars = cars_data[condition_north_america |
condition_very_high_cars]
print(f"Countries in North America OR with > 700 cars per capita:\
n{north_america_or_very_high_cars}\n")
# Output:
# country cars_per_capita continent
# 0 United States 800 North America
#1 Canada 750 North America
#2 Germany 650 Europe (Germany was caught by >700, even though it's not
North America)
A while loop repeatedly executes a block of code as long as a specified condition remains
True. The loop continues until the condition becomes False or a break statement is
encountered. It's often used when the number of iterations is not known beforehand.
Syntax
Python
while condition:
# Code to execute as long as 'condition' is True
# Make sure something inside the loop changes the condition
# to eventually become False to avoid an infinite loop!
Code Example
Python
# Scenario: Count down from 5
count = 5
print("Countdown:")
while count > 0:
print(count)
count -= 1 # Decrement count by 1 (shorthand for count = count - 1)
print("Blast off!")
# Output:
# Countdown:
#5
#4
#3
#2
#1
# Blast off!
print("\nAccumulating sum:")
while current_sum < target_sum:
print(f"Adding {num} to {current_sum}")
current_sum += num
num += 1
print(f"Final sum: {current_sum}")
# Output:
# Accumulating sum:
# Adding 1 to 0
# Adding 2 to 1
# Adding 3 to 3
# Adding 4 to 6
# Final sum: 10 (Loop stopped when sum became 10, which is not less than 10)
This is a simple introductory example to get comfortable with the while loop structure. It
typically involves a very basic condition and a clear way to change the condition to eventually
terminate the loop, preventing an infinite loop.
Syntax
Code Example
Python
# Warmup Scenario: Print numbers from 1 to 3.
num = 1
print("Counting to 3:")
while num <= 3:
print(num)
num += 1 # Increment num by 1
print("Done counting.")
# Output:
# Counting to 3:
#1
#2
#3
# Done counting.
The basic while loop consists of the while keyword, a condition, and a colon, followed by an
indented block of code. The loop repeatedly checks the condition before each iteration. If the
condition is True, the block is executed. If False, the loop terminates. It's crucial to ensure that
the loop's body modifies one or more variables involved in the condition, otherwise, it will run
forever (an "infinite loop").
Syntax
Python
while condition_that_becomes_false:
# Code block
# Modify variables affecting 'condition_that_becomes_false'
Code Example
Python
# Scenario: Keep asking for user input until a valid number is entered.
user_input = ""
is_valid_number = False
You can embed if, elif, else statements inside a while loop to add more sophisticated
decision-making logic within each iteration. This allows the loop to perform different actions or
react differently based on conditions that change during the loop's execution, leading to more
dynamic and powerful programs.
Syntax
Python
while loop_condition:
# Code inside the loop
if inner_condition1:
# Do something specific
elif inner_condition2:
# Do something else
else:
# Default action
Code Example
Python
# Scenario: Process a list of tasks, with special handling for certain tasks.
tasks = ["upload data", "clean data", "analyze data", "export report"]
processed_tasks = []
task_index = 0
print("Processing tasks:")
while task_index < len(tasks):
current_task = tasks[task_index]
if "clean" in current_task:
print(f"Special handling for: '{current_task}' - Applying data cleaning algorithm...")
elif "upload" in current_task:
print(f"Starting upload for: '{current_task}' - Checking network connection...")
else:
print(f"Processing regular task: '{current_task}'")
processed_tasks.append(current_task)
task_index += 1 # Move to the next task
# Scenario: A game loop where player health decreases and game ends when health is zero.
player_health = 100
enemy_attacks = [10, 5, 20, 15, 30]
attack_num = 0
print("\nGame started!")
while player_health > 0 and attack_num < len(enemy_attacks):
damage = enemy_attacks[attack_num]
player_health -= damage
print(f"Enemy attacks for {damage} damage. Player health: {player_health}")
if player_health <= 0:
print("Player defeated! Game Over.")
elif player_health < 30:
print("Warning: Low health! Find health pack!")
attack_num += 1
if player_health > 0:
print("All enemies defeated. Player wins!")
A for loop is used for iterating over a sequence (like a list, tuple, string, or range) or other
iterable objects. It executes a block of code once for each item in the sequence. for loops are
ideal when you know the number of iterations or when you need to process each item in a
collection.
Syntax
Python
for item in iterable:
# Code to execute for each 'item'
The item variable takes on the value of each element in the iterable during successive
iterations.
Code Example
Python
# 1. Loop over a list of numbers
numbers = [1, 2, 3, 4, 5]
print("Numbers in the list:")
for num in numbers:
print(num)
# Output:
# Numbers in the list:
#1
#2
#3
#4
#5
This is the most common use case for a for loop. You iterate through each element of a list,
performing some operation with each element. This is ideal for processing collections of data
where the order of elements matters.
Syntax
Python
for element_variable in my_list:
# Perform operations using element_variable
Code Example
Python
# A list of fruits
fruits = ["apple", "banana", "cherry", "date"]
# Apply a discount
discounted_prices = []
for price in prices:
discounted_price = price * 0.9 # 10% discount
discounted_prices.append(discounted_price)
Often, when looping over a list, you need both the value of the element and its index (its
position). Python's enumerate() function is perfect for this. It returns pairs of (index, value)
for each item in the iterable, allowing you to access both simultaneously in your loop.
Syntax
Python
for index, value in enumerate(my_list):
# Use index and value in the loop body
Code Example
Python
# List of tasks
tasks = ["Review report", "Schedule meeting", "Prepare presentation", "Send follow-up"]
print("\nFinding 'eggs':")
for i, item in enumerate(items):
if item == item_to_find:
print(f"'{item_to_find}' found at index {i}.") # Output: 'eggs' found at index 2.
break # Exit loop once found (optional)
This continues the concept of accessing both indexes and values, perhaps with more complex
scenarios or demonstrating alternative (though less Pythonic) ways to achieve the same result
as enumerate(). It might also involve conditional logic based on both index and value.
Syntax
Code Example
Python
# Scenario: Update elements based on their index.
numbers = [10, 20, 30, 40, 50]
# Alternative (less Pythonic) way to get index and value (discouraged in most cases)
print("\nManual index tracking:")
for i in range(len(numbers)):
print(f"Index {i}: Value {numbers[i]}")
# Output:
# Manual index tracking:
# Index 0: Value 15
# Index 1: Value 20
# Index 2: Value 35
# Index 3: Value 40
# Index 4: Value 55
# Scenario: Print elements and their indices, but only for elements meeting a condition
cities = ["London", "Paris", "Rome", "Berlin", "Madrid"]
print("\nCities that start with 'R':")
for index, city in enumerate(cities):
if city.startswith('R'):
print(f"Index {index}: {city}") # Output: Index 2: Rome
When you have a nested list (a list where elements are themselves lists), you can use nested
for loops to iterate through both the outer lists (rows) and the inner lists (elements within each
row). This is common for processing tabular data represented as lists of lists.
Syntax
Python
for outer_item in list_of_lists:
for inner_item in outer_item:
# Process inner_item
Python
for row in list_of_lists:
for col_val in row:
# Process col_val
Code Example
Python
# Student scores: [Name, Math, Science]
student_data = [
["Alice", 85, 90],
["Bob", 78, 82],
["Charlie", 92, 88]
]
This topic generalizes looping to other fundamental Python data structures beyond lists. It
focuses on dictionaries and NumPy arrays, demonstrating how for loops adapt to their specific
structures.
Syntax
Code Example
Dictionaries are unordered collections of key-value pairs. When you loop directly over a
dictionary using a for loop, it iterates over its keys by default. However, you can use dictionary
methods (.keys(), .values(), .items()) to iterate explicitly over keys, values, or both.
Syntax
Python
# Iterating over keys (default)
for key in my_dictionary:
# Use key: my_dictionary[key]
# Iterating over values
for value in my_dictionary.values():
# Use value
Code Example
Python
# A dictionary of product prices
product_prices = {
"Laptop": 1200,
"Mouse": 25,
"Keyboard": 75,
"Monitor": 300
}
While loops are possible, for iterating through elements, NumPy's vectorized operations are
almost always more efficient than Python for loops.
Syntax
Python
for element in 1d_numpy_array:
# Process element
Code Example
Python
import numpy as np
# Important: Prefer vectorized operations over loops for efficiency with NumPy!
# Example: Adding 10 to all elements in data_1d
data_1d_plus_10 = data_1d + 10 # This is much faster than a loop
print(f"\nVectorized addition: {data_1d_plus_10}")
Syntax
Code Example
Iterating over a pandas DataFrame row by row is a common task. The DataFrame.iterrows()
method is the standard and most explicit way to do this. For each iteration, iterrows() yields a
tuple containing the index of the row and the row itself as a Series object.
While direct iteration with for loops is possible, it's generally discouraged for large DataFrames
due to performance reasons. Vectorized operations (NumPy or pandas built-in functions) are
almost always faster. However, iterrows() is useful when you need to access both the index
and the data of each row, or when row-by-row logic is unavoidable.
Syntax
Python
import pandas as pd
for index, row in df.iterrows():
# 'index' is the row index (e.g., 0, 1, 2...)
# 'row' is a pandas Series representing the current row
# You can access elements of the row using row['column_name']
Code Example
Python
import pandas as pd
# Create a sample DataFrame
data = {
'Name': ['Alice', 'Bob', 'Charlie'],
'Age': [25, 30, 22],
'City': ['New York', 'London', 'Paris']
}
df = pd.DataFrame(data)
print(f"Original DataFrame:\n{df}\n")
Syntax
Code Example
Python
import pandas as pd
# Scenario: Calculate total value for each sale and apply a regional discount.
# Add a new 'Total Value' column
df_sales['Total Value'] = 0.0 # Initialize column
Syntax
Python
df['new_column_name'] = value_or_series
If value_or_series is a single value, it will be broadcasted to all rows. If it's a Series or array, its
length must match the DataFrame's number of rows.
Code Example
Python
import pandas as pd
This topic further explores adding columns, possibly demonstrating more complex logic for
column creation, such as using conditional statements to derive values for the new column (e.g.,
categorizing data), or using the .apply() method for more intricate row-wise or element-wise
transformations when vectorized solutions are not straightforward.
Syntax
● Using .apply(): df['new_col'] = df.apply(function_name, axis=1) (for row-wise)
● Using np.where() for conditional column creation: df['new_col'] =
np.where(condition, value_if_true, value_if_false)
Code Example
Python
import pandas as pd
import numpy as np # Often used with conditional logic for DataFrames
# 1. Add a new column based on a condition using np.where() (highly recommended for
element-wise conditionals)
# If Average_Score >= 80, 'Excellent', else 'Good'
students_df['Performance_Level'] = np.where(students_df['Average_Score'] >= 85, 'Excellent',
'Good')
print(f"After adding 'Performance_Level' with np.where():\n{students_df}\n")
# Output:
# Name Math_Score Science_Score Average_Score Performance_Level
# 0 Alice 85 90 87.5 Excellent
#1 Bob 78 82 80.0 Good
# 2 Charlie 92 88 90.0 Excellent
# 3 David 65 70 67.5 Good
#4 Eve 88 91 89.5 Excellent
# Using apply with axis=1 for row-wise logic (e.g., combine name and city)
def create_summary(row):
return f"{row['Name']} ({row['City']})"
# Assuming 'City' column exists from an earlier example, let's add it for this demo:
students_df['City'] = ['New York', 'London', 'Paris', 'New York', 'London']
students_df['Summary'] = students_df.apply(create_summary, axis=1)
print(f"After adding 'Summary' column using .apply(axis=1):\n{students_df}\n")
# Output:
# Name Math_Score Science_Score Average_Score Performance_Level Grade City
Summary
# 0 Alice 85 90 87.5 Excellent B New York Alice (New York)
#1 Bob 78 82 80.0 Good B London Bob (London)
# 2 Charlie 92 88 90.0 Excellent A Paris Charlie (Paris)
# 3 David 65 70 67.5 Good F New York David (New York)
#4 Eve 88 91 89.5 Excellent B Lon