Comprehensive Python Programming Guide

Everything You Need to Know to Get Started and Master the Basics

Table of Contents

Introduction to Python

What is Python?

Python is a versatile, high-level programming language designed for readability and simplicity. It employs indentation to define code blocks and supports procedural, object-oriented, and functional paradigms.

History of Python

Created by Guido van Rossum and released in 1991, Python has evolved through versions 2.x (legacy) to 3.x (current). Python 3.0 (2008) addressed design flaws and improved Unicode support.

Unique Features of Python

Python 2 vs Python 3

Installing Python

Download the installer from python.org. On Windows, check "Add Python to PATH"; on macOS/Linux, use package managers like Homebrew or apt.

Setting Up Development Environment

Use an IDE or editor (e.g., VS Code, PyCharm). Configure linting (flake8) and formatting (black) extensions to enforce code style and catch errors early.

Important Programming Basics

Python Keywords and Indentation

Python reserves words like def, return, if, for. Indentation (standard 4 spaces) defines blocks instead of braces.

Comments

# Single-line comment
"""
Multi-line comment or docstring,
used to document modules and functions.
"""
        

Use # for inline comments. Triple-quoted strings at the top of modules, classes, or functions serve as documentation.

Basic Data Types

Variables

x = 10         # int assigned dynamically
name = "Umar"  # string variable
is_active = True # boolean
        

Variables are created on assignment; types are inferred at runtime.

Operators

Arithmetic (+ - * / // % **), comparison (== != > < >= <=), logical (and, or, not), bitwise (& | ^ ~ << >>), membership (in, not in), identity (is, is not).

Strings

s = "Hello, Python!"
print(s[0], s[-1])       # H !
print(s.upper(), s.lower())  # HELLO, PYTHON! hello, python!
print(s.replace("Python", "World"))  # Hello, World!
        

Strings are immutable. Use slicing (s[start:end]) and methods (.strip(), .split(), .find()) for manipulation.

Getting User Input

age = input("Enter your age: ")
age = int(age)  # Convert to integer
print(f"You are {age} years old.")
        

input() returns a string. Convert types explicitly when needed.

First Program

print("Hello, World!")
        

Outputs text to the console using the print() function.

Loops & Control Statements

Control Structures

Simple if

x = 5
if x > 0:
    print("Positive")
        

The if statement executes its block only if the condition is True.

if-else

if x % 2 == 0:
    print("Even")
else:
    print("Odd")
        

else runs when if is False.

Nested if

if x > 0:
    if x < 10:
        print("1-9")
    else:
        print(">=10")
        

You can nest if blocks for multiple checks.

if-elif-else

if x < 0:
    print("Negative")
elif x == 0:
    print("Zero")
else:
    print("Positive")
        

elif allows chaining multiple conditions.

Loops

for loop

for i in range(5):
    print(i)
        

range(n) yields 0 to n-1; for iterates over any sequence.

while loop

count = 0
while count < 5:
    print(count)
    count += 1
        

while repeats as long as its condition holds true. Ensure loop variables update to avoid infinite loops.

Break & Continue

for i in range(10):
    if i == 5:
        break      # Exit loop completely
    if i % 2 == 0:
        continue   # Skip to next iteration
    print(i)
        

break stops the loop; continue skips the rest of the current iteration.

Functions, Modules & Packages

User-Defined Functions

def greet(name):
    """Return a greeting message for name."""
    return f"Hello, {name}!"

message = greet("Umar")
print(message)
        

Functions encapsulate code for reuse. Docstrings describe their purpose.

Function Parameters & Scope

Parameters can be positional, keyword, default, or variable-length (*args, **kwargs). Variables inside are local; use global to modify globals.

Lambda Functions

add = lambda a, b: a + b
print(add(3, 4))  # Outputs 7
        

lambda creates small anonymous functions inline.

Modules & Namespaces

# my_module.py
PI = 3.14

def area(radius):
    return PI * radius ** 2

# main.py
import my_module
print(my_module.area(5))

from my_module import area, PI
print(area(3))
        

Modules (.py files) group related code. Use import to access names. Namespaces prevent collisions.

The if __name__ == "__main__": block runs code only when the module is executed directly, not when imported.

Packages

Packages are directories with an __init__.py file, enabling hierarchical module organization. Install third-party packages via pip install package-name.

Data Structures in Python

Lists

fruits = ["apple", "banana", "cherry"]
fruits.append("date")       # Add at end
print(fruits[1])              # Access by index
        

Lists are ordered, mutable collections. Support indexing, slicing, and methods like append(), remove(), sort().

Lists as Stacks

stack = []
stack.append(1)
stack.append(2)
print(stack.pop())  # LIFO behavior: outputs 2
        

Lists as Queues

from collections import deque
queue = deque()
queue.append(1)
queue.append(2)
print(queue.popleft())  # FIFO behavior: outputs 1
        

Tuples

point = (10, 20)
print(point[0])  # Immutable sequence
        

Tuples are ordered, immutable sequences used for fixed collections.

del Statement

del fruits[0]  # Remove first item
del fruits      # Delete entire list
        

del removes items or entire variables.

Iterators & Generators

# Iterator example
nums = [1, 2, 3]
it = iter(nums)
print(next(it))  # 1

# Generator example
def gen(n):
    for i in range(n):
        yield i
for val in gen(3):
    print(val)
        

Iterators traverse collections. Generators create iterators with yield, saving memory.

Comprehensions

squares = [x**2 for x in range(5)]
evens = {x: x%2==0 for x in range(5)}
        

List, dict, and set comprehensions provide concise syntax for transforming iterables.

Ranges

for i in range(1, 10, 2):
    print(i)  # 1,3,5,7,9
        

range(start, stop, step) generates arithmetic sequences without storing them.

Dictionaries

student = {"name": "Bob", "age": 21}
print(student.get("name"))
student["grade"] = "A"
for key, val in student.items():
    print(key, val)
        

Dictionaries map keys to values. Use dict.keys(), .values(), .items() to iterate.

Sets

s = {1, 2, 3}
s.add(4)
s.remove(2)
print(3 in s)
        

Sets store unique unordered elements. Support union (|), intersection (&), difference (-).

Exception Handling in Python

Raising Exceptions

raise ValueError("Invalid value")
        

raise manually triggers exceptions to signal errors.

Handling Exceptions

try:
    x = int(input())
except ValueError:
    print("Please enter an integer.")
else:
    print("You entered", x)
finally:
    print("Execution completed.")
        

try wraps code that may fail, except handles specific errors, else runs if no errors, finally always executes.

Custom Exceptions

class MyError(Exception):
    """Custom exception type."""
    pass

raise MyError("Something went wrong")
        

Define custom exception classes by subclassing Exception.

Multithreading & Multiprocessing

Creating Threads

import threading

def worker(id):
    print(f"Worker {id}")

threads = []
for i in range(3):
    t = threading.Thread(target=worker, args=(i,))
    threads.append(t)
    t.start()
        

Threads run concurrently within a process. Use threading.Thread to start them.

Thread Synchronization

lock = threading.Lock()

def safe_increment():
    with lock:
        # only one thread can execute this block at a time
        global counter
        counter += 1
        

Use locks to prevent race conditions when accessing shared resources.

Thread Pools

from concurrent.futures import ThreadPoolExecutor

with ThreadPoolExecutor(max_workers=5) as executor:
    executor.map(worker, range(5))
        

ThreadPoolExecutor manages a pool of worker threads.

Multiprocessing Module

from multiprocessing import Process

def task(id):
    print(f"Process {id}")

if __name__ == "__main__":
    processes = []
    for i in range(3):
        p = Process(target=task, args=(i,))
        processes.append(p)
        p.start()
        

multiprocessing runs separate processes, bypassing the GIL for CPU-bound tasks.

File Handling (I/O)

Reading Text Files

with open('data.txt', 'r') as f:
    contents = f.read()
    print(contents)
        

open() with 'r' mode reads entire file into memory.

Writing Text Files

with open('out.txt', 'w') as f:
    f.write("Hello, file!\n")
        

'w' mode creates/truncates file. Use 'a' to append.

Binary Files & Pickle

import pickle

data = {'a': 1, 'b': 2}
with open('data.pkl', 'wb') as f:
    pickle.dump(data, f)

with open('data.pkl', 'rb') as f:
    loaded = pickle.load(f)
        

Pickle serializes objects to bytes; use 'wb' and 'rb' modes.

Collections in Python

The collections module provides specialized data types:

Object Oriented Programming

Defining Classes

class Person:
    """A simple class representing a person."""
    species = "Homo sapiens"  # Class attribute

    def __init__(self, name, age):
        self.name = name  # Instance attribute
        self.age = age

    def greet(self):
        print(f"Hello, I am {self.name}.")
        

__init__ initializes new objects. self refers to the instance.

Encapsulation

Use _protected and __private prefixes to signal intended privacy.

Inheritance

class Student(Person):
    def __init__(self, name, age, student_id):
        super().__init__(name, age)
        self.student_id = student_id
        

super() calls base class methods.

Polymorphism

Different classes can implement the same method names, allowing interchangeable usage.

Built-In Class Attributes

Destroying Objects

del person_instance  # Deletes reference to the object
        

Regular Expressions

What Are Regular Expressions?

Patterns to match character combinations in strings, handled by the re module.

match() vs search()

import re
m = re.match(r"\d+", "123abc")   # Matches at start
s = re.search(r"abc", "123abc")  # Searches anywhere
        

match() checks only at the beginning, search() scans the string.

Search and Replace

re.sub(r"\d+", "", "ID123")  # Replaces digits with 
        

sub() replaces all occurrences of the pattern.

Wildcards & Quantifiers

# . matches any char, * zero or more, + one or more
pattern = r"a.*?b"  # Non-greedy match from a to b
re.findall(pattern, "aXb aYYb")  # ['aXb', 'aYYb']
        

Quantifiers (?, *, +, {{m,n}}) control repetition. Use ? after to make them non-greedy.