Basic Input and Output
print() Output Function
print() outputs content to the console. Text, symbols and static content must be wrapped in matching quotes (single or double) to work correctly.
# Basic syntax
print(output_content)
# Example text output
print("Hello Python World!")
input() Input Function
input() pauses execution to collect user input from the console. The argument passed to input() is the prompt text shown to the user.
# Basic syntax
user_input = input("Enter your input here: ")
Comments
Comments are non-executable notes for developers, ignored by the Python interpreter.
- Single-line comments: Start with a
#, all content after#on the same line is treated as a comment. - Multi-line comments: Wrap an entire block of comments with three matching single or double quotes.
Variables
Variables act as storage containers for data in Python, with three core components:
- Data type: Category of the stored content
- Memory address: Location of the variable in system memory
- Value: The actual data stored in the variable
Variable Naming Rules
- Can only contain letters, numbers, and underscores
- Cannot start with a number, and cannot be entirely numeric
- No spaces or other special characters allowed
- Variable names are case-sensitive (
Ageandageare two distinct variables) - Cannot use Python reserved keywords or built-in function names as variable names
- Use descriptive names; common conventions are camelCase (each word starts with a capital letter) or snake_case.
Working with Variables
Variables must be declared before use. The = operator is used for assignment:
# Declare and assign variables
given_name = "Jamie Carter"
current_age = 28
# Output variable vs output literal string
print(given_name) # Outputs the value stored in the variable
print("given_name") # Outputs the literal text "given_name"
# Assign input value to variable
user_hobby = input("What is your hobby? ")
print(user_hobby)
Note: Python executes code top to bottom, so you cannot reference a variable before it is declared.
Basic Data Types
1. Integer (int)
Whole numbers with no decimal point are stored as integers:
current_year = 2024
print(current_year)
print(type(current_year)) # Output: <class 'int'>
2. Float (float)
Any number with a decimal point is classified as a float:
user_height = 1.75
print(user_height)
print(type(user_height))
print(type(0.0))
3. Boolean (bool)
Booleans only have two valid values, always capitalize the first letter:
True: Represents a true/yes condition, equivalent to the integer 1False: Represents a false/no condition, equivalent to the integer 0
Booleans can be used as numeric values, though this is rarely used in common practice.
Core Sequence Type: String (str)
Strings store sequences of characters, with the following rules:
- Single-line strings are wrapped in matching single or double quotes
- Multi-line strings are wrapped in three matching single/double quotes
- Quotes must always match. To include a quote inside a string, use escape characters or alternate opening/closing quote types.
# Valid single-line string
greeting = "Hello World"
# Valid multi-line string
multi_line = '''
First line of content
Second line of content
Third line of content
'''
# Invalid example (mismatched quotes, throws error)
# print("He said "Hello!")
# Correct way to include quotes inside a string
print('He said "Hello!"')
# String concatenation
full_text = "Hello " + "World!"
print(full_text)
Sequence Core Concepts: Indexing, Slicing and Step
Subscript (Index)
Unlike human counting that starts at 1, Python sequence indexes start at 0. Negative indexes count from the end of the sequence: -1 refers to the last element, -2 to the second last, and so on.
Access Single Elements by Index
# Syntax: sequence[index]
full_name = "Jamie Carter"
print(full_name[0]) # Output first character: J
print(full_name[3]) # Output 4th character: m
print(full_name[-2]) # Output second last character: e
# print(full_name[20]) # Throws index out of range error
Slicing: Extract Multiple Elements
Slicing lets you extract a sub-sequence from an existing sequence.
Syntax: sequence[start_index:end_index]
sample_text = "Today we will learn Python"
print(sample_text[3:10]) # Extract from index 3 up to (but not including) index 10
print(sample_text[3:30]) # No error if end exceeds max index, just returns all content up to end
print(sample_text[3:-2]) # Excludes the last two characters
print(sample_text[3:]) # Omitted end defaults to end of sequence
print(sample_text[:7]) # Omitted start defaults to 0
# Slicing always proceeds left to right. If start > end, you get an empty sequence
print(sample_text[-4:-2]) # Works, left to right
print(sample_text[-2:-4]) # Returns empty sequence, no error
Key Slicing Rules:
- End index is exclusive:
[2:6]extracts only indexes 2, 3, 4, 5 - Omitted start defaults to 0, omitted end defaults to end of sequence
- Out of range indexes do not throw errors (unlike single element access)
- Slicing always goes from lower index to higher index (left to right)
Step in Slicing
By default slicing takes every element (step = 1). You can specify a custom step to skip elements; a negative step reverses the entire sequence.
Syntax: sequence[start:end:step]
num_sequence = "123456789"
print(num_sequence[1::2]) # Output: 2468 (every second element starting from index 1)
print(num_sequence[::-1]) # Reverse entire sequence: 987654321
List (list)
Lists are mutable sequences wrapped in square brackets, elements separated by commas. Lists can store any data type, and elements can be modified after creation.
# Define a list
sample_list = ["apple", 25, True, 3.14]
print(sample_list)
print(sample_list[1]) # Output 25
print(type(sample_list))
# Modify element by index
sample_list[0] = "banana"
print(sample_list)
# Nested lists
list_a = [1, 2, 3]
list_b = [4, 5, 6]
nested_list = [list_a, list_b]
print(nested_list)
print(nested_list[0]) # Output first inner list
print(nested_list[0][1]) # Output 2 from first inner list
Tuple (tuple)
Tuples are immutable sequences wrapped in parentheses, elements separated by commas. They can store any data type, but cannot be modified after creation.
# Define a tuple
sample_tuple = ("chris", 30, False)
print(sample_tuple)
print(type(sample_tuple))
# Critical: single-element tuples *must* have a trailing comma
bad_single = ("test") # Not a tuple, this is just a string
print(type(bad_single)) # Output: <class 'str'>
good_single = ("test",) # Correct, trailing comma marks it as a tuple
print(type(good_single)) # Output: <class 'tuple'>
Escape Characters
Escape characters are special sequences starting with a backslash \ that have special meaning:
\n: New line\t: Tab indent (4 spaces)\\: Output a literal backslash\': Output a literal single quote
To disable escape character processing entirely, add an r before the opening quote of the string:
print("Hello\tWorld\nHow are you")
print(r"Hello\tWorld\nHow are you") # Escape characters treated as literal text
Type Conversion
Use built-in functions to convert between common data types:
int(data): Convert to integerfloat(data): Convert to floatstr(data): Convert to stringlist(data): Convert to listtuple(data): Convert to tuple
# Example 1: Convert string to integer for arithmetic
age_str = "18"
age_int = int(age_str)
print(age_int + 10) # Output 28, works after conversion
# Example 2: input() returns string by default
height_input = input("Enter your height in cm: ")
height_int = int(height_input)
print(height_int + 10) # Works after conversion
# Example 3: Concatenation requires matching string type
user_id = 12345
print(str(user_id) + " is your ID") # Convert int to string for concatenation
Important: Never name variables after built-ins like
int,float,list— this will overwrite the built-in and cause unexepcted errors.
Formatted String Output
Combining variables of different types manually is tedious. Python has three common formatting methods:
1. f-strings (Python 3.6+)
Add an f before the string, wrap variables/expressions in curly braces {}:
user_name = "Jamie"
user_age = 28
print(f"Hello, my name is {user_name}, and I am {user_age} years old.")
# You can put any expression inside braces
print(f"Next year I will be {user_age + 1} years old.")
print(f"The first character of my name is {user_name[0]}")
2. Old-style Percent Formatting
Use percent codes as placeholders, then pass values at the end:
%s: Placeholder for string%d: Placeholder for integer%f: Placeholder for float;%.1ffor 1 decimal place,%.2ffor 2 decimals
name = "Jamie"
age = 28
balance = 1234.5678
print("My name is %s, I am %d years old, and I have %.2f dollars" % (name, age, balance))
3. str.format() Method
Use empty curly braces as placeholders, pass values via the .format() method:
name = "Jamie"
age = 28
print("My name is {}, I am {} years old".format(name, age))
# Reorder values by index
print("My name is {1}, I am {0} years old".format(age, name))
Flow Control Statements
Three Core Execution Modes
- Sequential execution: Code runs line by line, top to bottom. Execution stops immediately if an error is encountered.
- Conditional execution: Runs different code blocks based on whether a condition is met.
- Loop execution: Repeats a code block as long as the condition remains true.
All condition checks rely on boolean values (
True/False).
Indentation
Python uses indentation to group code blocks. Indented code belongs to the preceding un-indented statement.
Conditional Statements (if/elif/else)
Run different code based on conditions:
# Double branch example
score = 75
if score > 60:
print("You passed!")
else:
print("You failed!")
# Multi-branch example
score = 60
if score == 100:
print("Perfect score!")
elif score > 60:
print("Passed")
else:
print("Failed")
Short-circuit Logic
and: Both conditions must beTrue. If the first condition isFalse, the second is never evaluated.or: Only one condition needs to beTrue. If the first isTrue, the second is never evaluated.
Any non-empty/non-zero value is treated as True in conditions; empty/zero values are False.
Loop Statements
while Loop
Runs the code block as long as the loop condition remains True:
count = 1
while count <= 100:
print(f"This is iteration {count}")
count += 1 # Don't forget to increment to avoid infinite loop
for Loop
Used to iterate over iterable objects, or run a fixed number of iterations:
# Iterate over a list
fruits = ["apple", "banana", "orange"]
for fruit in fruits:
print(fruit) # Assign each element to the temp variable one by one
# Fixed iterations with range()
for i in range(100): # Runs 100 times, i from 0 to 99
print(i)
for i in range(1, 100): # i from 1 to 99
print(i)
for i in range(1, 100, 2): # Step 2, only odd numbers 1, 3... 99
print(i)
break and continue
break: Immediately terminates the entire loopcontinue: Skips the current iteration and moves to the next
# break example: stop after 10 laps
for lap in range(1, 101):
print(f"Ran {lap} laps")
if lap == 10:
print("I'm tired, stopping")
break
# continue example: skip specific pages
for page in range(1, 21):
if page in [10, 15, 20]:
continue
print(f"Copied page {page}")
pass Statement
pass is a no-op placeholder. Use it when you need an empty code block to avoid syntax errors:
if some_condition:
pass # Will add code later, placeholder avoids error
Nested Control Flow
Nested Conditionals Example
will_rain = input("Will it rain today? (yes/no): ")
if will_rain == "yes":
activity = input("Do you want to read or play games? ")
if activity == "read":
print("Bring a book")
elif activity == "play":
print("Charge your console")
else:
print("Please enter a valid activity")
else:
print("Go for a hike")
Nested Loop Example: 5x5 Grid
for row in range(5):
for col in range(5):
print(2, end=' ') # end=' ' disables default new line after print
print() # Add new line after each row
Common Sequence Methods
List Methods
Lists are mutable, so they support add/remove/modify operations:
grocery = ["banana", "apple"]
# Add elements
grocery.append("orange") # Add to end
grocery.insert(2, "grapes") # Insert at specific index, shift existing right
grocery.extend(["ice cream", "jelly"]) # Add all elements from another iterable
# Remove elements
grocery.pop(2) # Remove element at specific index
grocery.remove("jelly") # Remove first matching value
# Slice assignment for bulk modification
grocery[1:4] = ["strawberry", "blueberry", "carrot", "dumpling"] # Can be longer/shorter than original slice
# Search
print(grocery.index("apple")) # Returns first index of match
print(grocery.count("apple")) # Count occurrences
# Sort
nums = [1, 5, 2, 8, 3, 9]
nums.sort() # Sort ascending in-place
print(nums)
nums.sort(reverse=True) # Sort descending in-place
print(nums)
Tuple Methods
Tuples are immutable, so they only have read-only methods:
sample_tuple = (30, 40, 50, 3, 2, 3)
print(sample_tuple.index(3, 4)) # Find first 3 starting from index 4
String Methods
Strings are immutable, all methods return new strings without modifying the original:
original = "I love learning, I learn every day"
print(original + " do you learn today?") # Original unchanged
# Replace substrings
bad_text = "You are a bad player, bad move"
print(bad_text.replace("bad", "inexperienced"))
# Case conversion
sample = "Hello World"
print(sample.lower()) # All lowercase
print(sample.upper()) # All uppercase
print(sample.title()) # First letter of each word uppercase
# Trim whitespace
spaced_text = " hello world "
print(spaced_text.strip()) # Remove leading/trailing whitespace
# Search
print(sample.find("o")) # Returns first index of o, -1 if not found
print(sample.count("l")) # Count occurrences
# Check content type
num_str = "12345"
print(num_str.isdigit()) # True
mixed_str = "abc123"
print(mixed_str.isalpha()) # False
Sets and Dictionaries
Set (set)
Sets are unordered collections of unique values, wrapped in curly braces. Used for deduplication and set logic operations. Only immutable data types can be stored in sets (no lists allowed).
# Define a set
usernames = {"Alex", "Chris", "Sam", "Alex"}
print(usernames) # Duplicate "Alex" is automatically removed
# Sets are unordered, cannot index: print(usernames[0]) throws error
# Set operations
a = {1, 2, 4}
b = {3, 4, 5}
print(a - b) # Difference: elements unique to a: {1, 2}
print(a & b) # Intersection: elements in both: {4}
print(a | b) # Union: all unique elements: {1, 2, 3, 4, 5}
# Set methods
usernames.add("Taylor") # Add new element
usernames.pop() # Remove random element
usernames.remove("Alex") # Remove specific element
usernames.clear() # Remove all elements, leaves empty set
Dictionary (dict)
Dictionaries store data as key-value pairs, wrapped in curly braces. Keys are unique and immutable; values can be any type.
# Define a dictionary
user_info = {
"name": "Jamie Carter",
"gender": "male"
}
print(user_info["name"])
# Key rules:
# - Keys must be immutable: int, str, tuple allowed, list not allowed
# - Values can be any type, including nested collections
# - Duplicate keys keep only the last value defined
nested_info = {
"name": "Jamie",
"balance": [100.5, 200.9, 300],
"address": {
"work": "New York",
"home": "Boston"
}
}
# Dictionary methods
user_info.setdefault("country", "USA") # Add key with default if it doesn't exist
user_info.pop("country") # Delete key-value pair by key
user_info.update({"age": 28, "gender": "female"}) # Update existing, add new
user_info["gender"] = "male" # Direct assignment: update if exists, add if not
print(user_info.get("name")) # Return value, None if key doesn't exist
print(user_info.keys()) # Get all keys
print(user_info.values()) # Get all values
print(user_info.items()) # Get all (key, value) pairs
Declare Empty Collections
empty_list = []
empty_tuple = ()
empty_str = ""
empty_set = set() # {} is empty dictionary, use set() for empty set
empty_dict = {}
Function Basics
A function wraps a block of reusable code. Function naming follows the same rules as variable naming.
Define and Call Functions
def greet():
message = "Hello World"
print(message)
greet() # Call the function
Function Parameters
Parameters let you pass dynamic values into a function:
def add(a, b):
print(a + b)
add(5, 10) # Number of arguments must match number of parameters
Common Parameter Types
- Required parameters: Must be passed, count must match
- Default parameters: Have a default value if no argument is passed. Must come after required parameters.
def greet_user(name, greeting="Hello"):
print(f"{greeting}, {name}!")
greet_user("Jamie") # Uses default greeting
greet_user("Jamie", "Good morning") # Overrides default
- Variable positional parameters (
*args): Accept any number of positional arguments, stores as a tuple.
def print_all(*args):
print(args)
print_all("apple", 123, True)
- Variable keyword parameters (
**kwargs): Accept any number of keyword arguments, stores as a dictionary.
def print_info(name, age, **kwargs):
print(f"Name: {name}, Age: {age}")
print(kwargs)
print_info("Jamie", 28, city="New York", job="Engineer")
Return Values
return sends a value back to the caller, and exits the function immediately. Functions without return return None by default.
def add(a, b):
return a + b
result = add(3, 5)
print(result + 2) # Use returned value for further operations
Closures and Decorators
Closures are nested functions that capture outer scope variables. Decorators are special closures used to add functionality to existing functions without modifying their source code (following the open/closed principle):
def add_feature(func):
def wrapper():
print("New functionality before original")
func()
print("New functionality after original")
return wrapper
@add_feature
def original():
print("Original function output")
original()
File Operations
Absolute vs Relative Paths
- Absolute path: Full path starting from the root of the drive
- Relative path: Path relative to the current working directory:
./is current directory,../is parent directory
Add r before the path string to avoid escape character issues.
Basic File Operations
Three core steps: open, operate, close. Always close files to avoid memory leaks. The with statement automatically closes files for you:
# Write to file
with open("test.txt", "w", encoding="utf-8") as f:
f.write("Hello World\n")
f.write("Second line")
# Read from file
with open("test.txt", "r", encoding="utf-8") as f:
print(f.read()) # Read entire file
Common open modes:
w: Write, overwrites existing content, creates file if it doesn't exista: Append, adds new content to end of existing filer: Readb: Binary mode for non-text files like images
Modules and Packages
A module is a .py file containing reusable Python code. A package is a folder that organizes related modules.
Importing Modules
# Import entire module
import math
print(math.pi)
# Import specific object from module
from math import pi
print(pi)
# Give alias with as
import numpy as np
Common Built-in Modules
time
import time
print(time.time()) # Seconds since epoch
print(time.strftime('%Y-%m-%d %H:%M:%S')) # Format current time
random
import random
print(random.randint(1, 10)) # Random integer 1-10 inclusive
print(random.choice(["apple", "banana", "orange"])) # Random pick
json
Preserve Python data types when saving to files:
import json
users = ["Alex", "Chris", "Jamie"]
# Save to file
with open("users.json", "w", encoding="utf-8") as f:
json.dump(users, f)
# Load from file
with open("users.json", "r", encoding="utf-8") as f:
loaded = json.load(f)
print(loaded[2]) # Output Jamie, original list type preserved
Object Oriented Programming Basics
Class and Object
- Class: A template/blueprint for creating objects
- Object: An instance created from a class Class variables are called attributes, class functions are called methods.
class Hero:
def __init__(self, name, health, quote):
self.name = name
self.health = health
self.quote = quote
def print_info(self):
print(f"{self.name}: {self.quote}, HP: {self.health}")
garen = Hero("Garen", 600, "Demaaaaaacia!")
garen.print_info()
self always refers to the current object instance, and must be the first parameter of all instance methods.
Encapsulation
Encapsulation hides internal implementation details. To make an attribute private, add two leading underscores __. Private attributes can only be accessed inside the class:
class User:
def __init__(self, name, age, face_rating):
self.name = name
self.age = age
self.__face = face_rating
def get_face(self):
return self.__face
def set_face(self, new_rating):
self.__face = new_rating
face = property(fget=get_face, fset=set_face)
user = User("Jamie", 28, 8)
print(user.face) # Access private attribute like normal
user.face = 9 # Modify private attribute like normal
Inheritance
A child class can inherit attributes and methods from a parent class:
class Parent:
def __init__(self):
self.money = 1000
def work(self):
print("Parent working")
class Child(Parent):
def __init__(self):
super().__init__() # Call parent class initializer
self.car = "Tesla"
child = Child()
child.work() # Inherited method from Parent
print(child.money) # Inherited attribute