1/87
Looks like no tags are added yet.
Name | Mastery | Learn | Test | Matching | Spaced |
---|
No study sessions yet.
Algorithm
A step-by-step procedure or formula for solving a problem or completing a task in programming and computer science.
Program
A collection of instructions written in a programming language that executes a specific task or solves a problem.
Input + Output
Input is data given to a program for processing.
Output is data that is displayed on the screen or that is sent to a file / other device.
Conditional Execution
Check for certain conditions and execute the appropriate sequence of statements.
Value
A data element that a program processes, storing a specific item of information, which can be passed to functions and is used in computations.
Data Types
Categories of data that determine the kind of operations that can be performed on them, such as integers, floats, or strings.
Integer — Whole numbers, positive or negative, without fractions.
Float — Numbers that contain decimal points.
String — A sequence of characters used to represent text.
Function — ‘type’
A classification that defines the nature of a function's return value, such as integer, float, or string.
Code — type()
Function — Type Conversion Functions
Functions that convert one data type to another, enabling operations across different data types in programming.
Code — int(), float(), str()
Variable
A named storage location in a program that can hold a value and allows programmers to reference or modify that value during execution.
When reading or writing code, say to yourself “n is assigned 17” or “n gets the value 17” or “n is a reference to the object 17” or “n refers to the object 17”. Don’t say “n equals 17”.
A variable is an abstract concept that enables data storage and retrieval. It can change throughout program execution, representing values that the program manipulates.
Variable names can contain both letters and digits, but they have to begin with a letter or an underscore. Although it is legal to use uppercase letters, by convention we don’t. If you do, remember that case matters. Bruce and bruce are different variables.
Variables are assigned to values with the assignment token, ‘=’.
Statement
An instruction that the Python interpreter can execute. Statements do not return a value.
Expression
A combination of values, variables, operators, and calls to functions.
Expressions need to be evaluated. If you ask Python to print an expression, the interpreter evaluates the expression and displays the result.
Operators and Operands
Operators are special tokens that represent computations.
Operands are the values the operator works on.
+, -, and * all mean the same in mathematics.
** is the token for exponentialism.
// is integer division.
% is the modulus operator.
// (integer division)
A division operation that returns the quotient without any remainder, discarding the fractional part of the result.
% (modulus operator)
A mathematical operator that returns the remainder of the division of one number by another.
Order of Operations
Reassignment of Variables
The process of updating the value stored in a variable after it has been initially assigned, allowing for dynamic changes in a program's execution.
Updating Variables
The act of changing the value of a variable during program execution, enabling programs to adapt to new data or conditions.
Operations on Strings
You cannot perform mathematical operations on strings, even if the strings look like numbers.
The ‘+’ operator does work with strings, but it represents concatenation, not addition.
The * operator also works, and performs repetition.
Operator Precedence (Order of Operations):
* (repetition) happens before + (concatenation), just like in math.
Use parentheses to force concatenation first.
Concatenation (Strings)
The operation of joining two or more strings together to form a single string, typically using the '+' operator in many programming languages. The two strings are linked end-to-end.
Repetition (Strings)
The operation of repeating a string multiple times, often using the '*' operator in programming languages. This results in a new string composed of the original string concatenated with itself the specified number of times.
One of the operands has to be a string and the other has to be an integer.
Function
A named sequence of statements that belong together.
The syntax for a function definition is:
def name(parameters):
statements
def → keyword that starts a function definition
name → function’s name
parameters → placeholders for information the function needs
The parameter list may be empty, or it may contain any number of parameters separated from one another by commas.
statements → the code that runs when the function is called
Compound Statements
A group of statements that can be executed as a single unit, typically using control structures like loops or conditionals in programming. They allow for structured programming by combining multiple actions into one block.
Parameters vs. Arguments
Parameters → Formal parameters, names used inside the function definition.
Arguments → Actual parameters, the real values you pass when you call the function.
Defining vs. Calling
Defining → Stores it for later.
Calling → Actually runs the function.
if name == "__main__":
This line checks if the Python file is being run directly and not imported as a module, allowing for the execution of code within that block.
A Python convention.
Code under it must also be intended.
Think of it as: this tells Python where the main program starts.
Function — ‘max’
Can be sent any number of arguments, separated by commas, and will return the maximum value sent.
Code — max()
Fruitful Functions
Functions that return a value after execution, allowing the result to be used later in the program.
Takes in input (arguments), does some work inside, then hands back a result.
A non-fruitful function (sometimes called a procedure) just does something (like printing text) but does not give back a result.
Use “return” to send data back.
Local Variables
Variables defined within a function that are accessible only within that function's scope. They lose their value once the function execution is complete.
Global Variables
Variables that are defined outside of any function, accessible throughout the entire program.
Shadowing → If a local variable has the same name as a global, the local “shadows” the global. This means inside the function, Python will always use the local.
The global variable cannot be accessed by Python because the local variable will be found first.
Parameters Reassigned Inside a Function:
Even if you reassign a parameter inside the function, it only affects the local version. The global variable you passed in does not change.
Reasons to Avoid Globals:
Using globals makes code confusing.
Functions become dependent on outside state.
Always pass values as parameters instead of relying on globals.
Return Statements
Used to send a value back to the caller of a function. It allows a function to output a result which can be stored and used later.
The return statement not only causes the function to return a value, but it also returns the flow of control back to the place in the program where the function call was made.
The call to a function terminates after the execution of a return statement.
All Python functions return the value “None” unless there is an explicit return statement with a value other than “None”.
If you use “print”, that value will not be returned to the place where the call was made.
Flow of Execution
The order in which statements are executed in a program, typically controlled by function calls, conditionals, and loops. Understanding flow of execution is crucial for predicting and debugging program behavior.
Function definitions do not alter the flow of execution of the program, but statements inside the function are not executed until the function is called.
When we get to the end of the program, it terminates.
You will read the “def” statements as you are scanning, but you should skip the body of the function until you reach a point where the function is called.
When inside a function, you might call another function.
Follow the flow of calls, not just top-to-bottom text.
Composition
A method of combining simple functions or structures to create a more complex function or structure. It allows for building complex behavior by composing smaller, reusable components.
Calling one function from inside another function.
It is a way to build bigger functions out of smaller ones. Makes code reusable.
Example is using “distance” + “area” to create “area2”.
The Random Module
A Python library that implements pseudo-random number generators for various distributions, enabling users to generate random numbers and choices. It provides functions such as random()
, randint()
, and choice()
.
Random number generators are based on a deterministic algorithm – repeatable and predictable. So, they’re called pseudo-random generators. They are not genuinely random, as they start with a seed value.
Each time you ask for another random number, you’ll get one based on the current seed attribute, and the state of the seed (which is one of the attributes of the generator) will be updated.
You must include “import random” to access the random module.
Function — random.random()
Returns a floating-point number in the range [0.0, 1.0).
[ ] → inclusive (0.0 is possible)
( ) → exclusive (1.0 is not possible)
The numbers are uniformly distributed (all equally likely).
You can scale the result by multiplying (e.g., print(random.random() * 5) gives numbers in [0.0, 5.0)).
Function — random.randrange(start, stop)
Returns a random integer between “start” and “stop - 1”.
Works like range; includes the lower bound but excludes the upper bound.
All values in the range are equally likely.
Boolean Values
Values representing True or False states, often used in conditionals and logical operations in programming.
The Python type for storing true and false values is called “bool”.
There are only two boolean values. They are True and False. They are both Boolean literals.
Capitalization matters.
They are not strings, and they are not surrounded by quotes.
Boolean Expressions
Something that evaluates to True or False.
Comparison operators are the main way we form boolean expressions.
The equality operator, ==, compares two values and produces a boolean value.
This is one of six common comparison operators.
= is an assignment operator.
An equality test is symmetric, but assignment is not. For example, if a == 7 then 7 == a. But in Python, the statement a = 7 is legal and 7 = a is not.
Comparison Operators
Logical Operators
Symbols that combine boolean expressions and determine logical outcome.
or → True if at least one condition is True.
In words we might say: “number equal to 5 or 6 or 7”. However, if we translate this into Python, number == 5 or 6 or 7. You cannot take a shortcut.
and → True only if both conditions are True.
not → Reverses (negates) a boolean value.
Logical Opposites
Boolean values that are inverse to each other, where one is True if the other is False.
Precedence of Operators
Precedence → The order in which Python evaluates operators when there are no parentheses.
Arithmetic first → relational next → logical last.
Parentheses can always be used to make order explicit (and improve readability).
Conditional Execution — Binary Selection (‘if’ statement)
Selection Statements / Conditional Statements → Give the ability to check conditions and change the behavior of the program accordingly.
The simplest form of selection is the “if” statement. This is sometimes referred to as binary selection since there are two possible paths of execution.
Condition → The boolean expression after the “if” statement. If it is true, then the immediately following indented statements get executed.
The “if” statement consists of a header line and a body. The header line begins with the keyword “if” followed by a boolean expression and ends with a colon (:).
The more indented statements that follow are called a block.
There is no limit on the number of statements that can appear under the two clauses of an “if” statement, but there has to be at least one statement in each block.
Omitting the Else Clause — Unary Selection
Unary Selection (if without else) → Only need to do something if a condition is True.
If the condition is False, the program just skips the block and continues normally.
There is only one possible path of execution.
A unary selection is a type of decision-making structure where a program evaluates a condition and executes a block of code only if the condition is true. If the condition is false, the program simply skips the block and continues with the rest of the code.
Unlike a full if–else
structure, unary selection omits the else
clause, meaning no action is taken if the condition is false.
Example:
x = 10
if x > 5: # unary selection
print("x is greater than 5")
print("done")
Nested Conditionals
A nested conditional is a decision-making structure in which one conditional statement is placed inside another. This allows the program to test multiple conditions in a hierarchical or step-by-step way, where the second (inner) condition is only checked if the first (outer) condition is true.
✅ Key Points:
One if
(or if–else
) statement is placed inside the block of another.
Conditions are evaluated in sequence, giving a hierarchical flow of logic.
Useful when decisions depend on earlier conditions being true.
Can lead to deeply indented code, so clarity is important.
Chained Conditionals
A chained conditional is a decision-making structure where multiple conditions are evaluated in sequence using if
, elif
, and else
statements. This allows for the execution of different blocks of code based on the first true condition encountered.
Uses if
→ elif
→ else
to chain together multiple branches.
Conditions are checked top to bottom:
The first true condition executes, and the rest are skipped.
If none are true, the else
(if present) runs.
Makes code clearer than deeply nested conditionals when testing multiple alternatives.
Only one branch will be able to run, and Python checks each condition in order.
There can be any number of “elif” statements, but at most one final “else”, which must come last. This “else” statement is optional.
Using Boolean Functions in Conditionals
A Boolean function is a function that returns a Boolean value (True
or False
). When used in conditionals, Boolean functions simplify code by separating the logic test from the control flow. This makes programs easier to read, maintain, and reuse.
Simple (Primitive) Data Types
Simple (or primitive) data types are the most basic kinds of data built into a programming language. They represent single values (not collections or structures) and are the fundamental building blocks for all other data types.
✅ Key Points:
Primitive = cannot be broken down into simpler data within the language.
Used to store simple values like numbers, text, or truth values.
Operations on primitive types are usually very fast because they’re directly supported by the computer’s memory and processor.
The exact list of primitive types varies between programming languages.
💻 Examples in Python:
int → integers (e.g., 42
, -7
, 0
)
float → floating-point numbers / decimals (e.g., 3.14
, -2.5
)
bool → Boolean values (e.g., True
, False
)
Collection Data Types
Collection data types are data structures that can store multiple values together in a single variable. Unlike primitive types, which hold only one value, collections group values so they can be organized, accessed, and manipulated efficiently.
Hold multiple elements (can be homogeneous or heterogeneous, depending on the language).
Support operations like indexing, iteration, searching, adding, and removing.
Make it easier to manage large or related sets of data.
Come in different forms (ordered vs unordered, mutable vs immutable).
String (str) → A sequence of characters.
List (list) → A sequence of items, which could be numbers, strings, or even other lists. An example is [1, 2, 3].
Collections can be treated as a whole thing (“hello world”) or piece by piece (“hello[0] gives “h”).
String
An ordered collection of characters.
Characters have positions (indexes) from left to right, starting at 0.
“cat” → index 0 = “c”
Strings are sequential, meaning their order matters.
Empty String → A string that has zero characters.
It is written as “” or ‘’.
Index Operator — Strings
Indexing:
Indexing Operator → Square brackets [ ] used to select a single character from a string.
Strings are sequences so each character has a position number (index).
Indexes start at 0, not 1.
The indexing can be any integer expression, like 2 + 1.
Indexing always returns a string of length 1. Python has no separate “character” type.
Negative Indexing:
You can also count backwards using negative numbers.
-1 = last character, -2 = second-to-last, etc.
Function — ‘length’
The length function returns the number of elements (or characters) in a collection or string. It’s used to quickly determine the size of data stored in a variable.
✅ Key Points:
Measures how many items are in a sequence or collection.
Works on strings, lists, tuples, sets, dictionaries, and other iterable objects.
Code — len()
Slice Operator
An operator used to access a subsequence of a string or collection by specifying a start, stop, and optionally a step value. It allows the retrieval of multiple elements at once using a specified range of indexes.
In Python, the slice operator uses square brackets with a colon (:
) to specify start, stop, and optionally step values.
✅ Key Points:
General form: sequence[start:stop]
start → index where the slice begins (inclusive, default = 0
)
stop → index where the slice ends, does not include it (exclusive, default = length of sequence)
step → interval between elements (default = 1
)
Works on any sequence type (string, list, tuple, range).
Does not modify the original sequence; creates a new one.
✅ Omitting Indices
If you leave out the start index, Python assumes the slice begins at the start of the sequence (0
).
If you leave out the stop index, Python assumes the slice continues until the end of the sequence.
If you omit both, [:]
makes a shallow copy of the entire sequence.
✅ Out-of-Range Indexes
Slicing is forgiving: if start
or stop
goes beyond the sequence length, Python automatically adjusts it.
Instead of throwing an error, it just returns as much as possible.
This behavior is different from single-element indexing (e.g., word[100]
), which raises an IndexError.
nums = [0, 1, 2, 3, 4]
print(nums[2:10]) # [2, 3, 4] → stop beyond range, no error
print(nums[-10:3]) # [0, 1, 2] → start below range, adjusted
print(nums[100:200])# [] → empty list, since no elements exist
Slice Operator with Lists:
Syntax → list[start:end]
Works exactly like string slices.
Starts at index “start” and goes up to but not including index “end”.
String Comparison
The comparison operators (==, <, >, etc.) work with strings. They are based on lexicographical order.
Lexicographical Order:
Strings are compared like dictionary order (alphabetical), but with a difference. All uppercase letters come before lowercase letters.
There is case-sensitivity when comparing strings.
Ordinal Value:
Each character has a numeric code (ordinal value) behind it.
ord() → converts a character into its integer code
chr() → converts an integer into its character equivalent
The Space Character:
Space (“ “) is a real character.
The ordinal value of space = 32.
Spaces affect comparisons and string length.
The ‘in’ and ‘not in’ Operators — Strings
The in
and not in
operators are used to check for membership in a sequence or collection. They test whether a value exists (or does not exist) in strings, lists, tuples, sets, or dictionaries, returning a Boolean value (True
or False
).
✅ Key Points:
in
→ evaluates to True
if the element exists in the collection.
not in
→ evaluates to True
if the element does not exist in the collection.
Works with all Python sequences and collections (string, list, tuple, set, dict).
Very useful for conditional statements, loops, and filtering.
List and Elements
A sequential collection of Python data values.
Each value has an index (its position in the list).
Lists are written with square brackets [ ], and elements are separated by commas.
Elements → The values in a list.
Elements can be any type → numbers, strings, booleans, even other lists.
Lists vs. Strings:
Both are sequences (ordered collections), and both can be accessed using indexes.
Strings only contain characters, while lists can contain any type of data (even a mix in one list).
Nested Lists → A list inside another list.
Sublist → The inner list.
Empty List → A list with no elements. Written as [ ].
Assigning Lists to Variables:
You can store lists in variables, just like numbers or strings.
List Length
len() with Lists:
Just like strings, len() tells you the length of a list.
The length of a list is the number of top-level elements.
Sublists count as one element.
Index Operator — Lists
Index Operator with Lists:
The same as with strings; use square brackets [ ].
The number inside the bracket is the index.
Indexing starts at 0.
Can utilize negative indexing, just like with strings.
The expression inside [ ] can be any integer expression.
The ‘in’ and ‘not in’ Operators — Lists
“in” and “not in” are boolean operators that test membership in a sequence.
“in” → Checks if an element is inside a list.
“not in” → Checks if an element is not inside a list.
Both return a boolean value (True or False).
Debugging
Bug → Any programming error.
Debugging → The process of finding and fixing those errors.
Types of Errors:
Syntax Errors → Mistakes in the rules of the language.
Forgetting a colon : in an if statement.
Caught before the program runs.
Runtime Errors → Errors that happen while the program is running.
Dividing by zero, or trying to access lst[10] when the list only has 5 elements.
Semantic Errors → The program runs without crashing, but it doesn’t do what you intended.
Writing x * y when you meant x + y.
Other Types of Errors:
ParseError → A syntax error. Python can’t even parse your code.
Typical Causes:
Missing parentheses, quotation marks, or commas.
Unbalanced parentheses.
TypeError → You’re trying to combine incompatible data types.
Typical Causes:
Adding a string and an integer.
Using arithmetic operators on the wrong type.
NameError → You used a variable or function name that Python doesn’t recognize.
Typical Causes:
Typos in variable names.
Using a variable before giving it a value.
ValueError → You passed a value to a function, but the value was not valid for that function.
Typical Causes:
Debugging → The process of finding and fixing errors in your code.
Form a hypothesis about what is wrong, modify your code, run the program again.
If the result matches your prediction, you’re closer to a fix.
If not, form a new hypothesis and repeat.
Make small changes, testing immediately, and always keep the program in a “working state”.
Incremental Programming → Building a program step by step, debugging as you go.
Debugging Interludes → Special sections with targeted debugging advice.
Incremental Success → Building programs piece by piece with frequent small victories.
Motivation Loop → Each solved problem gives you the energy to solve the next one.
Syntax Errors
Occur when Python cannot parse your code because it violates the language’s syntax rules.
Detected before the program runs.
Examples: missing colon, unmatched parentheses, misspelled keywords.
Every syntax error prevents the program from running.
If an error is found Python displays an error message, and quits execution immediately.
No part of the program will run until all syntax errors are fixed.
Runtime Errors
Occur while the program is running (not before).
The program looks okay at first, but when executed, something goes wrong.
These are also called exceptions because they signal that something exceptional (and bad) occurred.
Characteristics:
The program runs up to the point of the error.
Python stops at the error point and shows an exception message.
Semantic Errors
Occurs when your program runs without crashing, but produces the wrong result.
The code is syntactically correct, but there is an issue with the logic / meaning of the code.
The code does what you told it, but not what you intended.
Subscriptable Objects
What “subscriptable” means
A subscriptable object is any object that supports indexing.
Examples of subscriptable objects:
Strings → "hello"[0]
→ 'h'
Lists → [1,2,3][1]
→ 2
Tuples → (10,20,30)[2]
→ 30
Dictionaries → {"a":1}["a"]
→ 1
Non-subscriptable objects: types that don’t support indexing.
int, float, bool, etc. → you can’t do 10[0]
or 3.14[1]
.
# Indexing a non-subscriptable type
x = 10
x[0] # TypeError: 'int' object is not subscriptable
ValueError vs. TypeError
💡 Quick memory trick:
ValueError → “I got the right kind of thing, but the value doesn’t work.”
TypeError → “This kind of thing can’t do that operation at all.”
Strings are Immutable
Strings Cannot be Modified:
Strings in Python are immutable → Once created, they cannot be changed.
You cannot use indexing [ ] on the left side of an assignment to replace a character.
A TypeError occurs, because Python doesn’t allow changing the type’s structure (in this case, strings). Strings must stay exactly as they are.
Correct Approach:
Instead of editing a string in place, you must build a new string.
Use concatenation (+) and slicing to create the variation you want.
Function — ‘id’
The id()
function in Python returns a unique identifier (an integer) for an object.
This identifier is the object’s memory address (or a unique constant that acts like it) during its lifetime.
Code — id(object)
Object — any variable, list, string, function, etc.
Lists are Mutable
Unlike strings, lists are mutable → This means we can change an item in a list by accessing it directly as part of the assignment statement.
We can update one of the list items by using the indexing operator (square brackets) on the left side of an assignment.
Item Assignment → An assignment to an element of a list.
Item assignment does not work for strings. Recall that strings are immutable.
Using the Slice Operator → By combining assignment with the slice operator, we can update several elements at once.
Assigning an Empty List → We can also remove elements from a list by assigning the empty list to them.
Inserting Elements → We can insert elements into a list by squeezing them into an empty slice at the desired location.
Variables and Objects
Variable → Doesn’t store the value directly, but stores a reference to an object.
Object → Something a variable can refer to.
Checking Identity with “is”:
Use the “is” operator to test if two variables refer to the same object in memory.
Why True → Since strings are immutable, Python can optimize resources by making two names that refer to the same string literal value refer to the same object.
This is not the case with lists.
“a” and “b” have the same value, but do not refer to the same object.
A list is a collection of references.
The variable “a” is a reference to a collection of references.
Those references actually refer to the integer values in the list.
Even though “a” and “b” are two different lists (two different collections of references), the integer objects are shared by both.
Like strings, integers are also immutable so Python optimizes and lets everyone share the same object for some commonly used small integers.
The integers may still be shared in memory because integers (like strings) are immutable.
‘is’ Operator vs. ‘==’
is
→ tests whether two variables point to the same object in memory.
==
→ tests whether two variables have the same value, regardless of whether they are the same object.
Tips for Memorization:
is
→ “Are these two names pointing to the same house?”
==
→ “Do these two houses have the same furniture inside?”
Use is
for identity checks (often with None
: if x is None:
).
Use ==
for value comparisons (most equality checks in programs).
Aliasing
Since variables are references, assigning one variable to another makes them both point to the same object.
Because the same list has two different names, a and b, we say that it is aliased.
Changes made with one alias affect the other.
If a = [81, 82, 83] and b = a, print (a is b) → True, since both a and b now refer to the same list in memory.
When Aliasing is a Problem:
With mutable objects (like lists), aliasing can lead to unintended side effects.
You may accidentally change a value in one place, not realizing it changes another variable as well.
With immutable objects (like strings, integers), aliasing is safe because the object can’t be changed anyway.
Tips for Memorization:
Mutable objects + aliasing → shared changes
Immutable objects + aliasing → safe, since any “change” creates a new object
Use id()
to check if two variables point to the same object:
Explanation:
Initially, both x
and y
reference the same object (10
).
Integers are immutable, so when you “change” y
, Python creates a new object for y
.
x
still points to the original object.
✅ Key point:
Immutable objects (int, str, tuple) do not allow in-place modification, so aliasing doesn’t produce shared changes.
Unlike mutable objects (lists, dicts), modifying y
does not affect x
.
Cloning Lists
Why Clone Lists?
If you just do b = a, then a and b are aliases. They point to the same list. Changing one changes the other.
To avoid this, you need a separate copy of the list. This process is called cloning.
Cloning with Slice:
The easiest way to clone is to use the slice operator [ : ].
Taking a full slice ( a[ : ] ) creates a new list with the same elements.
Cloning vs. Aliasing:
Cloning → Making a new object that has the same contents as the original. Two variables have separate objects with the same content.
Slice operator is the quickest way to clone a list.
a == b → True (they have the same values)
a is b → False (they are different objects in memory)
Aliasing → Two variables share the same object.
a == b → True (they have the same values)
a is b → True (they are the same objects in memory)
Repetition and References
Repetition of Immutable Objects
Safe and behaves as expected because immutable objects cannot be changed.
Repetition of Mutable Objects
Be careful! Repetition creates multiple references to the same object, not independent copies.
Repetition with Nested Lists → Repeated References
When you repeat a list that contains a list, Python repeats the reference to that inner list, not independent copies. When we allow a list to refer to another list, problems can arise.
Avoiding Aliasing → How to Get Independent Sublists
Make copies of the inner list instead of repeating the same reference.
Changing one sublist won’t affect the others.
The ‘for’ Loop
Definition:
A for
loop is a control flow statement used to iterate over a sequence or iterable (like a list, tuple, string, or range).
It executes a block of code repeatedly for each item in the sequence.
Key Points:
Loops over each element directly, no manual indexing needed.
Works with any iterable: lists, tuples, strings, dictionaries, sets, ranges.
Can include an optional else
clause, executed if the loop completes normally (without break
).
Nested for
loops are possible for iterating over multi-dimensional data.
Loop Variable → ‘name’ in the example.
Temporarily holds the current item from the sequence.
Python List → The sequence being iterated over, inside [ ].
Loop Body → The indented code under the ‘for’ statement.
Runs once per item in the list.
Iteration Process → Python checks if there are items left to process.
If yes, assigns the next item to the loop variable and executes the loop body.
If no, the loop terminates and execution moves on.
Terminating Condition → The point at which no items remain, so the loop stops.
At the end of each execution of the body of the loop, Python returns to the ‘for’ statement, to see if there are more items to be handled.
Iterating Without Using the Loop Variable:
Sometimes the loop variable isn’t actually used inside the loop.
Control Flow — The ‘for’ Loop
Control Flow → The order in which the program’s statements are executed by the interpreter.
You can think of this as “Python’s moving finger” that points to each line in turn.
The flow of execution has been sequential so far.
One statement at a time, top to bottom.
This continues as long as statements are indented the same amount.
Sequential vs. Iterative Control Flow:
Sequential Flow → Runs straight through the code, one statement after another.
‘for’ Loop Flow → Introduces indented sub-statements (the loop body) after the loop heading. These are executed multiple times according to the iteration rules.
Function — Range
The range()
function generates a sequence of numbers.
It is commonly used in for loops to iterate a specific number of times.
Returns a range object, which is an immutable sequence of numbers.
Range Object: Immutable Sequence of Numbers
When you call range()
, Python does not create a list of all numbers immediately.
Instead, it creates a range object, which represents the sequence of numbers without storing them all in memory.
Immutable means you cannot change the numbers inside a range object after it’s created.
Code — range(stop)
Default Behavior:
range(N) → starts at 0, ends at N-1
range(4) produces 0,1,2,3
With range(N), a sequence N items long, but since we start at 0, the last number is N-1.
With range(start, stop), the sequence begins at ‘start’ and continues as long as the number is less than ‘stop’.
Range objects are lazy → they generate elements one by one when needed.
To force evaluation, wrap with list().
list(range(4)) → [0, 1, 2, 3]
Code — range(start, stop, step)
start → first number in the sequence (default = 0)
stop → end of the sequence (exclusive)
step → difference between consecutive numbers (default = 1)
Adding a Step:
General Form → range(start, beyondLast, step)
‘Step’ defines the increment (positive or negative).
The Accumulator Pattern
The accumulator pattern is a programming technique where a variable is used to collect or accumulate results while iterating through a sequence.
Commonly used for summing numbers, concatenating strings, counting items, or building lists.
Earlier, squaring ‘n’ was done with multiplication (n * n).
The new approach is using repeated addition instead of multiplication.
Generalizing → to compute n², add ‘n’ to itself ‘n’ times.
How the Algorithm Works:
Start with a running total initialized at 0.
Use a ‘for’ loop to repeat the process ‘n’ times.
Each time through the loop, add ‘n’ to the running total.
After the loop ends, the running total holds the result of n².
The Accumulator Pattern → A common programming pattern where a variable is repeatedly updated (accumulated) inside a loop.
Initialize the accumulator variable (often set to 0 for sums, or 1 for products).
Update the accumulator inside the loop (add, multiply, or otherwise modify).
Result → When the loop ends, the accumulator holds the final value.
Accumulator Variable → The variable (here, ‘runningtotal’) that stores the ongoing result.
If you put ‘runningtotal = 0’ inside the loop instead of before it, it resets to 0 every time the loop begins. The accumulator never grows beyond one update.
Modifying Program — The Accumulator Pattern
Methods — Strings
String methods are built-in functions in Python that operate on string objects to perform actions such as modifying, searching, or formatting text.
They are called using dot notation: string.method(arguments)
.
Strings are immutable, so most methods return a new string rather than modifying the original.
Why / When Guide:
Normalization → strip(), then lower() to compare user input.
Alignment for Display → ljust / rjust / center when printing tables.
Safe Searching → find / rfind when it is normal / possible that the substring might not be there; index / rindex when the substring must be present, as absence is a bug.
Counting → count() for quick frequency checks (remember: non-overlapping).
Bulk Edits → replace() for global changes; use ‘n’ when you only want the first few.
String Method — split() + join()
split()
→ divides a string into a list of substrings based on a separator (default is whitespace).
join()
→ combines elements of a list (or any iterable of strings) into a single string, using the string it’s called on as the separator.
String Method — format()
The format()
method allows you to insert variables or expressions into a string.
Provides flexible string formatting for readability, alignment, precision, and more.
Works with placeholders marked by {}
inside the string.
Strings remain immutable; format()
returns a new string.
Think of {}
as blanks to fill in.
Positional {0}
, {1}
→ fill based on order.
Keyword {name}
→ fill based on named argument.
You are able to mix numbered and named, but avoid mixing unnumbered {} with numbered {0} in the same string.
Useful for creating readable, formatted output instead of concatenation.
Traversal
Traversal → Processing a collection one item at a time from start to finish.
With strings, traversal means visiting each character in order (left → right).
How ‘for’ Works “By Item”
A for
loop in Python iterates directly over the items in a sequence (like a list, string, or tuple) or any iterable object.
A ‘for’ loop can iterate directly over items of any sequence (lists, strings, ranges).
The loop variable takes each item in turn; the loop body runs once per item.
Since a string is a sequence of characters, the ‘for’ loop iterates over every character automatically.
The Accumulator Pattern - Strings
The accumulator pattern with strings means starting with an empty string and then building it step by step inside a loop.
Each iteration adds (concatenates) more characters or words to the string.
Since strings are immutable, each update creates a new string stored back in the accumulator variable.
Steps:
Initialize an empty string (""
).
Loop through items (like characters or words).
Update the string by concatenating the current item.
Use the final result after the loop ends.
Use of ‘not in’ → Helps avoid the use of a very large ‘if’ statement that checks each of the individual vowel characters.
Methods — Lists
List methods are built-in functions that operate on lists, allowing you to add, remove, sort, or otherwise modify list elements.
They are called using dot notation: list.method(arguments)
.
Unlike strings, lists are mutable, so many methods modify the list in place instead of returning a new one.
List Methods — Types
List methods in Python can be grouped by how they behave:
Mutator Methods → Change (mutate) the list directly, no return value (return None
).
Return Methods → Do not change the list; instead, they return information or a new object.
Hybrid Methods → Change the list and also return a useful value.
Mutator = a worker who rearranges the warehouse but doesn’t report back.
Return = a worker who only gives you information but doesn’t touch anything.
Hybrid = a worker who rearranges something and hands you a piece of it.
1. Mutator Methods (change the list, return None):
append(x)
→ adds item to end.
extend(iterable)
→ adds multiple items.
insert(i, x)
→ inserts at index.
remove(x)
→ removes first occurrence.
sort()
→ sorts list in place.
reverse()
→ reverses list in place.
clear()
→ empties the list.
2. Return Methods (don’t change the list):
index(x)
→ returns index of x
.
count(x)
→ counts occurrences of x
.
copy()
→ returns a shallow copy.
3. Hybrid Methods (change list + return value):
pop(i)
→ removes item at index i
(default: last) and returns it.
List Methods — Returning ‘None’
Methods like ‘append’, ‘sort’, and ‘reverse’ all return ‘None’. This means that re-assigning ‘mylist’ to the result of sorting ‘mylist’ will result in losing the entire list.
Append vs. Concatenate — Lists
Append → Mutates in place, changes the same list object. Adds one item as a single element.
Concatenation with ‘+’ → Creates a new list, you must assign the result. The right-hand side must be a list (not a bare string).
Step 1: Initial assignment
origlist = [45, 32, 88]
A list object [45, 32, 88]
is created in memory.
The variable name origlist
now refers (points) to this list object.
Step 2: Concatenation
The expression origlist + ["cat"]
is evaluated.
In Python, the +
operator on lists does not mutate the original list.
Instead, it creates a brand-new list object that contains:
Step 3: Reassignment
The result of origlist + ["cat"]
(the new list) is assigned back to the variable origlist
.
Now, origlist
points to the new list object.
The old list [45, 32, 88]
still exists in memory, but nothing is pointing to it anymore (unless you had another variable referring to it).
Since no variables reference the old list, Python’s garbage collector will eventually clean it up.
Key Idea:
Mutating: Methods like .append()
or .extend()
change the list in place without creating a new one.
Concatenation with +
: Creates a new list object and then reassigns the variable.
Nested Lists
A list that contains another list as an element.
Accessing Items:
Modifying Elements Inside a Nested List:
Mutate the inner list directly through the outer reference.
Length and Slicing: