python
Python is a high-level, interpreted programming language known for its readable syntax, flexibility, and broad range of applications. Its simple and expressive design allows developers to focus on solving problems rather than managing complex language details, making it suitable for both beginners and experienced programmers. Python is widely used in web development, data analysis, artificial intelligence, automation, scientific computing, and software development.
This section explores the fundamental concepts of Python, including variables, data types, operators, control structures, functions, collections, modules, classes, exception handling, and file operations. It also examines Python’s major strengths, limitations, extensive library ecosystem, and practical applications, providing a clear foundation for understanding how Python is used to develop efficient and versatile software solutions.

Introduction To python
wwww
- Learn Python with AI Made Easy
- Introduction
- Detailed Setup and First Application
- 2.1 Prerequisites for Environment Setup
- 2.2 Setup on Linux (Ubuntu) – Command-Line Environment
- 2.3 Setup on Linux – Professional IDE Environment
- 2.4 Setup on Linux – AI-Integrated Development Workflow
- 2.5 Setup on Windows – Command-Line Environment
- 2.6 Setup on Windows – Professional IDE Environment
- 2.7 Setup on Windows – AI-Integrated Development Workflow
- 2.8 Setup on macOS – Command-Line Environment
- 2.9 Setup on macOS – Professional IDE Environment
- 2.10 Setup on macOS – AI-Integrated Development Workflow
- 2.11 Python Interpreter and Running Programs
- 2.12 First Python Program (Hello World)
- 2.13 Software Execution Lifecycle
- AI Integration with AI Tools
- Python Programming Basics
- Data Types & Operators
- 5.1 Numeric Types (int, float, complex)
- 5.2 Boolean Type
- 5.3 Sequence Types (string, list, tuple, range)
- 5.4 Set Types
- 5.5 Mapping Type – Dictionary
- 5.6 Arithmetic Operators
- 5.7 Comparison Operators
- 5.8 Logical Operators
- 5.9 Assignment Operators
- 5.10 Bitwise Operators
- 5.11 Identity Operators
- 5.12 Membership Operators
- Control Flow
- Functions & Modular Programming
- Python Data Structures
- Strings & Text Processing
- Modules & Packages
- Object-Oriented Programming (OOP)
- File Handling
- Error Handling (Exceptions)
- Advanced Python
- Data Structures & Algorithms in Python
- Python Ecosystem
- Real-World Projects
- Testing & Professional Development
- Career Readiness
- Portfolio organization
Learn Python with AI Made Easy
Understanding Python and Its Industry Importance
Why Python Matters in Industry
Python has become one of the most dominant programming languages in the world due to its simplicity, versatility, and extensive ecosystem. It powers everything from web applications to artificial intelligence systems. Companies like Google, Facebook, Netflix, and NASA use Python for critical infrastructure. Its readability makes it an excellent first language, while its power makes it suitable for professional development.
Career Opportunities
Python supports a wide range of career opportunities. Data Scientists use it for data analysis and machine learning, while Web Developers build backend applications with frameworks such as Django and Flask. Automation Engineers create scripts that streamline repetitive tasks, and DevOps Engineers use Python for infrastructure and deployment automation. AI/ML Engineers develop intelligent models and applications, while Cybersecurity Professionals use Python to build security tools and automate security-related tasks.
Technical Prerequisites
Before starting Python, you need basic computer literacy including file management, folder navigation, and using a text editor. No prior programming experience is required. Familiarity with command line operations is helpful but not necessary.
Common Beginner Mistakes
New Python developers often make mistakes like forgetting colons at the end of control statements, mixing tabs and spaces for indentation, using mutable default arguments, and not handling exceptions properly. Understanding these pitfalls early helps build better coding habits.
Role of AI in Python Development
AI tools like GitHub Copilot and ChatGPT have revolutionized Python development. They can generate code, explain concepts, debug errors, and suggest optimizations. These tools don’t replace learning but accelerate understanding and productivity.
How to Use This Course Effectively
This course combines structured learning with AI assistance. Read each concept, practice with code examples, then use AI tools to deepen understanding. Run every code example yourself and experiment with modifications. Use ChatGPT to explain concepts you find challenging.
Real-World Python Project Categories
Python projects span multiple domains. Beginner projects include calculators and to-do lists. Intermediate projects include REST APIs and web scrapers. Advanced projects include AI chatbots and recommendation systems. Each category builds specific skills.
Learning Roadmap
The roadmap progresses from basics to advanced topics. Start with environment setup and fundamental syntax. Progress through data types, control flow, and functions. Move to data structures, OOP, and file handling. Finally explore advanced features and ecosystem tools.
How to Use This Roadmap
Each section builds on previous knowledge. Master each concept before moving forward. Use the AI prompts to get additional explanations and examples. Complete the exercises and projects to reinforce learning.
Introduction
1.1 What is Python
Python is a high-level, interpreted, general-purpose programming language designed with an emphasis on simplicity, readability, and ease of development. It emphasizes code readability through significant indentation and clear syntax.
Python was designed to be easy to learn and use while being powerful enough for professional development.Python supports multiple programming paradigms, including procedural, object-oriented, and functional programming, allowing developers to choose different approaches based on the problem they are solving. Python’s philosophy emphasizes “there should be one– and preferably only one –obvious way to do it.”
Code Example
# Single-line comment
print("Hello, World!") # This is a simple print statement
"""
This is a multi-line comment
using triple quotes
It can span multiple lines
"""
1.2 History of Python
Python was created by Guido van Rossum and first released publicly in 1991.Its name comes from Monty Python’s Flying Circus, not the snake.
Python 2.0 was released in 2000 with new features like list comprehensions and garbage collection. Python 3.0 was released in 2008 with major improvements but breaking backward compatibility. Python 3 continues to evolve with regular updates adding features like pattern matching and improved performance.
1.3 Why Python is Popular
Python’s popularity stems from its simplicity, powerful libraries, and broad application range.
Python’s clean syntax makes it accessible to beginners. Its extensive standard library provides solutions for common tasks. The Python Package Index (PyPI) hosts thousands of third-party packages. Python’s versatility allows it to be used for web development, data science, automation, and more.
1.4 Key Features of Python
Python features include dynamic typing, automatic memory management, and extensive standard libraries.
Dynamic typing means variables don’t require type declarations. Automatic memory management handles allocation and garbage collection. Python is commonly described as an interpreted language, meaning its code is executed by the Python runtime rather than being compiled directly into native machine code first. Its cross-platform nature allows Python programs to run on operating systems such as Windows, macOS, and Linux, with little or no modification. Extensive libraries provide ready-to-use functionality.
Code Example
# Dynamic typing - variables can change type
bird_count = 10 # int
bird_count = "ten" # now string
# Automatic memory management
# Python handles memory allocation and deallocation automatically
1.5 Python vs Other Languages (C, C++, Java)
Python differs from compiled languages like C, C++, and Java in execution model, syntax complexity, and use cases.
vs C/C++: Python is interpreted while C/C++ are compiled. Python has automatic memory management while C/C++ require manual memory management. Python syntax is simpler and more readable. vs Java: Python is dynamically typed while Java is statically typed. Python code is often more concise than equivalent Java code, largely because Python has simpler syntax and requires less boilerplate. Python requires less boilerplate code.
1.6 Python Applications (Web, Data Science, AI, Automation, Cybersecurity)
Python is used across multiple domains for various applications.
Web Development: Django, Flask, and FastAPI for building web applications. Data Science: NumPy, Pandas, Matplotlib for analysis and visualization. AI/ML: Python provides powerful libraries such as TensorFlow, PyTorch, and Scikit-learn for building, training, and deploying machine learning and artificial intelligence models.Automation: Scripts for file operations, web scraping, and task scheduling. Cybersecurity: Security tools, penetration testing, and vulnerability scanning.
Detailed Setup and First Application
2.1 Prerequisites for Environment Setup
Before installing Python, ensure your system meets basic requirements.
You need a computer running Windows, macOS, or Linux. Administrative privileges may be required for installation. An internet connection for downloading Python and extensions. A text editor or IDE (Integrated Development Environment) is used to write, edit, and manage source code. An IDE may also provide features such as debugging, code completion, and project management.
2.2 Setup on Linux (Ubuntu) – Command-Line Environment
Step 1: Update System Packages
sudo apt update
sudo apt upgrade
Step 2: Install Python 3
sudo apt install python3 python3-pip
Step 3: Verify Installation
python3 --version
Step 4: Create a Project Folder
mkdir python-project
cd python-project
Step 5: Create Your First Python Script
nano hello.py
Step 6: Save and Exit
print("Hello, World!")
Press Ctrl+X, then Y, then Enter.
Step 7: Run the Program
python3 hello.py
Step 8 (Optional): Make the Script Executable
chmod +x hello.py
./hello.py
2.3 Setup on Linux – Professional IDE Environment
Step 1: Install VS Code
sudo snap install --classic code
Step 2: Install the Python Extension
Open VS Code, select the Extensions panel using Ctrl+Shift+X, search for “Python”, and install the official Microsoft Python extension.
Step 3: Open Your Project Folder
code .
Step 4: Create a New Python File
Click the New File icon and name it hello.py.
Step 5: Write Your Code
print("Hello, World!")
Step 6: Run the Code
Press Ctrl+F5 to run without debugging.
Step 7: Debug Your Code
Set a breakpoint by clicking the left margin, then press F5.
2.4 Setup on Linux – AI-Integrated Development Workflow
Step 1: Create Required Accounts
Create a GitHub account and subscribe to Copilot. Create an OpenAI or ChatGPT account.
Step 2: Install GitHub Copilot Extension in VS Code
Go to Extensions, search “GitHub Copilot”, and install.
Step 3: Authenticate Copilot
Sign in with your GitHub account.
Step 4: Generate Code Using Copilot
# Type a comment and let Copilot generate the code
# Function to count birds in a list
Step 5: Use ChatGPT for Explanations and Debugging
Ask ChatGPT to explain code or fix errors.
Step 6: Refactor Code with AI
Use AI suggestions to improve code quality.
2.5 Setup on Windows – Command-Line Environment
Step 1: Download Python Installer
Visit python.org and download the latest Python installer.
Step 2: Run the Installer
Check “Add Python to PATH” and click “Install Now”.
Step 3: Verify Installation
python --version
Step 4: Create a Project Folder
mkdir python-project
cd python-project
Step 5: Create Your First Python Script
echo print("Hello, World!") > hello.py
Step 6: Run the Program
python hello.py
Step 7 (Optional): Use Python Interactive Mode
python
>>> print("Hello")
>>> exit()
2.6 Setup on Windows – Professional IDE Environment
Step 1: Install Visual Studio Code
Download from code.visualstudio.com and install.
Step 2: Install the Python Extension
Open VS Code, go to Extensions, search “Python”, and install.
Step 3: Open Your Project Folder
File → Open Folder → Select python-project.
Step 4: Create a Python File
Click New File, name it hello.py.
Step 5: Run the Code
print("Hello, World!")
Press Ctrl+F5.
Step 6: Set Up Debugging
Click the Run and Debug icon, select Python, set breakpoints, and press F5.
2.7 Setup on Windows – AI-Integrated Development Workflow
Step 1: Install GitHub Copilot Extension
Search and install “GitHub Copilot” from Extensions.
Step 2: Sign In to GitHub
Sign in when prompted.
Step 3: Generate Code with Copilot
# Function to calculate total birds
Step 4: Use ChatGPT for Debugging
Copy error messages and ask ChatGPT for solutions.
Step 5: Refactor with AI
Ask AI to suggest improvements for your code.
2.8 Setup on macOS – Command-Line Environment
Step 1: Install Homebrew (Package Manager)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
Step 2: Install Python 3 via Homebrew
brew install python
Step 3: Verify Installation
python3 --version
Step 4: Create a Project Folder
mkdir python-project
cd python-project
Step 5: Create a Python Script
echo 'print("Hello, World!")' > hello.py
Step 6: Run the Program
python3 hello.py
2.9 Setup on macOS – Professional IDE Environment
Step 1: Install VS Code
Download from code.visualstudio.com and drag to Applications.
Step 2: Install Python Extension
Open VS Code, go to Extensions, search “Python”, and install.
Step 3: Open Project Folder
code .
Step 4: Create and Run hello.py
Create hello.py with print("Hello, World!") and press Ctrl+F5.
Step 5: Use the Integrated Debugger
Set breakpoints and press F5.
2.10 Setup on macOS – AI-Integrated Development Workflow
Step 1: Install GitHub Copilot in VS Code
Install from Extensions.
Step 2: Generate Code with AI
# Create a bird class with species and count
Step 3: Use ChatGPT to Understand Code
Ask ChatGPT to explain generated code.
Step 4: Optimize with AI
Request AI to suggest performance improvements.
2.11 Python Interpreter and Running Programs
The Python interpreter executes Python code either interactively or from files.
Interactive mode runs commands one at a time. Script mode executes complete files. The interpreter handles compilation to bytecode and execution. REPL (Read-Eval-Print-Loop) allows immediate feedback.
Code Example
# In interactive mode
>>> print("Hello")
Hello
>>> 2 + 3
5
# In script mode
# File: script.py
print("Hello from script")
2.12 First Python Program (Hello World)
Code Example
# hello.py - Your first Python program
print("Hello, World!")
# Using variables
message = "Hello, Python!"
print(message)
# Multiple prints
print("This is", "a", "single", "line")
# Formatted output
name = "Python"
version = 3.12
print(f"Welcome to {name} {version}!")
The print() function outputs text to the console. Variables store values for later use. The f-string format embeds variables in strings.
2.13 Software Execution Lifecycle
Python programs go through multiple stages from writing to execution.
Writing: Create source code in .py files. Compilation: Python compiles to bytecode (.pyc files). Execution: The Python Virtual Machine executes bytecode. Error Handling: Runtime errors are caught and managed. Output: Results are displayed or saved.
Code Example
# Understanding the execution flow
def main():
print("Program starts")
try:
result = 10 / 2
print(f"Result: {result}")
except Exception as e:
print(f"Error: {e}")
print("Program ends")
if __name__ == "__main__":
main()
AI Integration with AI Tools
3.1 ChatGPT Workflows
ChatGPT helps with learning, debugging, and generating Python code.
Use ChatGPT to explain concepts, debug errors, generate examples, optimize code, and suggest solutions. Provide clear context and specific questions.
Code Example
# Ask ChatGPT to explain this code
bird_data = {
'Sparrow': 10,
'Eagle': 3,
'Hawk': 5
}
# ChatGPT can explain dictionary comprehension
total = sum(count for count in bird_data.values())
3.2 GitHub Copilot
Copilot is an AI pair programmer that suggests code in real-time.
Copilot uses machine learning to predict and suggest code. It understands context from comments and surrounding code. It can generate complete functions, suggest alternatives, and speed up development.
Code Example
# Type a comment and Copilot suggests code
# Function to count birds in a dictionary
# Copilot may generate:
def count_birds(bird_dict):
return sum(bird_dict.values())
3.3 AI Debugging
AI tools help identify and fix code errors quickly.
Provide error messages to AI for explanation. AI suggests fixes and explains why errors occurred. AI can recommend debugging techniques and best practices.
Code Example
# Error example
try:
print(bird_count) # NameError
except NameError as e:
print(f"Error: {e}")
# AI suggests: define bird_count before using it
3.4 AI Testing
AI can generate test cases and suggest testing strategies.
AI creates test cases for functions. AI suggests edge cases and boundary conditions. AI recommends testing frameworks and approaches.
Code Example
# Ask AI to generate test for this function
def add_birds(birds, count):
return birds + count
# AI might suggest:
def test_add_birds():
assert add_birds(10, 5) == 15
assert add_birds(0, 0) == 0
3.5 AI Refactoring
AI suggests code improvements and refactoring opportunities.
AI identifies code smells and suggests better patterns. AI recommends performance optimizations. AI suggests more Pythonic approaches.
Code Example
# Before refactoring
def get_bird_count(data):
total = 0
for key in data:
total = total + data[key]
return total
# After AI suggests:
def get_bird_count(data):
return sum(data.values())
Python Programming Basics
4.1 Python Syntax Rules
Python syntax defines the rules for writing valid Python code.
Python uses line breaks to separate statements. Indentation determines code blocks. Colons start blocks. Comments start with #. Python is case-sensitive.
Code Example
# Python syntax rules in action
# Indentation is crucial
def display_birds():
print("Sparrow: 10") # This is indented
print("Eagle: 3") # Same indentation level
if True:
print("Inside if") # Increased indentation
# Case sensitivity
bird = "Sparrow"
Bird = "Eagle" # Different variable
print(bird) # Sparrow
print(Bird) # Eagle
4.2 Indentation in Python
Indentation defines code blocks and structure in Python.
Python uses whitespace to indicate code grouping. 4 spaces is the standard. Tabs and spaces cannot be mixed. Consistent indentation is required. Incorrect indentation causes IndentationError.
Code Example
# Correct indentation
def count_birds():
print("Counting birds") # 4 spaces indentation
if True:
print("Inside if") # 8 spaces
return 0
# Incorrect indentation (will cause error)
# def bad_function():
# print("No indentation") # IndentationError
# Proper block indentation
for i in range(3):
print(f"Bird {i}") # Indented inside loop
print("Done") # Not indented - outside loop
4.3 Variables
Variables store data values that can change during program execution.
Variables are created when assigned. Python is dynamically typed. Variable names in Python must begin with a letter or an underscore (_). They cannot start with a number. Multiple assignments are allowed. Variables can be deleted with del.
Code Example
# Variable assignment
bird_count = 10 # Integer
bird_name = "Sparrow" # String
bird_weight = 25.5 # Float
is_migratory = True # Boolean
# Multiple assignment
eagle, hawk = 3, 5 # eagle=3, hawk=5
# Dynamic typing - variable can change type
bird = 10 # int
bird = "Ten" # str (now string)
# Deleting variables
del bird_count
# print(bird_count) # NameError - variable deleted
4.4 Naming Conventions
Naming conventions are rules for naming variables, functions, and classes.
snake_case for variables and functions. PascalCase for classes. ALL_CAPS for constants. Names should be descriptive. Avoid single letters except for loops. Avoid reserved keywords.
Code Example
# Variable naming conventions
bird_count = 10 # snake_case
BIRD_LIMIT = 100 # ALL_CAPS (constant)
# Function naming
def count_birds(): # snake_case
pass
# Class naming
class BirdCount: # PascalCase
pass
# Avoid reserved words as names
# class = "Bird" # ERROR: class is reserved
# Good descriptive names
sparrow_total = 10
eagle_population = 3
# Bad naming
# x = 10 # Not descriptive
# total = 10 # Not specific enough
4.5 Python Keywords
Keywords are reserved words with special meaning in Python.
Keywords include if, else, for, while, def, class, return, import, try, except, True, False, None. Keywords cannot be used as variable names. Python has 35 keywords.
Code Example
# Python keywords in action
# Keywords are highlighted in code editors
if True: # 'if' is a keyword
print("Yes")
else: # 'else' is a keyword
print("No")
def add(a, b): # 'def' is a keyword
return a + b # 'return' is a keyword
class Bird: # 'class' is a keyword
pass
# Cannot use keywords as variable names
# return = 10 # SyntaxError
# class = "Bird" # SyntaxError
4.6 Type Casting
Type casting converts one data type to another.
Implicit casting occurs automatically. Explicit casting is done manually using functions. Common casting functions include int(), float(), str(), list(), tuple(), dict(), set().
Code Example
# Implicit casting (automatic)
result = 10 + 5.5 # int + float = float
print(type(result)) # <class 'float'>
# Explicit casting (manual)
num_str = "10"
num_int = int(num_str) # Convert string to int
num_float = float(num_str) # Convert string to float
# Complex conversions
number = 123
text = str(number) # int to string
print(type(text)) # <class 'str'>
# List to tuple
bird_list = ["Sparrow", "Eagle"]
bird_tuple = tuple(bird_list)
print(type(bird_tuple)) # <class 'tuple'>
# Tuple to list
bird_tuple = ("Sparrow", "Eagle")
bird_list = list(bird_tuple)
print(type(bird_list)) # <class 'list'>
Data Types & Operators
5.1 Numeric Types (int, float, complex)
Numeric types handle numbers of different kinds in Python.
int: Whole numbers without decimal points. float: Numbers with decimal points. complex: Numbers with real and imaginary parts. Python supports large integers and scientific notation.
Code Example
# Integer (int)
sparrow_count = 10
eagle_count = -3
big_number = 1_000_000 # Underscores for readability
# Float (float)
bird_weight = 25.5
eagle_weight = 4.5
scientific = 1.2e-3 # 0.0012
# Complex (complex)
bird_complex = 3 + 4j
print(bird_complex.real) # 3.0
print(bird_complex.imag) # 4.0
# Type checking
print(type(10)) # <class 'int'>
print(type(10.5)) # <class 'float'>
print(type(3+4j)) # <class 'complex'>
5.2 Boolean Type
Boolean represents truth values in Python.
Boolean has two values: True and False. Boolean values are case-sensitive. True is 1 and False is 0 when used in arithmetic. Used for conditions and comparisons.
Code Example
# Boolean values
is_migrating = True
is_endangered = False
# Boolean from comparisons
has_birds = 10 > 5 # True
has_eagles = 3 > 5 # False
# Boolean arithmetic
print(True + True) # 2
print(True * 5) # 5
print(False + 3) # 3
# Boolean conditions
bird_count = 10
if bird_count > 5: # Condition evaluates to True
print("Many birds")
# Type checking
print(type(True)) # <class 'bool'>
print(type(False)) # <class 'bool'>
5.3 Sequence Types (string, list, tuple, range)
String
Strings are sequences of characters enclosed in quotes.
Strings can be enclosed in single, double, or triple quotes. Strings are immutable. They support indexing, slicing, and many methods. Unicode characters are supported.
Code Example
# String creation
bird1 = "Sparrow" # Double quotes
bird2 = 'Eagle' # Single quotes
bird3 = """Multi-line
bird
text""" # Triple quotes
# String indexing
bird = "Sparrow"
print(bird[0]) # 'S'
print(bird[-1]) # 'w'
# String slicing
print(bird[1:4]) # 'par'
print(bird[:3]) # 'Spa'
print(bird[3:]) # 'arrow'
# String immutability (cannot change)
# bird[0] = 'P' # ERROR: string immutable
bird = "P" + bird[1:] # Create new string
List
Lists are ordered, mutable sequences of elements.
Lists can contain mixed types. Lists are mutable (can change). Support indexing, slicing, and many methods. Lists are dynamic and can grow/shrink.
Code Example
# List creation
birds = ["Sparrow", "Eagle", "Hawk", "Cardinal"]
mixed = [1, "Bird", 3.14, True]
# List indexing
print(birds[0]) # Sparrow
print(birds[-1]) # Cardinal
# List slicing
print(birds[1:3]) # ['Eagle', 'Hawk']
print(birds[:2]) # ['Sparrow', 'Eagle']
# List methods
birds.append("Finch") # Add to end
birds.insert(1, "Robin") # Insert at position
birds.remove("Eagle") # Remove specific element
birds.pop() # Remove and return last element
birds.pop(1) # Remove at position
# List comprehensions
numbers = [1, 2, 3, 4]
squares = [x**2 for x in numbers] # [1, 4, 9, 16]
Tuple
Tuples are ordered, immutable sequences of elements.
Tuples are similar to lists but cannot be changed after creation. They are faster than lists and can be used as dictionary keys. Single element tuples need a comma.
Code Example
# Tuple creation
birds = ("Sparrow", "Eagle", "Hawk")
single_bird = ("Sparrow",) # Tuple with one element
# Accessing tuples
print(birds[0]) # Sparrow
print(birds[-1]) # Hawk
print(birds[1:3]) # ('Eagle', 'Hawk')
# Tuple immutability (cannot change)
# birds[0] = "Robin" # ERROR: tuple immutable
# Converting tuple to list (to modify)
bird_list = list(birds) # ['Sparrow', 'Eagle', 'Hawk']
bird_list.append("Robin")
birds = tuple(bird_list) # ('Sparrow', 'Eagle', 'Hawk', 'Robin')
# Tuple unpacking
a, b, c = birds[:3]
print(a, b, c) # Sparrow Eagle Hawk
Range
Range generates a sequence of numbers.
Range is used for iterating a specific number of times. It can have start, stop, and step parameters. Range is memory-efficient as it generates numbers on demand.
Code Example
# Range with one parameter (stop)
for i in range(5):
print(i) # 0, 1, 2, 3, 4
# Range with two parameters (start, stop)
for i in range(2, 6):
print(i) # 2, 3, 4, 5
# Range with three parameters (start, stop, step)
for i in range(0, 10, 2):
print(i) # 0, 2, 4, 6, 8
# Converting range to list
numbers = list(range(5)) # [0, 1, 2, 3, 4]
5.4 Set Types
Sets are unordered collections of unique elements.
Sets contain unique elements only. Sets are unordered (no indexing). Sets are mutable (can add/remove). Sets support mathematical operations like union and intersection. Sets cannot contain other sets (nested sets not allowed).
Code Example
# Set creation
birds = {"Sparrow", "Eagle", "Hawk", "Sparrow"} # {'Eagle', 'Hawk', 'Sparrow'}
# Using set constructor
birds = set(["Sparrow", "Eagle", "Hawk"])
# Adding elements
birds.add("Cardinal")
birds.update(["Robin", "Finch"])
# Removing elements
birds.remove("Eagle") # Raises error if not found
birds.discard("Parrot") # No error if not found
birds.pop() # Remove arbitrary element
# Set operations
set1 = {"Sparrow", "Eagle", "Hawk"}
set2 = {"Sparrow", "Robin", "Finch"}
print(set1.union(set2)) # Union
print(set1.intersection(set2)) # Intersection
print(set1.difference(set2)) # Difference
print(set1.symmetric_difference(set2)) # Symmetric difference
5.5 Mapping Type – Dictionary
Dictionaries store key-value pairs.
Dictionaries use keys to access values. Keys must be immutable (strings, numbers, tuples). Values can be any type. Duplicate keys take the last value. Dictionaries are unordered (Python 3.7+ preserves insertion order).
Code Example
# Dictionary creation
birds = {
"Sparrow": 10,
"Eagle": 3,
"Hawk": 5
}
# Using dict constructor
birds = dict(Sparrow=10, Eagle=3, Hawk=5)
# Accessing values
print(birds["Sparrow"]) # 10
print(birds.get("Eagle")) # 3
print(birds.get("Finch")) # None (no error)
# Adding/updating
birds["Robin"] = 8 # Add new
birds["Eagle"] = 4 # Update existing
# Duplicate key - last value taken
birds = {"Sparrow": 10, "Sparrow": 20} # {'Sparrow': 20}
# Dictionary methods
keys = birds.keys() # View keys
values = birds.values() # View values
items = birds.items() # View key-value pairs
# Nested dictionaries
bird_data = {
"Sparrow": {"count": 10, "weight": 25.5},
"Eagle": {"count": 3, "weight": 4500.0}
}
print(bird_data["Sparrow"]["count"]) # 10
5.6 Arithmetic Operators
Arithmetic operators perform mathematical calculations.
Operators include + (addition), - (subtraction), * (multiplication), / (division), // (floor division), % (modulo), ** (exponentiation).
Code Example
# Arithmetic operators
x = 10
y = 3
print(x + y) # 13
print(x - y) # 7
print(x * y) # 30
print(x / y) # 3.3333333333333335
print(x // y) # 3 (floor division)
print(x % y) # 1 (modulo/remainder)
print(x ** y) # 1000 (exponentiation)
# Order of operations
result = 2 + 3 * 4 # 14 (multiplication first)
result = (2 + 3) * 4 # 20 (parentheses first)
5.7 Comparison Operators
Comparison operators compare values and return Boolean results.
Operators include == (equal), != (not equal), > (greater than), < (less than), >= (greater or equal), <= (less or equal).
Code Example
a = 10
b = 20
c = 10
# Equal and not equal
print(a == b) # False
print(a == c) # True
print(a != b) # True
# Comparison
print(a > b) # False
print(a < b) # True
print(a >= c) # True
print(a <= b) # True
# String comparison
print("Sparrow" == "Sparrow") # True
print("Eagle" > "Hawk") # False (alphabetical)
5.8 Logical Operators
Logical operators combine boolean expressions.
Operators include and (both true), or (at least one true), not (invert). Short-circuit evaluation stops at first determining value.
Code Example
x = True
y = False
z = True
# Logical operations
print(x and y) # False
print(x and z) # True
print(x or y) # True
print(y or x) # True
print(not x) # False
print(not y) # True
# Short-circuit evaluation
def expensive_check():
print("Checking...")
return True
# and stops at first False
result = False and expensive_check() # expensive_check not called
# or stops at first True
result = True or expensive_check() # expensive_check not called
5.9 Assignment Operators
Assignment operators assign values and combine operations.
Operators include = (assign), +=, -=, *=, /=, //=, %=, **=. They perform operation and assignment in one step.
Code Example
# Basic assignment
birds = 10
# Compound assignment
birds += 5 # birds = birds + 5 = 15
birds -= 3 # birds = birds - 3 = 12
birds *= 2 # birds = birds * 2 = 24
birds /= 4 # birds = birds / 4 = 6.0
birds //= 2 # birds = birds // 2 = 3
birds %= 2 # birds = birds % 2 = 1
birds **= 3 # birds = birds ** 3 = 1
# Practical example
count = 10
count += 5
print(count) # 15
5.10 Bitwise Operators
Bitwise operators work on binary representations of integers.
Operators include & (AND), | (OR), ^ (XOR), ~ (NOT), << (left shift), >> (right shift). Used for low-level programming and flag manipulation.
Code Example
a = 5 # 0101 in binary
b = 3 # 0011 in binary
print(a & b) # 1 (0001)
print(a | b) # 7 (0111)
print(a ^ b) # 6 (0110)
print(~a) # -6 (two's complement)
print(a << 1) # 10 (1010)
print(a >> 1) # 2 (0010)
# Flags example
READ = 1 # 001
WRITE = 2 # 010
EXEC = 4 # 100
# Set read and write permission
permission = READ | WRITE # 3 (011)
print(permission & READ) # 1 (True)
print(permission & EXEC) # 0 (False)
5.11 Identity Operators
Identity operators check if two variables refer to the same object.
Operators include is and is not. They compare object identity, not value equality. is checks if two variables reference the same object in memory.
Code Example
a = [1, 2, 3]
b = [1, 2, 3]
c = a
# Identity vs equality
print(a == b) # True (same values)
print(a is b) # False (different objects)
print(a is c) # True (same object)
# With integers (Python caches small integers)
x = 10
y = 10
print(x is y) # True (small integers cached)
x = 1000
y = 1000
print(x is y) # False (larger integers not cached)
# None is a singleton
result = None
print(result is None) # True
print(result is not None) # False
5.12 Membership Operators
Membership operators check if an element exists in a sequence.
Operators include in and not in. Work with strings, lists, tuples, dictionaries (checks keys), and sets.
Code Example
# String membership
text = "Sparrow"
print('S' in text) # True
print('x' in text) # False
print('ar' in text) # True
# List membership
birds = ["Sparrow", "Eagle", "Hawk"]
print("Eagle" in birds) # True
print("Finch" in birds) # False
# Dictionary membership (checks keys)
data = {"Sparrow": 10, "Eagle": 3}
print("Sparrow" in data) # True
print(10 in data) # False (values not checked)
# Not in
print("Finch" not in birds) # True
Control Flow
6.1 Conditional Statements (if, if-else, elif ladder, nested conditions)
Conditional statements control program flow based on conditions.
The if statement executes a block of code when its specified condition evaluates to True. if-else provides an alternate block. elif (else-if) checks multiple conditions. Nested conditions place conditional blocks inside others.
Code Example
# Simple if
bird_count = 10
if bird_count > 5:
print("Many birds")
# if-else
if bird_count > 5:
print("Many birds")
else:
print("Few birds")
# elif ladder
if bird_count > 10:
print("Large flock")
elif bird_count > 5:
print("Medium flock")
elif bird_count > 0:
print("Small flock")
else:
print("No birds")
# Nested conditions
if bird_count > 0:
print("Birds present")
if bird_count > 10:
print("Large flock")
else:
print("Small flock")
else:
print("No birds present")
# Multiple conditions with logical operators
if bird_count > 0 and bird_count < 20:
print("Moderate flock")
6.2 Loops (for, while)
For Loop
The for loop iterates over sequences.
for loop works with iterables like strings, lists, tuples, dictionaries, and ranges. It’s used when the number of iterations is known or when iterating over a collection.
Code Example
# Iterating over a string
for bird in "Eagle":
print(bird)
# Iterating over a list
birds = ["Sparrow", "Eagle", "Hawk"]
for bird in birds:
print(bird)
# Iterating over a dictionary
bird_data = {"Sparrow": 10, "Eagle": 3}
for species, count in bird_data.items():
print(f"{species}: {count}")
# Using range
for i in range(5):
print(i) # 0, 1, 2, 3, 4
for i in range(2, 6): # 2, 3, 4, 5
print(i)
for i in range(0, 10, 2): # 0, 2, 4, 6, 8
print(i)
While Loop
The while loop repeats while a condition is true.
while loop continues until the condition becomes false. It’s used when the number of iterations is unknown or depends on a condition that changes during execution.
Code Example
# Basic while loop
count = 0
while count < 5:
print(count)
count += 1
# While with user input
birds = []
while True:
species = input("Enter bird (or 'done' to stop): ")
if species.lower() == "done":
break
birds.append(species)
# While with condition
bird_count = 10
while bird_count > 0:
print(bird_count)
bird_count -= 1
# Infinite loop (use carefully)
# while True:
# print("This runs forever")
6.3 Loop Control Statements (break, continue, pass)
Loop control statements modify loop execution flow.
break exits the loop entirely. continue skips current iteration and continues with next. pass does nothing (placeholder for code).
Code Example
# Break - exits loop early
birds = ["Sparrow", "Eagle", "Hawk", "Robin", "Finch"]
for bird in birds:
if bird == "Hawk":
break
print(bird) # Sparrow, Eagle (stops before Hawk)
# Continue - skips current iteration
for bird in birds:
if bird == "Hawk":
continue
print(bird) # Sparrow, Eagle, Robin, Finch (skips Hawk)
# Pass - placeholder (does nothing)
for bird in birds:
if bird == "Eagle":
pass # TODO: Add special handling for Eagles
else:
print(bird)
# Nested loops with break
for i in range(3):
for j in range(3):
if i == 1 and j == 1:
break # Breaks only inner loop
print(i, j)
# Practical example - find first occurrence
target = "Hawk"
for bird in birds:
if bird == target:
print(f"Found {target}")
break
else:
print(f"{target} not found")
Functions & Modular Programming
7.1 Defining Functions
Functions are reusable blocks of code that perform specific tasks.
Functions help organize code, avoid repetition, and enable reusability. They can take parameters and return values. Functions are defined with def keyword.
Code Example
# Simple function
def display_birds():
print("Sparrow")
print("Eagle")
print("Hawk")
# Call the function
display_birds()
# Function with parameters
def count_birds(sparrow_count, eagle_count):
total = sparrow_count + eagle_count
print(f"Total: {total}")
count_birds(10, 3)
# Function with return value
def get_total_birds(sparrow_count, eagle_count):
return sparrow_count + eagle_count
total = get_total_birds(10, 3)
print(total)
# Function with multiple returns
def get_bird_stats(sparrow_count, eagle_count):
total = sparrow_count + eagle_count
ratio = sparrow_count / eagle_count if eagle_count > 0 else 0
return total, ratio
total, ratio = get_bird_stats(10, 3)
7.2 Parameters & Arguments
Positional Arguments
Positional arguments are matched by position in function call.
Values are assigned to parameters in the order they’re passed. Required unless default values are provided.
Code Example
def bird_info(species, count, weight):
print(f"{species}: {count} birds, {weight}g")
# Positional arguments
bird_info("Sparrow", 10, 25.5) # Sparrow, 10, 25.5
Keyword Arguments
Keyword arguments are passed with parameter names.
Keyword arguments can be in any order. They make code more readable. Cannot follow positional arguments.
Code Example
def bird_info(species, count, weight):
print(f"{species}: {count} birds, {weight}g")
# Keyword arguments
bird_info(species="Sparrow", count=10, weight=25.5)
bird_info(count=10, weight=25.5, species="Sparrow")
# Mixing positional and keyword
bird_info("Sparrow", count=10, weight=25.5) # Valid
# bird_info(species="Sparrow", 10, 25.5) # Invalid
Default Arguments
Default arguments provide values when not specified.
Default values are assigned to parameters. Must be rightmost parameters. Evaluated once at function definition.
Code Example
def bird_info(species, count=0, weight=0.0):
print(f"{species}: {count} birds, {weight}g")
# Using defaults
bird_info("Sparrow") # count=0, weight=0.0
bird_info("Eagle", 3) # weight=0.0
bird_info("Hawk", 5, 1200.0) # All provided
# Default with list (caution)
def add_bird(bird, birds_list=[]): # Mutable default
birds_list.append(bird)
return birds_list
# This shares the default list across calls
print(add_bird("Sparrow")) # ['Sparrow']
print(add_bird("Eagle")) # ['Sparrow', 'Eagle']
# Better approach
def add_bird(bird, birds_list=None):
if birds_list is None:
birds_list = []
birds_list.append(bird)
return birds_list
Variable-Length Arguments
Variable-length arguments accept any number of arguments.
*args for positional arguments (tuple). **kwargs for keyword arguments (dictionary).
Code Example
# Variable positional arguments
def count_birds(*birds):
print(f"Birds seen: {len(birds)}")
for bird in birds:
print(bird)
count_birds("Sparrow", "Eagle") # 2 birds
count_birds("Sparrow", "Eagle", "Hawk") # 3 birds
# Variable keyword arguments
def display_bird_info(**bird_data):
for key, value in bird_data.items():
print(f"{key}: {value}")
display_bird_info(species="Sparrow", count=10)
display_bird_info(species="Eagle", count=3, weight=4500.0)
# Combined
def bird_report(*species, **stats):
print(f"Species: {species}")
print(f"Stats: {stats}")
bird_report("Sparrow", "Eagle", total=13, average=10.5)
7.3 Return Values
Functions return values using the return statement.
return ends function execution and returns a value. Functions without return return None. Multiple values can be returned as a tuple.
Code Example
# Single return
def get_total(a, b):
return a + b
result = get_total(10, 3)
print(result) # 13
# Multiple returns (tuple)
def get_bird_stats(sparrow_count, eagle_count):
total = sparrow_count + eagle_count
ratio = sparrow_count / eagle_count if eagle_count > 0 else 0
return total, ratio
total, ratio = get_bird_stats(10, 3)
print(total) # 13
print(ratio) # 3.333...
# No return (returns None)
def display_bird(bird):
print(f"Bird: {bird}")
result = display_bird("Sparrow")
print(result) # None
# Conditional returns
def get_bird_status(count):
if count == 0:
return "No birds"
elif count > 0 and count < 10:
return "Few birds"
else:
return "Many birds"
print(get_bird_status(5)) # Few birds
print(get_bird_status(0)) # No birds
7.4 Lambda Functions
Lambda functions are anonymous inline functions.
Lambda functions are defined with lambda keyword. They’re single-expression functions. Used where small functions are needed briefly.
Code Example
# Lambda function
square = lambda x: x**2
print(square(5)) # 25
# Lambda with filter
birds = ["Sparrow", "Eagle", "Hawk", "Robin"]
long_names = list(filter(lambda x: len(x) > 4, birds))
print(long_names) # ['Sparrow', 'Robin']
# Lambda with map
bird_counts = [10, 3, 5, 8]
doubled = list(map(lambda x: x * 2, bird_counts))
print(doubled) # [20, 6, 10, 16]
# Lambda with sorted
birds = ["Sparrow", "Eagle", "Hawk"]
sorted_birds = sorted(birds, key=lambda x: len(x))
print(sorted_birds) # ['Eagle', 'Hawk', 'Sparrow']
# Multiple parameters
add = lambda a, b: a + b
print(add(5, 3)) # 8
# Ternary lambda
max_val = lambda a, b: a if a > b else b
print(max_val(10, 5)) # 10
7.5 Recursion
Recursion is a function calling itself to solve problems.
Recursive functions have a base case (stopping condition) and recursive case (call itself with smaller problem). Used for problems with recursive structure like tree traversal.
Code Example
# Factorial using recursion
def factorial(n):
# Base case
if n <= 1:
return 1
# Recursive case
return n * factorial(n - 1)
print(factorial(5)) # 120
print(factorial(3)) # 6
# Fibonacci using recursion
def fibonacci(n):
# Base cases
if n <= 0:
return 0
elif n == 1:
return 1
# Recursive case
return fibonacci(n - 1) + fibonacci(n - 2)
print(fibonacci(6)) # 8
# List sum using recursion
def sum_list(numbers):
if not numbers:
return 0
return numbers[0] + sum_list(numbers[1:])
print(sum_list([1, 2, 3, 4])) # 10
# Factorial with recursion depth
import sys
sys.setrecursionlimit(1000) # Set recursion limit
# Recursion with direct calculation
def bird_count(n):
if n == 0:
return 0
return 1 + bird_count(n - 1)
print(bird_count(5)) # 5
Python Data Structures
8.1 Lists
Lists are mutable, ordered collections of elements.
Lists are created with brackets []. They can hold mixed types. Lists support indexing, slicing, and many methods.
Code Example
# List creation
birds = ["Sparrow", "Eagle", "Hawk", "Cardinal"]
mixed = [1, "Bird", 3.14, True]
# List methods
birds.append("Finch") # Add to end
birds.insert(1, "Robin") # Insert at position
birds.extend(["Dove", "Crow"]) # Add multiple
birds.remove("Eagle") # Remove specific
bird = birds.pop() # Remove and return last
bird = birds.pop(1) # Remove at position
birds.sort() # Sort in place
birds.reverse() # Reverse in place
# Indexing
print(birds[0]) # First
print(birds[-1]) # Last
# Slicing
print(birds[1:3]) # Elements 1-2
print(birds[:2]) # First two
print(birds[2:]) # From index 2
# List comprehension
numbers = [1, 2, 3, 4]
squares = [x**2 for x in numbers] # [1, 4, 9, 16]
evens = [x for x in numbers if x % 2 == 0] # [2, 4]
# Nested lists
birds_nest = [
["Sparrow", 10],
["Eagle", 3],
["Hawk", 5]
]
print(birds_nest[0][0]) # Sparrow
8.2 Tuples
Tuples are immutable, ordered collections of elements.
Tuples are created with parentheses (). They cannot be changed after creation. Faster than lists and can be dictionary keys.
Code Example
# Tuple creation
birds = ("Sparrow", "Eagle", "Hawk")
single = ("Sparrow",) # Comma required for single element
# Indexing and slicing
print(birds[0]) # Sparrow
print(birds[-1]) # Hawk
print(birds[1:3]) # ('Eagle', 'Hawk')
# Tuple operations
print(birds + ("Robin", "Finch")) # Concatenation
print(birds * 2) # Repetition
print(len(birds)) # Length
# Tuple unpacking
a, b, c = birds
print(a, b, c) # Sparrow Eagle Hawk
# Tuple as dictionary key
bird_data = {("Sparrow", 2024): 10, ("Eagle", 2024): 3}
# Converting tuple to list
bird_list = list(birds) # ['Sparrow', 'Eagle', 'Hawk']
bird_list.append("Robin")
birds = tuple(bird_list)
# Tuple methods
print(birds.count("Eagle")) # Count occurrences
print(birds.index("Eagle")) # Find index
8.3 Sets
Sets are unordered, mutable collections of unique elements.
Sets are created with braces {}. They contain unique elements only. No indexing (unordered). Support mathematical operations.
Code Example
# Set creation
birds = {"Sparrow", "Eagle", "Hawk", "Sparrow"} # {'Eagle', 'Hawk', 'Sparrow'}
# Using set constructor
birds = set(["Sparrow", "Eagle", "Hawk"])
# Adding and removing
birds.add("Cardinal")
birds.update(["Robin", "Finch"])
birds.remove("Eagle") # Raises error if not found
birds.discard("Parrot") # No error if not found
# Set operations
set1 = {"Sparrow", "Eagle", "Hawk"}
set2 = {"Sparrow", "Robin", "Finch"}
print(set1 | set2) # Union
print(set1 & set2) # Intersection
print(set1 - set2) # Difference
print(set1 ^ set2) # Symmetric difference
# Set comprehension
numbers = [1, 2, 2, 3, 3, 4]
unique = {x for x in numbers} # {1, 2, 3, 4}
# Membership testing
print("Eagle" in birds) # True
8.4 Dictionaries
Dictionaries store key-value pairs with fast lookup.
Dictionaries use keys to access values. Keys must be immutable. Duplicate keys take the last value. Python 3.7+ preserves insertion order.
Code Example
# Dictionary creation
birds = {
"Sparrow": 10,
"Eagle": 3,
"Hawk": 5
}
# Using dict constructor
birds = dict(Sparrow=10, Eagle=3, Hawk=5)
# Accessing values
print(birds["Sparrow"]) # 10
print(birds.get("Eagle")) # 3
print(birds.get("Finch", 0)) # 0 (default value)
# Adding and updating
birds["Robin"] = 8 # Add new
birds["Eagle"] = 4 # Update existing
# Dictionary methods
keys = birds.keys() # dict_keys(['Sparrow', 'Eagle', ...])
values = birds.values() # dict_values([10, 3, 5, ...])
items = birds.items() # dict_items([('Sparrow', 10), ...])
# Deleting items
del birds["Hawk"] # Remove key
popped = birds.pop("Eagle") # Remove and return
popped = birds.popitem() # Remove last item
# Nested dictionaries
bird_data = {
"Sparrow": {"count": 10, "weight": 25.5},
"Eagle": {"count": 3, "weight": 4500.0}
}
print(bird_data["Sparrow"]["count"]) # 10
# Dictionary comprehension
numbers = [1, 2, 3]
squares = {x: x**2 for x in numbers} # {1: 1, 2: 4, 3: 9}
Strings & Text Processing
9.1 String Basics (indexing, slicing)
Strings are sequences of characters with support for indexing and slicing.
Strings are immutable. Positive indexing starts at 0. Negative indexing starts at -1. Slicing creates new strings.
Code Example
# String creation with different quotes
single = 'Sparrow'
double = "Eagle"
triple = """Multi-line
bird
text"""
# Positive indexing
bird = "Sparrow"
print(bird[0]) # S
print(bird[3]) # r
print(bird[6]) # w
# Negative indexing
print(bird[-1]) # w
print(bird[-3]) # r
# Slicing
print(bird[1:4]) # par
print(bird[:3]) # Spa
print(bird[3:]) # row
print(bird[::2]) # S r w (jump by 2)
print(bird[::-1]) # worrapS (reverse)
# Check membership
print('S' in "Sparrow") # True
print('x' in "Sparrow") # False
# Length
print(len("Sparrow")) # 7
9.2 String Methods (upper, lower, split, join, replace, etc.)
String methods provide common operations on strings.
Methods include upper(), lower(), split(), join(), replace(), find(), count(), strip(), etc.
Code Example
bird = " Sparrow "
# Case conversion
print(bird.upper()) # " SPARROW "
print(bird.lower()) # " sparrow "
print(bird.title()) # " Sparrow "
# Whitespace removal
print(bird.strip()) # "Sparrow"
print(bird.lstrip()) # "Sparrow "
print(bird.rstrip()) # " Sparrow"
# Searching
text = "The eagle soared high"
print(text.find("eagle")) # 4 (position)
print(text.find("hawk")) # -1 (not found)
print(text.count("e")) # 3
# Replacement
print(text.replace("eagle", "hawk")) # "The hawk soared high"
# Split and join
words = text.split() # ['The', 'eagle', 'soared', 'high']
joined = "-".join(words) # "The-eagle-soared-high"
# Checking
print("Sparrow".startswith("S")) # True
print("Sparrow".endswith("w")) # True
print("Sparrow".isalpha()) # True
print("123".isdigit()) # True
# Title and capitalize
print("hello world".title()) # "Hello World"
print("hello world".capitalize()) # "Hello world"
9.3 String Formatting (f-strings, format() method)
String formatting inserts values into strings.
f-strings (Python 3.6+) are the modern preferred method. .format() is the older method. % formatting is the oldest method.
Code Example
# f-strings (recommended)
species = "Sparrow"
count = 10
weight = 25.5
print(f"Bird: {species}") # Bird: Sparrow
print(f"Count: {count}, Weight: {weight}g") # Count: 10, Weight: 25.5g
print(f"{species}: {count:.2f} birds") # Sparrow: 10.00 birds
# Expressions in f-strings
print(f"Double: {count * 2}") # Double: 20
print(f"Total: {count + 5}") # Total: 15
# .format() method
print("Bird: {}".format(species)) # Bird: Sparrow
print("Count: {}, Weight: {}g".format(count, weight))
# Positional and keyword arguments
print("{1} {0}".format("Sparrow", "Eagle")) # Eagle Sparrow
print("{species}: {count}".format(species="Eagle", count=3))
# % formatting (older)
print("Bird: %s" % species) # Bird: Sparrow
print("Count: %d, Weight: %.2f" % (count, weight))
# Alignment and padding
print(f"{species:>10}") # Right align
print(f"{species:<10}") # Left align
print(f"{species:^10}") # Center
9.4 Regular Expressions (re module)
Regular expressions provide pattern matching for text.
The re module provides regex functionality. Patterns use special characters for matching. Used for validation, searching, and replacement.
Code Example
import re
text = "Sparrow 10, Eagle 3, Hawk 5"
# Search
match = re.search(r'Eagle', text)
print(match.group()) # Eagle
# Find all
birds = re.findall(r'\w+', text) # ['Sparrow', '10', 'Eagle', '3', 'Hawk', '5']
numbers = re.findall(r'\d+', text) # ['10', '3', '5']
# Find pattern with groups
pattern = r'(\w+)\s+(\d+)'
matches = re.findall(pattern, text)
for bird, count in matches:
print(f"{bird}: {count}")
# Substitution
replaced = re.sub(r'\d+', 'X', text) # "Sparrow X, Eagle X, Hawk X"
# Compile pattern for efficiency
pattern = re.compile(r'\b[A-Z][a-z]+\b')
birds = pattern.findall(text) # ['Sparrow', 'Eagle', 'Hawk']
# Check if string matches
email_pattern = r'^[\w\.-]+@[\w\.-]+\.\w+$'
print(bool(re.match(email_pattern, 'bird@example.com'))) # True
Modules & Packages
10.1 Creating Modules
Modules are Python files containing reusable code.
Any .py file is a module. Modules organize code, avoid duplication, and provide namespaces. They can contain functions, classes, and variables.
Code Example
# bird_module.py (module file)
"""Module containing bird-related functions and classes"""
# Constants
MAX_BIRDS = 100
# Variables
bird_types = ["Sparrow", "Eagle", "Hawk"]
# Functions
def count_birds(birds_dict):
"""Count total birds in dictionary"""
return sum(birds_dict.values())
# Classes
class Bird:
def __init__(self, species, count):
self.species = species
self.count = count
def display(self):
print(f"{self.species}: {self.count}")
10.2 Importing Modules
Importing allows using code from other modules.
import brings module into current namespace. from imports specific items. as creates aliases.
Code Example
# Import entire module
import bird_module
print(bird_module.MAX_BIRDS)
bird_module.count_birds({"Sparrow": 10, "Eagle": 3})
# Import specific items
from bird_module import count_birds, Bird
print(count_birds({"Sparrow": 10, "Eagle": 3}))
b = Bird("Hawk", 5)
# Import with alias
import bird_module as bm
print(bm.MAX_BIRDS)
# Import all items (not recommended)
from bird_module import *
print(MAX_BIRDS)
# Built-in module import
import math
import random
import datetime
10.3 Built-in Modules (math, random, datetime, os, sys)
Built-in modules provide common functionality without installation.
math: Mathematical operations. random: Random number generation. datetime: Date and time operations. os: Operating system interactions. sys: System-specific parameters.
Code Example
# math module
import math
print(math.pi) # 3.14159
print(math.sqrt(16)) # 4.0
print(math.factorial(5)) # 120
print(math.pow(2, 3)) # 8.0
# random module
import random
print(random.random()) # Random float 0-1
print(random.randint(1, 10)) # Random integer 1-10
birds = ["Sparrow", "Eagle", "Hawk"]
print(random.choice(birds)) # Random choice
random.shuffle(birds) # Shuffle list
# datetime module
import datetime
now = datetime.datetime.now()
print(now)
print(now.year, now.month, now.day)
delta = datetime.timedelta(days=7)
print(now + delta)
# os module
import os
print(os.getcwd()) # Current directory
# os.mkdir("new_folder") # Create directory
print(os.listdir(".")) # List files
# sys module
import sys
print(sys.version) # Python version
print(sys.platform) # Operating system
10.4 Creating Packages
Packages organize related modules in directories.
A package is a directory with __init__.py file. Packages can have sub-packages. They provide hierarchical organization.
Code Example
# Directory structure
bird_package/
__init__.py
birds.py
data/
__init__.py
bird_data.py
utils/
__init__.py
helpers.py
# __init__.py (makes directory a package)
# Can contain initialization code
# birds.py (module in package)
def count_birds(birds_dict):
return sum(birds_dict.values())
# Importing from package
from bird_package import birds
from bird_package.data import bird_data
from bird_package.utils import helpers
# Using package
birds.count_birds({"Sparrow": 10, "Eagle": 3})
Object-Oriented Programming (OOP)
11.1 Classes & Objects
Classes are blueprints for objects. Objects are instances of classes.
Classes define attributes (data) and methods (functions). Objects are concrete instances with specific values. Classes enable encapsulation and code organization.
Code Example
# Class definition
class Bird:
# Class attribute (shared by all instances)
species_count = 0
# Constructor (initialize object)
def __init__(self, species, count):
self.species = species # Instance attribute
self.count = count # Instance attribute
Bird.species_count += 1 # Update class attribute
# Method (function in class)
def display(self):
print(f"{self.species}: {self.count} birds")
def add_birds(self, number):
self.count += number
print(f"Added {number}. New count: {self.count}")
# Creating objects (instances)
sparrow = Bird("Sparrow", 10)
eagle = Bird("Eagle", 3)
# Using objects
sparrow.display() # Sparrow: 10 birds
eagle.display() # Eagle: 3 birds
print(Bird.species_count) # 2
# Modify object
sparrow.add_birds(5) # Added 5. New count: 15
sparrow.display() # Sparrow: 15 birds
# Accessing attributes
print(sparrow.species) # Sparrow
print(sparrow.count) # 15
11.2 Constructors (init)
__init__ is the constructor method called when creating objects.
The constructor initializes object attributes. It’s called automatically. Can have parameters for custom initialization.
Code Example
class Bird:
def __init__(self, species, count, weight=0.0):
self.species = species
self.count = count
self.weight = weight
self.is_active = True
print(f"Bird {species} created")
def display(self):
print(f"{self.species}: {self.count} birds, {self.weight}g")
# Creating objects with different parameters
sparrow = Bird("Sparrow", 10, 25.5)
eagle = Bird("Eagle", 3) # Uses default weight
hawk = Bird("Hawk", 5)
sparrow.display()
eagle.display()
11.3 Encapsulation (private variables)
Encapsulation hides internal data and exposes controlled access.
Private variables use double underscore __ prefix. They’re name-mangled to prevent accidental access. Getters and setters control access.
Code Example
class Bird:
def __init__(self, species, count):
self.species = species
self.__count = count # Private variable
self.__weight = 0.0 # Private variable
# Getter
def get_count(self):
return self.__count
# Setter with validation
def set_count(self, count):
if count >= 0:
self.__count = count
else:
print("Error: Count cannot be negative")
# Getter
def get_weight(self):
return self.__weight
# Setter with validation
def set_weight(self, weight):
if weight > 0:
self.__weight = weight
else:
print("Error: Weight must be positive")
def display(self):
print(f"{self.species}: {self.__count} birds, {self.__weight}g")
# Usage
sparrow = Bird("Sparrow", 10)
print(sparrow.species) # Sparrow (public)
# print(sparrow.__count) # Error: private
print(sparrow.get_count()) # 10 (access via getter)
sparrow.set_count(15) # Modify via setter
sparrow.set_weight(25.5) # Set weight
sparrow.display()
11.4 Inheritance
Inheritance creates a hierarchy of classes that share attributes and methods.
Child classes inherit from parent classes. They can override methods and add new ones. super() calls parent methods.
Code Example
# Parent class
class Bird:
def __init__(self, species, count):
self.species = species
self.count = count
def fly(self):
print(f"{self.species} is flying")
def display(self):
print(f"{self.species}: {self.count} birds")
# Child class (inherits from Bird)
class Eagle(Bird):
def __init__(self, species, count, wingspan):
super().__init__(species, count) # Call parent constructor
self.wingspan = wingspan # New attribute
def hunt(self): # New method
print(f"{self.species} is hunting")
def fly(self): # Override method
print(f"{self.species} soars with {self.wingspan}m wingspan")
def display(self): # Override method
super().display() # Call parent method
print(f"Wingspan: {self.wingspan}m")
# Another child class
class Sparrow(Bird):
def chirp(self):
print(f"{self.species} chirps: Chirp chirp!")
# Usage
eagle = Eagle("Golden Eagle", 3, 2.3)
sparrow = Sparrow("House Sparrow", 10)
# Inherited methods
eagle.display() # Calls overridden method
eagle.fly() # Calls overridden method
sparrow.fly() # Inherited method
# New methods
eagle.hunt() # Eagle-specific
sparrow.chirp() # Sparrow-specific
11.5 Polymorphism
Polymorphism allows different objects to respond to the same method call in their own way, enabling the same interface to work with different implementations.
Different classes can have methods with the same name. The correct method is determined at runtime. Enables flexible code design.
Code Example
class Bird:
def speak(self):
return "Generic bird sound"
class Eagle(Bird):
def speak(self):
return "Screech!"
class Sparrow(Bird):
def speak(self):
return "Chirp chirp!"
class Parrot(Bird):
def speak(self):
return "Hello! I can talk!"
def bird_sound(bird):
"""Function that works with any bird"""
print(bird.speak())
# Creating different birds
birds = [
Eagle(),
Sparrow(),
Parrot(),
Bird()
]
# Polymorphism in action
for bird in birds:
bird_sound(bird)
# Output:
# Screech!
# Chirp chirp!
# Hello! I can talk!
# Generic bird sound
# Function expecting any bird type
def report_bird(bird):
print(f"Bird says: {bird.speak()}")
11.6 Abstraction (abstract classes)
Abstract classes define interfaces that must be implemented by derived classes.
Abstract classes cannot be instantiated. They contain abstract methods that derived classes must implement. They define a contract for subclasses.
Code Example
from abc import ABC, abstractmethod
# Abstract class
class Bird(ABC):
@abstractmethod
def fly(self):
"""All birds must fly"""
pass
@abstractmethod
def speak(self):
"""All birds must speak"""
pass
def display(self):
print("This is a bird")
# Concrete class implementing Bird
class Eagle(Bird):
def fly(self):
print("Eagle soars high")
def speak(self):
print("Screech!")
class Sparrow(Bird):
def fly(self):
print("Sparrow flutters")
def speak(self):
print("Chirp chirp!")
# Cannot instantiate abstract class
# bird = Bird() # TypeError
# Can instantiate concrete classes
eagle = Eagle()
sparrow = Sparrow()
# All birds have same interface
def bird_actions(bird):
bird.fly()
bird.speak()
bird_actions(eagle) # Eagle soars high, Screech!
bird_actions(sparrow) # Sparrow flutters, Chirp chirp!
File Handling
12.1 Reading Files
Reading files extracts data from text files.
Files are opened, read, and closed. Various reading methods are available. Context managers (with) handle file closing automatically.
Code Example
# Method 1: read entire file
with open('birds.txt', 'r') as file:
content = file.read()
print(content)
# Method 2: read lines
with open('birds.txt', 'r') as file:
lines = file.readlines()
for line in lines:
print(line.strip())
# Method 3: iterate over file
with open('birds.txt', 'r') as file:
for line in file:
print(line.strip())
# Method 4: read specific number of characters
with open('birds.txt', 'r') as file:
data = file.read(10)
print(data)
12.2 Writing Files
Writing files saves data to text files.
write() writes a string. writelines() writes multiple lines. a mode appends to existing file.
Code Example
# Write to file (overwrites existing)
with open('birds.txt', 'w') as file:
file.write("Sparrow, Eagle, Hawk\n")
file.write("Finch, Robin, Cardinal\n")
# Write multiple lines
lines = ["Sparrow, Eagle, Hawk\n", "Finch, Robin, Cardinal\n"]
with open('birds.txt', 'w') as file:
file.writelines(lines)
# Append to file
with open('birds.txt', 'a') as file:
file.write("Dove, Crow\n")
# Write with format
bird_data = {"Sparrow": 10, "Eagle": 3, "Hawk": 5}
with open('bird_counts.txt', 'w') as file:
for species, count in bird_data.items():
file.write(f"{species}: {count}\n")
12.3 File Modes
File modes specify how to open files.
Common modes: 'r' (read), 'w' (write), 'a' (append), 'x' (exclusive creation), 'r+' (read and write), 'b' (binary mode).
Code Example
# Read mode
with open('file.txt', 'r') as file:
content = file.read()
# Write mode (overwrite)
with open('file.txt', 'w') as file:
file.write("New content")
# Append mode (add to end)
with open('file.txt', 'a') as file:
file.write("Additional content")
# Read and write mode
with open('file.txt', 'r+') as file:
content = file.read()
file.write("Appended")
# Binary mode
with open('image.jpg', 'rb') as file:
binary_data = file.read()
# Exclusive creation (fails if file exists)
try:
with open('new_file.txt', 'x') as file:
file.write("New file created")
except FileExistsError:
print("File already exists")
12.4 Working with CSV Files
CSV files store tabular data with comma-separated values.
The csv module handles CSV operations. reader reads CSV files. writer writes CSV files. DictReader and DictWriter use dictionaries.
Code Example
import csv
# Writing CSV
bird_data = [
['Species', 'Count', 'Weight'],
['Sparrow', '10', '25.5'],
['Eagle', '3', '4500.0'],
['Hawk', '5', '1200.0']
]
with open('birds.csv', 'w', newline='') as file:
writer = csv.writer(file)
writer.writerows(bird_data)
# Reading CSV
with open('birds.csv', 'r') as file:
reader = csv.reader(file)
for row in reader:
print(row)
# Using DictWriter
fieldnames = ['Species', 'Count', 'Weight']
with open('birds_dict.csv', 'w', newline='') as file:
writer = csv.DictWriter(file, fieldnames=fieldnames)
writer.writeheader()
writer.writerow({'Species': 'Sparrow', 'Count': '10', 'Weight': '25.5'})
# Using DictReader
with open('birds_dict.csv', 'r') as file:
reader = csv.DictReader(file)
for row in reader:
print(row['Species'], row['Count'])
12.5 Working with JSON Files
JSON files store structured data in JavaScript Object Notation format.
JSON is human-readable and language-independent. json module handles serialization and deserialization. dump writes JSON, load reads JSON.
Code Example
import json
# JSON data
bird_data = {
"Sparrow": {"count": 10, "weight": 25.5},
"Eagle": {"count": 3, "weight": 4500.0},
"Hawk": {"count": 5, "weight": 1200.0}
}
# Write JSON to file
with open('birds.json', 'w') as file:
json.dump(bird_data, file, indent=4)
# Read JSON from file
with open('birds.json', 'r') as file:
loaded_data = json.load(file)
print(loaded_data)
# JSON to Python object (loads)
json_string = '{"Sparrow": 10, "Eagle": 3}'
data = json.loads(json_string)
print(data)
# Python object to JSON (dumps)
python_data = {"Sparrow": 10, "Eagle": 3}
json_string = json.dumps(python_data, indent=2)
print(json_string)
# Handling dates in JSON
from datetime import datetime
data = {"date": datetime.now().isoformat()}
with open('date.json', 'w') as file:
json.dump(data, file)
Error Handling (Exceptions)
13.1 try, except
try-except blocks handle runtime errors gracefully.
Code that might cause errors goes in try block. Error handling goes in except blocks. Multiple exception types can be caught.
Code Example
# Basic try-except
try:
birds = [10, 20, 30]
print(birds[5]) # IndexError
except:
print("Error occurred")
# Catching specific exceptions
try:
count = int("abc") # ValueError
except ValueError:
print("Invalid number")
# Multiple except blocks
try:
birds = [10, 20, 30]
print(birds[5])
except IndexError:
print("Index out of range")
except ValueError:
print("Invalid value")
# Exception with variable
try:
bird_count = int(input("Enter count: "))
except ValueError as e:
print(f"Error: {e}")
# Multiple exceptions in one block
try:
bird_count = int("abc")
except (ValueError, TypeError) as e:
print(f"Error: {e}")
# try with else (runs if no error)
try:
bird_count = 10
except:
print("Error occurred")
else:
print("No error, count is", bird_count)
13.2 finally
finally block executes regardless of errors.
finally runs whether an exception occurred or not. Used for cleanup operations like closing files or connections.
Code Example
# Basic finally
try:
bird_count = 10
print("Processing")
except:
print("Error")
finally:
print("Always executes")
# File handling with finally
file = None
try:
file = open('birds.txt', 'r')
content = file.read()
except FileNotFoundError:
print("File not found")
finally:
if file:
file.close() # Ensure file closes
print("File closed")
# Better approach - with context manager
try:
with open('birds.txt', 'r') as file:
content = file.read()
except FileNotFoundError:
print("File not found")
# Cleaning up resources
def process_birds():
try:
print("Processing birds")
return 10 # Return value
finally:
print("Cleanup executed")
result = process_birds() # "Cleanup executed" before return
print(result) # 10
13.3 raise
raise manually triggers exceptions.
raise is used to signal errors. Can create and raise custom exceptions. Exceptions propagate to calling code.
Code Example
# Raising built-in exception
def check_bird_count(count):
if count < 0:
raise ValueError("Count cannot be negative")
return count
try:
check_bird_count(-5)
except ValueError as e:
print(f"Error: {e}")
# Raising with custom message
def get_bird(species):
if species == "":
raise Exception("Species cannot be empty")
return species
# Re-raising exception
try:
bird_count = int("abc")
except ValueError:
print("Invalid input")
raise # Re-raise the exception
# Custom validation
def validate_bird_data(species, count):
if not species:
raise ValueError("Species required")
if count <= 0:
raise ValueError("Count must be positive")
return True
try:
validate_bird_data("", 10)
except ValueError as e:
print(f"Validation error: {e}")
13.4 Custom Exceptions
Custom exceptions are user-defined exception classes.
Custom exceptions inherit from Exception. They can have additional attributes and methods. They provide specific error types.
Code Example
# Custom exception class
class BirdError(Exception):
"""Base class for bird-related errors"""
pass
class BirdNotFoundError(BirdError):
"""Raised when a bird is not found"""
def __init__(self, species):
self.species = species
self.message = f"Bird {species} not found"
super().__init__(self.message)
class BirdCountError(BirdError):
"""Raised when bird count is invalid"""
def __init__(self, count, message="Invalid count"):
self.count = count
self.message = f"{message}: {count}"
super().__init__(self.message)
# Using custom exceptions
def get_bird_count(species, bird_data):
if species not in bird_data:
raise BirdNotFoundError(species)
return bird_data[species]
def set_bird_count(species, count):
if count < 0:
raise BirdCountError(count, "Count cannot be negative")
print(f"{species}: {count}")
# Handling custom exceptions
bird_data = {"Sparrow": 10, "Eagle": 3}
try:
print(get_bird_count("Hawk", bird_data))
except BirdNotFoundError as e:
print(f"Error: {e}")
try:
set_bird_count("Sparrow", -5)
except BirdCountError as e:
print(f"Error: {e}")
# Catching specific exceptions
try:
get_bird_count("Finch", bird_data)
except BirdNotFoundError as e:
print(f"Bird not found: {e.species}")
except BirdError as e:
print(f"General bird error: {e}")
Advanced Python
14.1 Decorators
Decorators modify or enhance functions without changing their code.
Decorators are higher-order functions. They wrap functions with additional behavior. Used for logging, timing, authentication, etc.
Code Example
# Basic decorator
def timer(func):
import time
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"{func.__name__} took {end - start:.4f} seconds")
return result
return wrapper
@timer
def count_birds():
total = 0
for i in range(1000000):
total += i
return total
count_birds() # Prints timing info
# Decorator with parameters
def repeat(times):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(times):
func(*args, **kwargs)
return wrapper
return decorator
@repeat(3)
def bird():
print("Bird!")
bird() # Prints "Bird!" 3 times
# Practical decorator - logging
def log_function(func):
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__} with {args}")
result = func(*args, **kwargs)
print(f"{func.__name__} returned {result}")
return result
return wrapper
@log_function
def add_birds(a, b):
return a + b
add_birds(10, 5)
# Multiple decorators
@timer
@log_function
def process_birds():
return 42
14.2 Generators (yield)
Generators produce values lazily using yield.
Generators create iterators. They generate values on demand, saving memory. yield pauses and resumes function execution.
Code Example
# Basic generator
def count_birds():
yield "Sparrow"
yield "Eagle"
yield "Hawk"
birds = count_birds()
print(next(birds)) # Sparrow
print(next(birds)) # Eagle
print(next(birds)) # Hawk
# Generator with loop
def bird_generator(n):
for i in range(n):
yield f"Bird {i}"
for bird in bird_generator(5):
print(bird)
# Infinite generator
def infinite_birds():
count = 0
while True:
count += 1
yield f"Bird {count}"
bird_gen = infinite_birds()
print(next(bird_gen)) # Bird 1
print(next(bird_gen)) # Bird 2
print(next(bird_gen)) # Bird 3
# Generator expression
numbers = (x**2 for x in range(10))
for num in numbers:
print(num)
# Practical - reading large file
def read_large_file(file_path):
with open(file_path, 'r') as file:
for line in file:
yield line.strip()
# for line in read_large_file('big_file.txt'):
# process(line)
# Generator with multiple yields
def multiple_yields():
print("First yield")
yield 1
print("Second yield")
yield 2
print("Third yield")
yield 3
for value in multiple_yields():
print(value)
14.3 Iterators
Iterators provide sequential access to collections.
Iterators implement __iter__() and __next__(). They’re used with for loops. Custom iterators can be created.
Code Example
# Basic iterator example
birds = ["Sparrow", "Eagle", "Hawk"]
iterator = iter(birds)
print(next(iterator)) # Sparrow
print(next(iterator)) # Eagle
print(next(iterator)) # Hawk
# Custom iterator
class BirdIterator:
def __init__(self, birds):
self.birds = birds
self.index = 0
def __iter__(self):
return self
def __next__(self):
if self.index >= len(self.birds):
raise StopIteration
bird = self.birds[self.index]
self.index += 1
return bird
birds = ["Sparrow", "Eagle", "Hawk"]
bird_iter = BirdIterator(birds)
for bird in bird_iter:
print(bird)
# Using iter with built-in functions
text = "Eagle"
letter_iter = iter(text)
print(list(letter_iter)) # ['E', 'a', 'g', 'l', 'e']
# Creating iterator from range
range_iter = iter(range(3))
print(next(range_iter)) # 0
print(next(range_iter)) # 1
14.4 Context Managers
Context managers manage resources using with statements.
Context managers set up and tear down resources automatically. They use __enter__ and __exit__ methods. The with statement ensures proper cleanup.
Code Example
# File context manager (built-in)
with open('file.txt', 'w') as file:
file.write("Hello")
# Custom context manager using class
class BirdContext:
def __enter__(self):
print("Setting up bird context")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("Cleaning up bird context")
def count(self):
print("Counting birds")
with BirdContext() as bc:
bc.count()
# Custom context manager using contextlib
from contextlib import contextmanager
@contextmanager
def bird_manager():
print("Entering")
try:
yield "Bird data"
finally:
print("Exiting")
with bird_manager() as data:
print(f"Processing: {data}")
# Practical - database connection
@contextmanager
def database_connection():
print("Connecting to database")
conn = "Database connection"
try:
yield conn
finally:
print("Closing database connection")
with database_connection() as db:
print(f"Using {db}")
14.5 Multithreading
Multithreading runs multiple threads concurrently.
Threads allow parallel execution within a single process. threading module provides thread management. Useful for I/O-bound tasks.
Code Example
import threading
import time
# Basic thread
def count_birds(count):
for i in range(count):
print(f"Bird {i} from thread {threading.current_thread().name}")
time.sleep(0.1)
# Create and start threads
thread1 = threading.Thread(target=count_birds, args=(3,))
thread2 = threading.Thread(target=count_birds, args=(3,))
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print("All threads complete")
# Thread with shared resource
counter = 0
lock = threading.Lock()
def increment():
global counter
for _ in range(1000):
with lock: # Thread-safe operation
counter += 1
threads = []
for _ in range(10):
t = threading.Thread(target=increment)
threads.append(t)
t.start()
for t in threads:
t.join()
print(f"Counter: {counter}") # Should be 10000
# Thread with arguments
def bird_thread(species, count):
print(f"{species}: {count}")
t = threading.Thread(target=bird_thread, args=("Sparrow", 10))
t.start()
t.join()
14.6 Multiprocessing
Multiprocessing runs multiple processes for CPU-intensive tasks.
Processes have separate memory space. multiprocessing module provides process management. Bypasses GIL for true parallelism.
Code Example
import multiprocessing
import time
# CPU-intensive task
def count_birds_heavy(count):
total = 0
for i in range(count):
total += i
return total
# Using Process
def process_function(start, end):
total = 0
for i in range(start, end):
total += i
return total
with multiprocessing.Pool() as pool:
results = pool.map(count_birds_heavy, [1000000, 1000000])
print(results)
# Process pool
def compute_bird_data(n):
return sum(range(n))
if __name__ == "__main__":
with multiprocessing.Pool(processes=4) as pool:
data = [1000000, 2000000, 3000000, 4000000]
results = pool.map(compute_bird_data, data)
print(results)
# Shared memory
import multiprocessing as mp
def worker(shared_list):
shared_list.append("Bird")
if __name__ == "__main__":
manager = mp.Manager()
shared_list = manager.list()
processes = []
for _ in range(5):
p = mp.Process(target=worker, args=(shared_list,))
processes.append(p)
p.start()
for p in processes:
p.join()
print(shared_list)
14.7 Async Programming (asyncio)
Async programming handles concurrent operations without threads.
asyncio enables asynchronous programming. async/await syntax for coroutines. Ideal for I/O-bound, network, and database operations.
Code Example
import asyncio
import time
# Basic async function
async def bird_async():
print("Bird starts")
await asyncio.sleep(1)
print("Bird finishes")
return "Result"
# Run async function
result = asyncio.run(bird_async())
print(result)
# Multiple async tasks
async def count_birds(species, delay):
await asyncio.sleep(delay)
print(f"Counted {species} after {delay}s")
return f"{species}: done"
async def main():
tasks = [
count_birds("Sparrow", 2),
count_birds("Eagle", 1),
count_birds("Hawk", 3)
]
results = await asyncio.gather(*tasks)
print(results)
asyncio.run(main())
# Async with asyncio.create_task
async def process():
task1 = asyncio.create_task(count_birds("Sparrow", 2))
task2 = asyncio.create_task(count_birds("Eagle", 1))
await task1
await task2
# Async context manager
async def async_context():
async with asyncio.timeout(2):
await asyncio.sleep(1)
print("Success")
print("Done")
asyncio.run(async_context())
Data Structures & Algorithms in Python
15.1 Complexity Analysis (Time, Space, Big-O)
Complexity analysis measures algorithm efficiency.
Time complexity describes how an algorithm’s running time changes as the input size grows. Space complexity describes how its memory usage changes with input size. Big-O notation expresses the growth rate of an algorithm’s time or space requirements.
Code Example
# O(1) - Constant time
def get_first_bird(birds):
return birds[0] # Always same time
# O(n) - Linear time
def find_bird(birds, target):
for bird in birds:
if bird == target:
return True
return False
# O(log n) - Logarithmic
def binary_search(birds, target):
left, right = 0, len(birds) - 1
while left <= right:
mid = (left + right) // 2
if birds[mid] == target:
return True
elif birds[mid] < target:
left = mid + 1
else:
right = mid - 1
return False
# O(n²) - Quadratic
def find_duplicates(birds):
duplicates = []
for i in range(len(birds)):
for j in range(i + 1, len(birds)):
if birds[i] == birds[j]:
duplicates.append(birds[i])
return duplicates
# O(n log n) - Linearithmic
def sort_birds(birds):
return sorted(birds) # Timsort is O(n log n)
# Analyzing complexity
def sum_list(numbers):
total = 0 # O(1)
for n in numbers: # O(n)
total += n
return total # O(1)
# Total: O(n)
15.2 Stack (LIFO)
Stack is a LIFO (Last-In-First-Out) data structure.
Stack operations: push (add to top), pop (remove from top), peek (view top). Implemented with list in Python.
Code Example
# Stack implementation using list
class BirdStack:
def __init__(self):
self.items = []
def push(self, bird):
self.items.append(bird)
print(f"Pushed: {bird}")
def pop(self):
if not self.is_empty():
return self.items.pop()
print("Stack is empty!")
return None
def peek(self):
if not self.is_empty():
return self.items[-1]
return None
def is_empty(self):
return len(self.items) == 0
def size(self):
return len(self.items)
def display(self):
print("Stack:", self.items)
# Using stack
stack = BirdStack()
stack.push("Sparrow")
stack.push("Eagle")
stack.push("Hawk")
print("Top:", stack.peek()) # Hawk
print("Pop:", stack.pop()) # Hawk
print("Top:", stack.peek()) # Eagle
# Stack with list operations directly
birds = []
birds.append("Sparrow") # Push
birds.append("Eagle")
birds.append("Hawk")
print(birds.pop()) # Hawk
15.3 Queue (FIFO)
Queue is a FIFO (First-In-First-Out) data structure.
Queue operations: enqueue (add to back), dequeue (remove from front). Implemented with collections.deque for efficiency.
Code Example
from collections import deque
# Queue implementation using deque
class BirdQueue:
def __init__(self):
self.items = deque()
def enqueue(self, bird):
self.items.append(bird)
print(f"Enqueued: {bird}")
def dequeue(self):
if not self.is_empty():
return self.items.popleft()
print("Queue is empty!")
return None
def peek(self):
if not self.is_empty():
return self.items[0]
return None
def is_empty(self):
return len(self.items) == 0
def size(self):
return len(self.items)
def display(self):
print("Queue:", list(self.items))
# Using queue
queue = BirdQueue()
queue.enqueue("Sparrow")
queue.enqueue("Eagle")
queue.enqueue("Hawk")
print("Front:", queue.peek()) # Sparrow
print("Dequeue:", queue.dequeue()) # Sparrow
print("Front:", queue.peek()) # Eagle
# Queue using list (less efficient)
class SimpleQueue:
def __init__(self):
self.items = []
def enqueue(self, item):
self.items.append(item)
def dequeue(self):
if self.items:
return self.items.pop(0) # O(n) - inefficient
15.4 Linked List
Linked list is a sequence of nodes where each node references the next.
Nodes contain data and pointer to next node. Singly linked list (forward only). Doubly linked list (forward and backward).
Code Example
# Node class
class Node:
def __init__(self, data):
self.data = data
self.next = None
# Singly Linked List
class BirdList:
def __init__(self):
self.head = None
def append(self, data):
new_node = Node(data)
if not self.head:
self.head = new_node
return
current = self.head
while current.next:
current = current.next
current.next = new_node
def prepend(self, data):
new_node = Node(data)
new_node.next = self.head
self.head = new_node
def delete(self, data):
if not self.head:
return
if self.head.data == data:
self.head = self.head.next
return
current = self.head
while current.next:
if current.next.data == data:
current.next = current.next.next
return
current = current.next
def display(self):
current = self.head
while current:
print(current.data, end=" -> ")
current = current.next
print("None")
# Using linked list
birds = BirdList()
birds.append("Sparrow")
birds.append("Eagle")
birds.prepend("Hawk")
birds.display() # Hawk -> Sparrow -> Eagle -> None
birds.delete("Sparrow")
birds.display() # Hawk -> Eagle -> None
15.5 Trees
Trees are hierarchical data structures with parent-child relationships.
Binary trees have up to two children. Binary search trees have ordered nodes. Tree traversal includes inorder, preorder, postorder.
Code Example
# Binary Tree Node
class TreeNode:
def __init__(self, data):
self.data = data
self.left = None
self.right = None
# Binary Search Tree
class BirdTree:
def __init__(self):
self.root = None
def insert(self, data):
if not self.root:
self.root = TreeNode(data)
else:
self._insert(self.root, data)
def _insert(self, node, data):
if data < node.data:
if node.left:
self._insert(node.left, data)
else:
node.left = TreeNode(data)
else:
if node.right:
self._insert(node.right, data)
else:
node.right = TreeNode(data)
def inorder(self):
result = []
self._inorder(self.root, result)
return result
def _inorder(self, node, result):
if node:
self._inorder(node.left, result)
result.append(node.data)
self._inorder(node.right, result)
def search(self, data):
return self._search(self.root, data)
def _search(self, node, data):
if not node or node.data == data:
return node
if data < node.data:
return self._search(node.left, data)
return self._search(node.right, data)
# Using tree
tree = BirdTree()
birds = ["Sparrow", "Eagle", "Hawk", "Cardinal", "Robin"]
for bird in birds:
tree.insert(bird)
print("Inorder:", tree.inorder()) # Alphabetical order
print("Search Eagle:", tree.search("Eagle") is not None)
15.6 Graphs
Graphs represent connections between nodes.
Graphs have nodes (vertices) and edges. Directed vs undirected. Weighted vs unweighted. Represented with adjacency list or matrix.
Code Example
# Graph using adjacency list
class BirdGraph:
def __init__(self):
self.graph = {}
def add_node(self, node):
if node not in self.graph:
self.graph[node] = []
def add_edge(self, node1, node2):
if node1 not in self.graph:
self.add_node(node1)
if node2 not in self.graph:
self.add_node(node2)
self.graph[node1].append(node2)
self.graph[node2].append(node1) # For undirected graph
def display(self):
for node, neighbors in self.graph.items():
print(f"{node} -> {neighbors}")
def bfs(self, start):
visited = set()
queue = [start]
visited.add(start)
result = []
while queue:
node = queue.pop(0)
result.append(node)
for neighbor in self.graph.get(node, []):
if neighbor not in visited:
visited.add(neighbor)
queue.append(neighbor)
return result
def dfs(self, start):
visited = set()
result = []
self._dfs(start, visited, result)
return result
def _dfs(self, node, visited, result):
visited.add(node)
result.append(node)
for neighbor in self.graph.get(node, []):
if neighbor not in visited:
self._dfs(neighbor, visited, result)
# Using graph
graph = BirdGraph()
birds = ["Sparrow", "Eagle", "Hawk", "Robin"]
for bird in birds:
graph.add_node(bird)
graph.add_edge("Sparrow", "Eagle")
graph.add_edge("Sparrow", "Hawk")
graph.add_edge("Eagle", "Robin")
graph.add_edge("Hawk", "Robin")
graph.display()
print("BFS:", graph.bfs("Sparrow"))
print("DFS:", graph.dfs("Sparrow"))
15.7 Sorting Algorithms (Bubble, Merge, Quick)
Sorting algorithms arrange elements in specific order.
Bubble Sort: O(n²), simple but slow. Merge Sort is a stable sorting algorithm with O(n log n) time complexity. It divides the array into smaller parts, sorts them, and then merges the sorted parts. It typically requires O(n) extra memory for the merging process. Quick Sort: O(n log n) average, in-place sorting.
Code Example
# Bubble Sort (O(n²))
def bubble_sort(arr):
n = len(arr)
for i in range(n):
for j in range(0, n - i - 1):
if arr[j] > arr[j + 1]:
arr[j], arr[j + 1] = arr[j + 1], arr[j]
return arr
# Merge Sort (O(n log n))
def merge_sort(arr):
if len(arr) <= 1:
return arr
mid = len(arr) // 2
left = merge_sort(arr[:mid])
right = merge_sort(arr[mid:])
return merge(left, right)
def merge(left, right):
result = []
i, j = 0, 0
while i < len(left) and j < len(right):
if left[i] <= right[j]:
result.append(left[i])
i += 1
else:
result.append(right[j])
j += 1
result.extend(left[i:])
result.extend(right[j:])
return result
# Quick Sort (O(n log n) average)
def quick_sort(arr):
if len(arr) <= 1:
return arr
pivot = arr[-1]
left = [x for x in arr[:-1] if x <= pivot]
right = [x for x in arr[:-1] if x > pivot]
return quick_sort(left) + [pivot] + quick_sort(right)
# Testing
birds = [34, 7, 23, 32, 5, 62]
print("Original:", birds)
print("Bubble:", bubble_sort(birds.copy()))
print("Merge:", merge_sort(birds.copy()))
print("Quick:", quick_sort(birds.copy()))
# String sorting
bird_names = ["Eagle", "Sparrow", "Hawk", "Robin"]
print("Sorted names:", sorted(bird_names)) # Built-in sort
15.8 Searching Algorithms (Linear, Binary)
Searching algorithms find specific elements in data structures.
Linear Search: O(n), works on unsorted data. Binary Search: O(log n), requires sorted data.
Code Example
# Linear Search (O(n))
def linear_search(arr, target):
for i, item in enumerate(arr):
if item == target:
return i
return -1
# Binary Search (O(log n))
def binary_search(arr, target):
left, right = 0, len(arr) - 1
while left <= right:
mid = (left + right) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
left = mid + 1
else:
right = mid - 1
return -1
# Testing
birds = [5, 12, 23, 32, 45, 62, 78, 91]
target = 45
# Linear Search
pos = linear_search(birds, target)
print(f"Linear: Found {target} at position {pos}")
# Binary Search (requires sorted array)
birds_sorted = sorted(birds)
pos = binary_search(birds_sorted, target)
print(f"Binary: Found {target} at position {pos}")
# Search in list of strings
names = ["Eagle", "Hawk", "Robin", "Sparrow"]
print("Find Eagle:", names.index("Eagle")) # Built-in
# Performance comparison
import time
data = list(range(1000000))
start = time.time()
linear_search(data, 999999)
print(f"Linear: {time.time() - start:.4f}s")
start = time.time()
binary_search(data, 999999)
print(f"Binary: {time.time() - start:.4f}s")
Python Ecosystem
16.1 Database Programming (SQLite, MySQL, PostgreSQL)
Database programming enables persistent data storage.
SQLite: Lightweight, file-based database. MySQL/PostgreSQL: Server-based databases. Python provides modules for each.
Code Example
import sqlite3
# SQLite connection
conn = sqlite3.connect('birds.db')
cursor = conn.cursor()
# Create table
cursor.execute('''
CREATE TABLE IF NOT EXISTS birds (
id INTEGER PRIMARY KEY,
species TEXT NOT NULL,
count INTEGER,
weight REAL
)
''')
# Insert data
cursor.execute("INSERT INTO birds (species, count, weight) VALUES (?, ?, ?)",
("Sparrow", 10, 25.5))
cursor.execute("INSERT INTO birds (species, count, weight) VALUES (?, ?, ?)",
("Eagle", 3, 4500.0))
# Insert multiple rows
birds_data = [
("Hawk", 5, 1200.0),
("Robin", 8, 30.0),
("Finch", 6, 15.0)
]
cursor.executemany("INSERT INTO birds (species, count, weight) VALUES (?, ?, ?)",
birds_data)
# Commit changes
conn.commit()
# Query data
cursor.execute("SELECT * FROM birds")
for row in cursor.fetchall():
print(f"ID: {row[0]}, Species: {row[1]}, Count: {row[2]}, Weight: {row[3]}g")
# Query with conditions
cursor.execute("SELECT * FROM birds WHERE count > 5")
print("\nBirds with count > 5:")
for row in cursor.fetchall():
print(f"{row[1]}: {row[2]}")
# Update data
cursor.execute("UPDATE birds SET count = 12 WHERE species = 'Sparrow'")
# Delete data
cursor.execute("DELETE FROM birds WHERE species = 'Finch'")
# Close connection
conn.close()
16.2 Web Development (Flask, Django, FastAPI)
Web frameworks build web applications and APIs.
Flask: Lightweight, flexible microframework. Django: Full-featured, batteries-included. FastAPI: Modern, fast, async-capable.
Code Example
# Flask example
from flask import Flask, jsonify, request
app = Flask(__name__)
# Sample data
birds = {"Sparrow": 10, "Eagle": 3, "Hawk": 5}
@app.route('/')
def home():
return "Welcome to Bird API!"
@app.route('/birds')
def get_birds():
return jsonify(birds)
@app.route('/birds/<species>')
def get_bird(species):
if species in birds:
return jsonify({species: birds[species]})
return jsonify({"error": "Bird not found"}), 404
@app.route('/birds', methods=['POST'])
def add_bird():
data = request.json
species = data.get('species')
count = data.get('count')
if species and count:
birds[species] = count
return jsonify({"message": "Bird added"}), 201
return jsonify({"error": "Invalid data"}), 400
# Run server
if __name__ == '__main__':
app.run(debug=True)
# FastAPI example
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/birds/{species}")
def read_bird(species: str):
return {"species": species, "count": birds.get(species, 0)}
16.3 Data Science (NumPy, Pandas, Matplotlib)
Data science libraries handle numerical operations, data manipulation, and visualization.
NumPy: Numerical computing with arrays. Pandas: Data manipulation and analysis. Matplotlib: Data visualization and plotting.
Code Example
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# ---- NUMPY ----
# Create arrays
arr = np.array([10, 20, 30, 40, 50])
print("Array:", arr)
print("Shape:", arr.shape)
print("Mean:", arr.mean())
print("Sum:", arr.sum())
# 2D array
matrix = np.array([[1, 2, 3], [4, 5, 6]])
print("Matrix:")
print(matrix)
# NumPy operations
print("Squared:", arr ** 2)
print("Square root:", np.sqrt(arr))
# ---- PANDAS ----
# Create DataFrame
data = {
'Species': ['Sparrow', 'Eagle', 'Hawk', 'Robin'],
'Count': [10, 3, 5, 8],
'Weight': [25.5, 4500.0, 1200.0, 30.0]
}
df = pd.DataFrame(data)
print("DataFrame:")
print(df)
# Basic statistics
print("\nStatistics:")
print(df.describe())
# Filtering
print("\nFiltered (Count > 5):")
print(df[df['Count'] > 5])
# Sorting
print("\nSorted by Weight:")
print(df.sort_values('Weight'))
# ---- MATPLOTLIB ----
# Simple plot
plt.figure(figsize=(10, 6))
plt.bar(df['Species'], df['Count'])
plt.title('Bird Counts')
plt.xlabel('Species')
plt.ylabel('Count')
plt.show()
# Custom plot
plt.figure(figsize=(10, 6))
plt.scatter(df['Weight'], df['Count'], s=100)
plt.title('Weight vs Count')
plt.xlabel('Weight (g)')
plt.ylabel('Count')
for i, species in enumerate(df['Species']):
plt.annotate(species, (df['Weight'][i], df['Count'][i]))
plt.show()
16.4 Machine Learning (Scikit-Learn, TensorFlow, PyTorch)
Machine learning libraries build and train models.
Scikit-Learn: Traditional ML algorithms. TensorFlow: Deep learning framework. PyTorch: Dynamic neural networks.
Code Example
# Scikit-Learn example
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
# Generate sample data
X, y = make_classification(n_samples=100, n_features=5, random_state=42)
# Split data
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
# Train model
model = RandomForestClassifier()
model.fit(X_train, y_train)
# Predict and evaluate
y_pred = model.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy: {accuracy:.2f}")
# TensorFlow example
import tensorflow as tf
# Simple neural network
model = tf.keras.Sequential([
tf.keras.layers.Dense(64, activation='relu'),
tf.keras.layers.Dense(32, activation='relu'),
tf.keras.layers.Dense(1, activation='sigmoid')
])
# Compile model
model.compile(optimizer='adam',
loss='binary_crossentropy',
metrics=['accuracy'])
# Model summary
model.summary()
# PyTorch example (conceptual)
import torch
import torch.nn as nn
class SimpleModel(nn.Module):
def __init__(self):
super().__init__()
self.layer1 = nn.Linear(5, 10)
self.layer2 = nn.Linear(10, 1)
def forward(self, x):
x = torch.relu(self.layer1(x))
x = torch.sigmoid(self.layer2(x))
return x
# Create model
model = SimpleModel()
print(model)
Real-World Projects
17.1 Beginner Projects (Calculator, Password Generator, To-Do List)
Calculator
Code Example
# Simple Calculator
def calculator():
print("Simple Calculator")
print("Operations: +, -, *, /")
try:
num1 = float(input("Enter first number: "))
operation = input("Enter operation (+, -, *, /): ")
num2 = float(input("Enter second number: "))
if operation == '+':
result = num1 + num2
elif operation == '-':
result = num1 - num2
elif operation == '*':
result = num1 * num2
elif operation == '/':
if num2 == 0:
print("Error: Division by zero!")
return
result = num1 / num2
else:
print("Invalid operation!")
return
print(f"{num1} {operation} {num2} = {result}")
except ValueError:
print("Error: Invalid input!")
# Run calculator
calculator()
Password Generator
Code Example
import random
import string
def password_generator():
print("Password Generator")
length = int(input("Enter password length: "))
use_uppercase = input("Include uppercase? (y/n): ").lower() == 'y'
use_digits = input("Include digits? (y/n): ").lower() == 'y'
use_symbols = input("Include symbols? (y/n): ").lower() == 'y'
# Build character set
chars = string.ascii_lowercase
if use_uppercase:
chars += string.ascii_uppercase
if use_digits:
chars += string.digits
if use_symbols:
chars += string.punctuation
# Generate password
password = ''.join(random.choice(chars) for _ in range(length))
print(f"Generated password: {password}")
# Generate multiple passwords
def multiple_passwords():
count = int(input("How many passwords? "))
length = int(input("Password length: "))
for i in range(count):
password = ''.join(random.choice(string.ascii_letters + string.digits)
for _ in range(length))
print(f"Password {i+1}: {password}")
password_generator()
To-Do List
Code Example
class TodoList:
def __init__(self):
self.tasks = []
def add_task(self, task):
self.tasks.append({"task": task, "done": False})
print(f"Added: {task}")
def view_tasks(self):
if not self.tasks:
print("No tasks!")
return
for i, task in enumerate(self.tasks, 1):
status = "✓" if task["done"] else "○"
print(f"{i}. [{status}] {task['task']}")
def mark_done(self, index):
if 0 <= index < len(self.tasks):
self.tasks[index]["done"] = True
print(f"Task completed: {self.tasks[index]['task']}")
def delete_task(self, index):
if 0 <= index < len(self.tasks):
task = self.tasks.pop(index)
print(f"Deleted: {task['task']}")
def run(self):
while True:
print("\n--- To-Do List ---")
print("1. Add task")
print("2. View tasks")
print("3. Mark task done")
print("4. Delete task")
print("5. Exit")
choice = input("Enter choice: ")
if choice == '1':
task = input("Enter task: ")
self.add_task(task)
elif choice == '2':
self.view_tasks()
elif choice == '3':
self.view_tasks()
index = int(input("Enter task number: ")) - 1
self.mark_done(index)
elif choice == '4':
self.view_tasks()
index = int(input("Enter task number: ")) - 1
self.delete_task(index)
elif choice == '5':
print("Goodbye!")
break
else:
print("Invalid choice!")
# Run to-do list
todo = TodoList()
todo.run()
17.2 Intermediate Projects (REST API, Web Scraper, Chat Application)
REST API (using Flask)
Code Example
from flask import Flask, jsonify, request
app = Flask(__name__)
# Data store
bird_data = {
1: {"species": "Sparrow", "count": 10, "weight": 25.5},
2: {"species": "Eagle", "count": 3, "weight": 4500.0},
3: {"species": "Hawk", "count": 5, "weight": 1200.0}
}
next_id = 4
# GET all birds
@app.route('/birds', methods=['GET'])
def get_birds():
return jsonify(bird_data)
# GET single bird
@app.route('/birds/<int:bird_id>', methods=['GET'])
def get_bird(bird_id):
if bird_id in bird_data:
return jsonify(bird_data[bird_id])
return jsonify({"error": "Bird not found"}), 404
# POST new bird
@app.route('/birds', methods=['POST'])
def add_bird():
global next_id
data = request.json
if 'species' not in data or 'count' not in data:
return jsonify({"error": "Missing required fields"}), 400
bird_data[next_id] = {
"species": data['species'],
"count": data['count'],
"weight": data.get('weight', 0.0)
}
next_id += 1
return jsonify({"message": "Bird added", "id": next_id - 1}), 201
# PUT update bird
@app.route('/birds/<int:bird_id>', methods=['PUT'])
def update_bird(bird_id):
if bird_id not in bird_data:
return jsonify({"error": "Bird not found"}), 404
data = request.json
bird_data[bird_id].update(data)
return jsonify({"message": "Bird updated", "bird": bird_data[bird_id]})
# DELETE bird
@app.route('/birds/<int:bird_id>', methods=['DELETE'])
def delete_bird(bird_id):
if bird_id not in bird_data:
return jsonify({"error": "Bird not found"}), 404
del bird_data[bird_id]
return jsonify({"message": "Bird deleted"})
if __name__ == '__main__':
app.run(debug=True)
17.3 Advanced Projects (AI Chatbot, Recommendation System)
AI Chatbot
Code Example
import random
import json
import re
class SimpleChatbot:
def __init__(self):
self.responses = {
"greeting": [
"Hello! How can I help you?",
"Hi there! What can I do for you?",
"Welcome! I'm here to assist you."
],
"bird_question": [
"Birds are fascinating creatures!",
"I love learning about birds!",
"What would you like to know about birds?"
],
"bird_identification": [
"I can help identify birds based on description.",
"What color is the bird?",
"Tell me more about the bird you saw."
],
"unknown": [
"I'm not sure I understand.",
"Could you rephrase that?",
"I'm still learning! Please try again."
]
}
def greet(self):
return random.choice(self.responses["greeting"])
def identify_bird(self, text):
bird_keywords = ['sparrow', 'eagle', 'hawk', 'robin', 'finch']
for bird in bird_keywords:
if bird in text.lower():
return f"Ah! You mentioned {bird}. They're wonderful birds!"
return None
def respond(self, text):
# Check for greeting
if any(word in text.lower() for word in ['hello', 'hi', 'hey', 'greetings']):
return self.greet()
# Check for bird identification
bird_response = self.identify_bird(text)
if bird_response:
return bird_response
# Check for bird questions
if any(word in text.lower() for word in ['bird', 'feather', 'wing']):
return random.choice(self.responses["bird_question"])
return random.choice(self.responses["unknown"])
def run(self):
print("Chatbot: " + self.greet())
while True:
user_input = input("You: ")
if user_input.lower() in ['bye', 'goodbye', 'exit', 'quit']:
print("Chatbot: Goodbye! Have a great day!")
break
response = self.respond(user_input)
print("Chatbot:", response)
# Run chatbot
# chatbot = SimpleChatbot()
# chatbot.run()
Recommendation System
Code Example
# Simple content-based recommendation
class BirdRecommender:
def __init__(self):
self.birds = {
'Sparrow': {'size': 'small', 'color': 'brown', 'habitat': 'urban'},
'Eagle': {'size': 'large', 'color': 'brown', 'habitat': 'mountains'},
'Hawk': {'size': 'medium', 'color': 'brown', 'habitat': 'forests'},
'Robin': {'size': 'small', 'color': 'red', 'habitat': 'gardens'},
'Cardinal': {'size': 'medium', 'color': 'red', 'habitat': 'forests'}
}
def recommend(self, preferences):
# Find birds matching preferences
recommendations = []
for bird, traits in self.birds.items():
matches = 0
for key, value in preferences.items():
if traits.get(key) == value:
matches += 1
if matches > 0:
recommendations.append((bird, matches))
# Sort by match count
recommendations.sort(key=lambda x: x[1], reverse=True)
return [bird for bird, _ in recommendations]
def run(self):
print("Bird Recommendation System")
print("Available preferences: size (small/medium/large), color (brown/red), habitat (urban/mountains/forests/gardens)")
preferences = {}
pref_input = input("Enter preferences (e.g., size=small,color=red): ")
for item in pref_input.split(','):
key, value = item.split('=')
preferences[key.strip()] = value.strip()
recommendations = self.recommend(preferences)
if recommendations:
print("Recommended birds:", recommendations)
else:
print("No matching birds found")
# Run recommender
recommender = BirdRecommender()
recommender.run()
Testing & Professional Development
18.1 Unit Testing (unittest, pytest)
Unit testing verifies code correctness.
unittest: Built-in testing framework. pytest: More advanced third-party framework. Both support assertions and test discovery.
Code Example
# Using unittest
import unittest
def count_birds(birds):
return sum(birds.values())
def get_bird(birds, species):
return birds.get(species, 0)
class TestBirdFunctions(unittest.TestCase):
def test_count_birds(self):
bird_data = {"Sparrow": 10, "Eagle": 3, "Hawk": 5}
self.assertEqual(count_birds(bird_data), 18)
self.assertEqual(count_birds({}), 0)
def test_get_bird(self):
bird_data = {"Sparrow": 10, "Eagle": 3}
self.assertEqual(get_bird(bird_data, "Sparrow"), 10)
self.assertEqual(get_bird(bird_data, "Hawk"), 0)
def test_invalid_input(self):
with self.assertRaises(TypeError):
count_birds(None)
# Run tests
# if __name__ == '__main__':
# unittest.main()
# Using pytest
def test_count_birds():
bird_data = {"Sparrow": 10, "Eagle": 3, "Hawk": 5}
assert count_birds(bird_data) == 18
assert count_birds({}) == 0
def test_get_bird():
bird_data = {"Sparrow": 10, "Eagle": 3}
assert get_bird(bird_data, "Sparrow") == 10
assert get_bird(bird_data, "Hawk") == 0
# Fixtures with pytest
import pytest
@pytest.fixture
def sample_birds():
return {"Sparrow": 10, "Eagle": 3, "Hawk": 5}
def test_with_fixture(sample_birds):
assert count_birds(sample_birds) == 18
18.2 Packaging & Deployment (pip, virtualenv, Docker)
Packaging and deployment tools distribute Python applications.
pip: Package installer. virtualenv: Isolated environment. Docker: Containerization for consistent deployment.
Code Example
# setup.py for packaging
"""
from setuptools import setup, find_packages
setup(
name="bird-package",
version="1.0.0",
packages=find_packages(),
install_requires=[
"flask>=2.0.0",
"pandas>=1.3.0",
"numpy>=1.21.0"
],
author="Your Name",
description="A bird management package",
classifiers=[
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License"
]
)
"""
# Virtual environment commands
"""
# Create virtual environment
python -m venv venv
# Activate (Windows)
venv\Scripts\activate
# Activate (Mac/Linux)
source venv/bin/activate
# Install packages
pip install flask pandas numpy
# Install from requirements
pip install -r requirements.txt
# Freeze requirements
pip freeze > requirements.txt
"""
# Dockerfile for containerization
"""
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "app.py"]
"""
# Docker commands
"""
# Build image
docker build -t bird-app .
# Run container
docker run -p 5000:5000 bird-app
"""
18.3 Open Source Contribution (GitHub workflow, pull requests)
Open source contribution involves collaborating on public projects.
Git workflow: Clone, branch, commit, push. Pull Request: Propose changes to a repository. Code Review: Feedback and approval process.
Code Example
# Git commands
"""
# Clone repository
git clone https://github.com/username/bird-project.git
# Create branch
git checkout -b feature/add-bird-function
# Make changes
# Edit files, add features
# Stage changes
git add .
# Commit with message
git commit -m "Add function to count birds"
# Push branch
git push origin feature/add-bird-function
# Create pull request on GitHub
"""
# Example contribution code
class BirdCalculator:
def __init__(self):
self.birds = {}
def add_bird(self, species, count):
"""Add or update bird count."""
self.birds[species] = self.birds.get(species, 0) + count
def get_total(self):
"""Return total number of birds."""
return sum(self.birds.values())
def get_species(self):
"""Return list of bird species."""
return list(self.birds.keys())
# Contribution guidelines
"""
# Contributing to Bird-Project
## How to Contribute
1. Fork the repository
2. Create a feature branch
3. Write tests for your changes
4. Submit a pull request
## Coding Standards
- Follow PEP 8
- Add docstrings
- Include unit tests
- Update documentation
"""
Career Readiness
19.1 Portfolio Development
A portfolio showcases your Python projects and skills.
Include diverse projects showing different skills. Organize with clear README files. Demonstrate problem-solving ability.
Code Example
# Example README.md for portfolio project
"""
# Bird Management System
A Python application for tracking bird populations in different habitats.
## Features
- Add and update bird species
- Track population statistics
- Generate reports
- Export data to CSV
## Technologies
- Python 3.9+
- Flask for web interface
- SQLite for data storage
- Pandas for data analysis
- Matplotlib for visualizations
## Installation
```bash
git clone https://github.com/username/bird-management
cd bird-management
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
Usage
from bird_system import BirdManager
manager = BirdManager()
manager.add_bird("Sparrow", 10)
manager.add_bird("Eagle", 3)
print(manager.get_report())
Demo
[Link to live demo]
Contact
- Email: username@example.com
- LinkedIn: linkedin.com/in/username
“””
Portfolio organization
“””
Portfolio Structure:
├── projects/
│ ├── bird-management/
│ │ ├── README.md
│ │ ├── src/
│ │ ├── tests/
│ │ └── requirements.txt
│ ├── data-analysis/
│ └── machine-learning/
├── README.md
└── contact.md
“””
---
## 19.2 Technical Interviews
**What They Are**
Technical interviews assess Python knowledge and problem-solving.
**Detailed Explanation**
Practice common questions, explain your thought process, write clean code, and test edge cases.
**Code Example**
```python
# Common interview questions
# 1. Reverse a string
def reverse_string(s):
return s[::-1]
# 2. Check if palindrome
def is_palindrome(s):
s = s.lower().replace(" ", "")
return s == s[::-1]
# 3. Find duplicates in list
def find_duplicates(arr):
seen = set()
duplicates = []
for item in arr:
if item in seen:
duplicates.append(item)
else:
seen.add(item)
return duplicates
# 4. Fibonacci
def fibonacci(n):
if n <= 1:
return n
a, b = 0, 1
for _ in range(2, n + 1):
a, b = b, a + b
return b
# 5. FizzBuzz
def fizzbuzz(n):
for i in range(1, n + 1):
if i % 15 == 0:
print("FizzBuzz")
elif i % 3 == 0:
print("Fizz")
elif i % 5 == 0:
print("Buzz")
else:
print(i)
# 6. Binary Search
def binary_search(arr, target):
left, right = 0, len(arr) - 1
while left <= right:
mid = (left + right) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
left = mid + 1
else:
right = mid - 1
return -1
# 7. Two Sum
def two_sum(nums, target):
seen = {}
for i, num in enumerate(nums):
complement = target - num
if complement in seen:
return [seen[complement], i]
seen[num] = i
return []
19.3 Resume Building
A resume highlights your Python skills and experience.
Include technical skills, relevant projects, work experience, and education. Quantify achievements and use action verbs.
Code Example
# Resume template example
"""
# John Doe
Python Developer | Data Scientist
Email: john@example.com | LinkedIn: linkedin.com/in/johndoe | GitHub: github.com/johndoe
## Summary
Experienced Python developer with 5+ years of experience in data science and
web development. Passionate about building scalable applications and solving
complex problems.
## Technical Skills
- Languages: Python, SQL, JavaScript
- Frameworks: Django, Flask, FastAPI
- Libraries: Pandas, NumPy, Scikit-learn, TensorFlow
- Tools: Git, Docker, AWS, Jupyter
## Experience
### Senior Python Developer | Tech Company (2021-Present)
- Built RESTful APIs serving 10k+ daily requests
- Reduced response time by 40% through optimization
- Led team of 5 developers on 3 major projects
### Python Developer | Startup (2018-2021)
- Developed data pipelines processing 1M+ records daily
- Implemented ML models achieving 92% accuracy
- Created dashboards for real-time monitoring
## Projects
### Bird Management System
- Python, Flask, SQLite, Pandas
- Complete bird tracking system with reporting features
- Deployed on AWS with 99.9% uptime
## Education
### MS in Computer Science, University Name (2016-2018)
### BS in Computer Science, University Name (2012-2016)
"""
19.4 Freelancing and Employment
Freelancing and employment are career paths for Python developers.
Freelancing involves working for multiple clients independently. Employment involves working for a company. Both require strong communication and problem-solving skills.
Code Example
# Freelance proposal template
"""
Project Proposal: Bird Data Analysis Platform
Client: ABC Wildlife Foundation
## Executive Summary
Development of a comprehensive bird tracking and analysis platform
using Python, Django, and advanced data visualization tools.
## Project Scope
- Build interactive dashboard for bird sightings
- Implement data import from CSV and API sources
- Create automated reporting system
- Provide real-time analytics and visualizations
## Technical Approach
- Backend: Python/Django REST Framework
- Database: PostgreSQL
- Frontend: React.js
- Deployment: AWS
## Timeline
- Phase 1: Requirements & Design (2 weeks)
- Phase 2: Development (8 weeks)
- Phase 3: Testing & Deployment (2 weeks)
- Phase 4: Training & Handover (1 week)
## Cost Estimate
- Development: $15,000
- Deployment & Maintenance: $2,000/year
## Portfolio
- Bird Management System (link)
- Wildlife Data Platform (link)
## References
Available upon request
"""
# Job application checklist
"""
## Job Application Checklist
1. Research the company and role
2. Customize resume and cover letter
3. Prepare for technical interview
4. Practice common coding questions
5. Review data structures and algorithms
6. Prepare examples of past projects
7. Practice system design questions
8. Prepare questions to ask the interviewer
9. Follow up after interview
10. Negotiate offer
## Interview Preparation Resources
- LeetCode: Practice coding problems
- HackerRank: Coding challenges
- Glassdoor: Company reviews and interview questions
- LinkedIn: Professional networking
- GitHub: Showcase your projects
"""
# Networking tips
"""
## Networking for Python Developers
1. Attend Python meetups and conferences
2. Contribute to open source projects
3. Share projects on GitHub
4. Write blog posts about Python
5. Connect on LinkedIn
6. Join Python Slack/Discord communities
7. Participate in coding competitions
8. Offer to speak at local meetups
9. Create tutorials and guides
10. Help others in Python forums
"""
This comprehensive Python guide covers all the topics from the roadmap with clear explanations, practical code examples, and real-world applications. Each section is designed to be standalone while building on previous concepts, making it suitable for beginners and intermediate learners alike.