Course Level: Undergraduate (Year 1–2) Prerequisites: Basic computer literacy; no prior programming experience required. Instructor's Note: This document is de…
Course Level: Undergraduate (Year 1–2)
Prerequisites: Basic computer literacy; no prior programming experience required.
Instructor's Note: This document is designed to serve as a full semester's worth of introductory reading material. Work through it sequentially. Type every code example yourself — reading code is not the same as writing it.
Table of Contents
- Introduction to Python
- Setting Up Your Environment
- Python Syntax Basics
- Variables and Data Types
- Operators and Expressions
- Control Flow
- Functions
- Data Structures
- Strings in Depth
- File Input/Output
- Error Handling and Exceptions
- Object-Oriented Programming
- Modules and Packages
- Virtual Environments and Dependency Management
- Introduction to Advanced Topics
- Best Practices and PEP 8
- Common Pitfalls for Beginners
- Capstone Project Suggestions
- Further Reading and Resources
- Tags
1. Introduction to Python
1.1 What Is Python?
Python is a high-level, interpreted, dynamically typed, general-purpose programming language created by Guido van Rossum and first released in 1991. Its design philosophy emphasizes code readability and simplicity, famously summarized in The Zen of Python (PEP 20):
import this
Run the snippet above in any Python interpreter, and you will see 19 aphorisms, including:
"Beautiful is better than ugly."
"Explicit is better than implicit."
"Simple is better than complex."
"Readability counts."
1.2 Why Learn Python?
| Reason |
Explanation |
| Readability |
Syntax resembles pseudocode; ideal for beginners. |
| Versatility |
Web development, data science, AI/ML, automation, scientific computing, DevOps. |
| Huge Ecosystem |
Over 500,000 packages on PyPI. |
| Community |
Massive global community, abundant tutorials and Stack Overflow answers. |
| Industry Demand |
Consistently ranked among the top 3 most in-demand programming languages. |
| Academic Use |
Standard in research (NumPy, SciPy, Pandas, Matplotlib). |
1.3 Interpreted vs. Compiled
Python is interpreted, meaning source code is executed line-by-line by the Python interpreter rather than being compiled to machine code ahead of time.
Note: CPython (the reference implementation) actually compiles to bytecode first, then interprets the bytecode. This is an implementation detail, but useful to know.
Source (.py) → Bytecode (.pyc) → Python Virtual Machine → Machine Code
2. Setting Up Your Environment
2.1 Installing Python
- Visit python.org/downloads.
- Download the latest stable version (3.11+ recommended).
- Windows: Check "Add Python to PATH" during installation.
- macOS/Linux: Python 3 is usually pre-installed; verify with
python3 --version.
Verify installation:
python --version
# or
python3 --version
2.2 Choosing an Editor or IDE
| Tool |
Best For |
Notes |
| IDLE |
Absolute beginners |
Bundled with Python |
| VS Code |
General use |
Lightweight, extensible |
| PyCharm |
Large projects |
Powerful, heavier |
| Jupyter Notebook |
Data science |
Interactive cells |
| Vim/Emacs |
Power users |
Steep learning curve |
2.3 The Interactive REPL
The Read-Eval-Print Loop (REPL) lets you execute Python one line at a time.
$ python3
>>> 2 + 3
5
>>> print("Hello, world!")
Hello, world!
>>> exit()
Tip: Use the REPL for quick experiments; use script files for anything reusable.
2.4 Running Your First Script
Create hello.py:
# hello.py
print("Hello, world!")
Run it:
python hello.py
3. Python Syntax Basics
3.1 Indentation
Unlike most languages that use braces {}, Python uses indentation to define blocks. The standard is 4 spaces.
if True:
print("Indented block")
print("Still inside")
print("Outside the block")
Warning: Mixing tabs and spaces causes TabError. Configure your editor to insert spaces.
3.2 Comments
# This is a single-line comment
"""
This is a multi-line string,
often used as a docstring or comment.
"""
def add(a, b):
"""Return the sum of a and b."""
return a + b
3.3 Statements and Expressions
- Statement: an instruction that performs an action (
x = 5).
- Expression: produces a value (
2 + 3).
3.4 Line Continuation
total = 1 + 2 + 3 + \
4 + 5 + 6
# Or use parentheses (preferred)
total = (1 + 2 + 3 +
4 + 5 + 6)
4. Variables and Data Types
4.1 Variables
Python variables are names bound to objects. No explicit type declaration is needed.
name = "Alice"
age = 21
gpa = 3.85
is_enrolled = True
Under the hood: A variable is a reference to an object in memory. name = "Alice" binds the name name to a str object.
4.2 Built-in Data Types
| Type |
Example |
Description |
int |
42 |
Arbitrary-precision integer |
float |
3.14 |
Double-precision floating point |
complex |
2+3j |
Complex numbers |
str |
"hello" |
Immutable sequence of Unicode characters |
bool |
True |
True or False |
list |
[1, 2, 3] |
Mutable ordered sequence |
tuple |
(1, 2, 3) |
Immutable ordered sequence |
dict |
{"a": 1} |
Mutable key-value mapping |
set |
{1, 2, 3} |
Mutable unordered collection of unique items |
NoneType |
None |
Represents absence of value |
4.3 Type Checking and Conversion
x = 42
print(type(x)) # <class 'int'>
y = str(x) # "42"
z = float("3.14") # 3.14
a = int("10") # 10
Common Pitfall: int("3.14") raises ValueError. Use int(float("3.14")) instead.
4.4 Dynamic Typing
x = 10
x = "ten" # Valid — x now references a string
Python is dynamically typed: types are checked at runtime, not compile time.
5. Operators and Expressions
5.1 Arithmetic Operators
| Operator |
Meaning |
Example |
+ |
Addition |
3 + 2 → 5 |
- |
Subtraction |
3 - 2 → 1 |
* |
Multiplication |
3 * 2 → 6 |
/ |
Division (float) |
7 / 2 → 3.5 |
// |
Floor division |
7 // 2 → 3 |
% |
Modulus |
7 % 2 → 1 |
** |
Exponentiation |
2 ** 3 → 8 |
5.2 Comparison Operators
3 == 3 # True
3 != 4 # True
3 < 4 # True
3 >= 3 # True
5.3 Logical Operators
True and False # False
True or False # True
not True # False
5.4 Bitwise Operators
5 & 3 # 1 (AND)
5 | 3 # 7 (OR)
5 ^ 3 # 6 (XOR)
~5 # -6 (NOT)
5 << 1 # 10 (left shift)
5 >> 1 # 2 (right shift)
5.5 Operator Precedence
From highest to lowest (partial):
**
*, /, //, %
+, -
<<, >>
&
^, |
- Comparisons (
==, <, etc.)
not, and, or
Best Practice: Use parentheses to make intent explicit.
6. Control Flow
6.1 if, elif, else
score = 85
if score >= 90:
grade = "A"
elif score >= 80:
grade = "B"
elif score >= 70:
grade = "C"
else:
grade = "F"
print(grade) # B
6.2 while Loops
count = 0
while count < 5:
print(count)
count += 1
6.3 for Loops
for i in range(5):
print(i)
for fruit in ["apple", "banana", "cherry"]:
print(fruit)
6.4 range() in Depth
range(5) # 0, 1, 2, 3, 4
range(2, 8) # 2, 3, 4, 5, 6, 7
range(1, 10, 2) # 1, 3, 5, 7, 9
range(10, 0, -1) # 10, 9, ..., 1
6.5 Loop Control: break, continue, else
for n in range(10):
if n == 5:
break
print(n)
for n in range(5):
if n % 2 == 0:
continue
print(n) # 1, 3
for n in range(3):
print(n)
else:
print("Loop finished without break")
Note: The else clause on loops runs only if the loop completes without break.
6.6 Truthiness
Falsy values: False, None, 0, 0.0, "", [], {}, (), set().
Everything else is truthy.
if []:
print("Not printed")
if [0]:
print("Printed — non-empty list is truthy")
7. Functions
7.1 Defining Functions
def greet(name):
"""Return a greeting for name."""
return f"Hello, {name}!"
print(greet("Alice"))
7.2 Parameters vs. Arguments
- Parameter: the variable in the function definition (
name).
- Argument: the value passed in the call (
"Alice").
7.3 Default Arguments
def power(base, exponent=2):
return base ** exponent
power(3) # 9
power(3, 3) # 27
Common Pitfall — Mutable Default Arguments:
def append_to(element, target=[]): # BAD
target.append(element)
return target
append_to(1) # [1]
append_to(2) # [1, 2] ← Surprise!
Fix:
def append_to(element, target=None):
if target is None:
target = []
target.append(element)
return target
7.4 Keyword Arguments
def describe(name, age, city):
print(f"{name}, {age}, from {city}")
describe(age=30, city="Nairobi", name="Amina")
7.5 *args and **kwargs
def sum_all(*args):
return sum(args)
sum_all(1, 2, 3, 4) # 10
def print_info(**kwargs):
for key, value in kwargs.items():
print(f"{key}: {value}")
print_info(name="Alice", age=21)
7.6 Scope: LEGB Rule
Python resolves names in this order: Local → Enclosing → Global → Built-in.
x = "global"
def outer():
x = "enclosing"
def inner():
x = "local"
print(x) # local
inner()
outer()
7.7 global and nonlocal
counter = 0
def increment():
global counter
counter += 1
increment()
print(counter) # 1
7.8 Lambda Functions
square = lambda x: x ** 2
print(square(5)) # 25
# Commonly used with map, filter, sorted
nums = [3, 1, 4, 1, 5]
sorted(nums, key=lambda n: -n) # [5, 4, 3, 1, 1]
7.9 Type Hints (PEP 484)
def add(a: int, b: int) -> int:
return a + b
Note: Type hints are not enforced at runtime; they aid readability and tooling.
8. Data Structures
8.1 Lists
fruits = ["apple", "banana", "cherry"]
fruits.append("date") # add to end
fruits.insert(1, "kiwi") # insert at index
fruits.remove("banana") # remove by value
popped = fruits.pop() # remove and return last
fruits[0] # "apple"
fruits[-1] # last element
fruits[1:3] # slice
| Method |
Description |
append(x) |
Add x to end |
extend(iterable) |
Add all items |
insert(i, x) |
Insert at index i |
remove(x) |
Remove first occurrence of x |
pop([i]) |
Remove and return item |
index(x) |
Return index of x |
count(x) |
Count occurrences |
sort() |
Sort in place |
reverse() |
Reverse in place |
copy() |
Shallow copy |
clear() |
Remove all items |
8.2 Tuples
Immutable ordered sequences.
point = (3, 4)
x, y = point # unpacking
single = (5,) # note the comma
empty = ()
List vs. Tuple:
| Feature |
List |
Tuple |
| Mutable |
✅ |
❌ |
| Hashable |
❌ |
✅ (if contents hashable) |
| Use case |
Dynamic collections |
Fixed records |
| Performance |
Slower |
Faster |
8.3 Dictionaries
student = {
"name": "Alice",
"age": 21,
"major": "CS"
}
student["gpa"] = 3.85
student.get("minor", "None") # safe access
student.keys()
student.values()
student.items()
Note: Since Python 3.7, dictionaries preserve insertion order.
8.4 Sets
a = {1, 2, 3}
b = {3, 4, 5}
a | b # union → {1, 2, 3, 4, 5}
a & b # intersection → {3}
a - b # difference → {1, 2}
a ^ b # symmetric difference → {1, 2, 4, 5}
8.5 Comprehensions
squares = [x ** 2 for x in range(10)]
evens = [x for x in range(20) if x % 2 == 0]
word_lengths = {word: len(word) for word in ["a", "bb", "ccc"]}
unique = {x % 3 for x in range(10)}
gen = (x ** 2 for x in range(10)) # generator expression
Best Practice: Prefer comprehensions over map/filter when readability is preserved.
8.6 Choosing the Right Structure
| Need |
Structure |
| Ordered, mutable |
list |
| Ordered, immutable |
tuple |
| Key-value mapping |
dict |
| Unique items, fast membership |
set |
| Immutable set |
frozenset |
9. Strings in Depth
9.1 Creating Strings
s1 = 'single'
s2 = "double"
s3 = """triple
quoted"""
9.2 Indexing and Slicing
s = "Python"
s[0] # 'P'
s[-1] # 'n'
s[1:4] # 'yth'
s[::-1] # 'nohtyP' (reversed)
9.3 Common Methods
"hello".upper() # "HELLO"
"HELLO".lower() # "hello"
" hi ".strip() # "hi"
"a,b,c".split(",") # ['a', 'b', 'c']
"-".join(["a", "b"]) # "a-b"
"abc".replace("a", "x") # "xbc"
"abc".startswith("a") # True
"abc".find("b") # 1
9.4 Formatting
name, age = "Alice", 21
# f-strings (Python 3.6+) — preferred
f"{name} is {age}"
# .format()
"{} is {}".format(name, age)
# % formatting (legacy)
"%s is %d" % (name, age)
9.5 Immutability
Strings are immutable. Operations return new strings.
s = "abc"
# s[0] = "x" # TypeError
s = "x" + s[1:] # "xbc"
10. File Input/Output
10.1 Reading Files
with open("data.txt", "r", encoding="utf-8") as f:
content = f.read()
with open("data.txt") as f:
for line in f:
print(line.rstrip())
10.2 Writing Files
with open("output.txt", "w") as f:
f.write("Hello\n")
f.writelines(["line1\n", "line2\n"])
10.3 File Modes
| Mode |
Meaning |
"r" |
Read (default) |
"w" |
Write (truncates) |
"a" |
Append |
"x" |
Create, fail if exists |
"b" |
Binary mode |
"+" |
Read and write |
Best Practice: Always use with — it ensures the file is closed even if an exception occurs.
10.4 Working with Paths
from pathlib import Path
p = Path("data") / "file.txt"
if p.exists():
print(p.read_text())
11. Error Handling and Exceptions
11.1 Try/Except
try:
x = int("abc")
except ValueError as e:
print(f"Error: {e}")
11.2 Multiple Exceptions
try:
result = 10 / 0
except (ZeroDivisionError, TypeError) as e:
print(e)
11.3 else and finally
try:
f = open("data.txt")
except FileNotFoundError:
print("Missing file")
else:
print("Opened successfully")
f.close()
finally:
print("Always runs")
11.4 Raising Exceptions
def sqrt(x):
if x < 0:
raise ValueError("Cannot take sqrt of negative")
return x ** 0.5
11.5 Custom Exceptions
class InsufficientFundsError(Exception):
pass
def withdraw(balance, amount):
if amount > balance:
raise InsufficientFundsError("Not enough money")
return balance - amount
Best Practice: Catch specific exceptions. Avoid bare except: clauses.
12. Object-Oriented Programming
12.1 Classes and Objects
class Dog:
species = "Canis familiaris" # class attribute
def __init__(self, name, age):
self.name = name # instance attribute
self.age = age
def bark(self):
return f"{self.name} says woof!"
rex = Dog("Rex", 3)
print(rex.bark())
12.2 Inheritance
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
raise NotImplementedError
class Cat(Animal):
def speak(self):
return "Meow"
class Dog(Animal):
def speak(self):
return "Woof"
12.3 super()
class Puppy(Dog):
def __init__(self, name, age, toy):
super().__init__(name, age)
self.toy = toy
12.4 Dunder (Magic) Methods
class Vector:
def __init__(self, x, y):
self.x, self.y = x, y
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
def __repr__(self):
return f"Vector({self.x}, {self.y})"
def __eq__(self, other):
return (self.x, self.y) == (other.x, other.y)
12.5 Properties
class Circle:
def __init__(self, radius):
self._radius = radius
@property
def radius(self):
return self._radius
@radius.setter
def radius(self, value):
if value < 0:
raise ValueError("Radius must be non-negative")
self._radius = value
12.6 Class vs. Instance Attributes
| Type |
Defined |
Shared? |
| Class attribute |
Inside class body |
✅ All instances |
| Instance attribute |
In __init__ via self |
❌ Per instance |
12.7 Encapsulation Conventions
_name — internal by convention.
__name — name-mangled (not truly private).
13. Modules and Packages
13.1 Importing
import math
math.sqrt(16)
from math import sqrt, pi
sqrt(16)
import numpy as np
np.array([1, 2, 3])
13.2 Creating Modules
mymodule.py:
def greet(name):
return f"Hi, {name}"
main.py:
from mymodule import greet
print(greet("Alice"))
13.3 The __name__ Guard
if __name__ == "__main__":
print("Running as script")
13.4 Packages
A package is a directory containing __init__.py.
mypackage/
├── __init__.py
├── module_a.py
└── subpackage/
├── __init__.py
└── module_b.py
14. Virtual Environments and Dependency Management
14.1 Why Virtual Environments?
Isolate project dependencies to avoid version conflicts.
14.2 venv
python -m venv .venv
source .venv/bin/activate # Linux/macOS
.venv\Scripts\activate # Windows
pip install requests
deactivate
14.3 pip Essentials
pip install package_name
pip install package_name==1.2.3
pip freeze > requirements.txt
pip install -r requirements.txt
pip list
14.4 Modern Alternatives
- Poetry — dependency resolution + packaging.
- Pipenv — combines pip + venv.
- Conda — scientific stack, cross-language.
15. Introduction to Advanced Topics
15.1 Iterators
nums = [1, 2, 3]
it = iter(nums)
next(it) # 1
next(it) # 2
15.2 Generators
def countdown(n):
while n > 0:
yield n
n -= 1
for x in countdown(3):
print(x)
Under the hood: Generators are lazy — they produce values on demand, saving memory.
15.3 Decorators
def logged(func):
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__}")
return func(*args, **kwargs)
return wrapper
@logged
def add(a, b):
return a + b
add(2, 3)
15.4 Context Managers
class Timer:
def __enter__(self):
import time
self.start = time.time()
return self
def __exit__(self, *args):
print(f"Elapsed: {time.time() - self.start:.4f}s")
with Timer():
sum(range(10_000_000))
15.5 Asynchronous Programming (Brief)
import asyncio
async def main():
print("Hello")
await asyncio.sleep(1)
print("World")
asyncio.run(main())
15.6 Type Hints and typing
from typing import List, Dict, Optional
def process(items: List[int]) -> Optional[int]:
return sum(items) if items else None
15.7 Introduction to Testing
# test_math.py
def add(a, b):
return a + b
def test_add():
assert add(2, 3) == 5
Run with pytest.
16. Best Practices and PEP 8
16.1 PEP 8 Highlights
- 4 spaces per indentation level.
- Lines ≤ 79 characters (docstrings/comments ≤ 72).
- Two blank lines between top-level definitions.
snake_case for functions and variables.
CapWords for classes.
UPPER_CASE for constants.
- Imports at the top, grouped: standard → third-party → local.
16.2 Naming Conventions
| Entity |
Convention |
| Variable |
snake_case |
| Constant |
UPPER_SNAKE_CASE |
| Function |
snake_case |
| Class |
CapWords |
| Module |
lowercase or snake_case |
| Package |
lowercase |
16.3 Code Quality Tools
| Tool |
Purpose |
black |
Auto-formatter |
flake8 |
Linter |
pylint |
Linter + more |
mypy |
Static type checker |
isort |
Import sorter |
pytest |
Testing framework |
16.4 The Zen of Python — Revisited
import this
17. Common Pitfalls for Beginners
| Pitfall |
Example |
Fix |
| Mutable default args |
def f(x, l=[]) |
Use None sentinel |
| Integer division confusion |
7 / 2 == 3.5 |
Use // for floor |
is vs == |
x is 1000 |
Use == for values |
| Modifying list while iterating |
for x in lst: lst.remove(x) |
Iterate over a copy |
| Shadowing built-ins |
list = [1, 2] |
Rename variable |
| Late binding in closures |
Loops + lambdas |
Bind with default arg |
Forgetting self |
Method definitions |
Always include self |
| Ignoring exceptions |
except: pass |
Catch specific exceptions |
| Comparing floats directly |
0.1 + 0.2 == 0.3 |
Use math.isclose |
Confusing == and = |
if x = 5 |
Syntax error; use == |
18. Capstone Project Suggestions
- Student Grade Manager — CLI app with file persistence.
- Personal Expense Tracker — CRUD with SQLite.
- Web Scraper — Using
requests + BeautifulSoup.
- To-Do List GUI — Using
tkinter.
- Simple Chatbot — Rule-based or with
transformers.
- Data Analysis Notebook — Pandas + Matplotlib on a public dataset.
- Flask Blog — Minimal web app.
- Sudoku Solver — Backtracking algorithm.
19. Further Reading and Resources
Official
Books
- Automate the Boring Stuff with Python — Al Sweigart
- Python Crash Course — Eric Matthes
- Fluent Python — Luciano Ramalho
- Effective Python — Brett Slatkin
Practice
Community
20. Tags
#python #pythonprogramming #learnpython #pythoncourse #coding #programming #university #college #computerscience #softwareengineering #datascience #webdevelopment #automation #pep8 #swiftener
End of Course.
Published on swiftener.com — Your gateway to mastering technology.