Python
-
Link download
-
Checking
python --version
Basics
Syntax and Variables
Python uses simple, clean syntax. Variables don't need explicit declarations.
# Variable assignment
x = 10
y = 3.14
name = "Alice"
a, b = 5, "Hello"
# Printing variables
print(x, y, name)
Control Flow
x = 10
if x > 5:
print("x is greater than 5")
elif x == 5:
print("x is 5")
else:
print("x is 5 or less")
# Ternary operator
sound = pet == "dog" if "bark" else "meow"
# match-case example (Python 3.10+)
match x:
case 1:
print("x is 1")
case 10:
print("x is 10")
case _: # like default
print("x is something else")
# Loops
for i in range(5): # 0 to 4
print(i)
else: # else block after for (Optional)
print("Loop finished")
for char in "Hello":
print(char)
for fruit in ["apple", "banana", "cherry"]:
print(fruit)
for key, value in {"a": 1, "b": 2}.items():
print(key, value)
# while loop, break, continue
i = 0
while i < 5:
if i == 3:
break
if i == 1:
i += 1
continue
print(i)
i += 1
else:
print("While loop finished")
# pass does nothing, used as a placeholder
for _ in range(3):
pass
Functions
# Function definition
def greet(name = "Guest"):
return f"Hello, {name}!"
# Function call
print(greet()) # Hello, Guest!
print(greet("Alice")) # Hello, Alice!
# Arbitrary arguments
def add(*args):
return sum(args)
print(add(1, 2, 3)) # 6
# Keyword arguments
def multiply(**kwargs):
result = 1
for value in kwargs.values():
result *= value
return result
print(multiply(a=2, b=3, c=4)) # 24
# List comprehension and lambda
squares = [x**2 for x in range(5)]
print(squares) # [0, 2, 4, 6, 8]
# Anonymous function (lambda)
double = lambda x: x * 2
Data Structures
my_list = [10, 20, 'apple', 3.14, 20]
print(f"Original List: {my_list}") # [10, 20, 'apple', 3.14, 20]
# Accessing elements (indexing)
print(f"Element at position 1: {my_list[1]}") # 20
# Slicing
print(f"Slice from start up to position 3 (exclusive): {my_list[:3]}") # [10, 20, 'apple']
# Modifying an element
my_list[0] = 15
print(f"List after changing the first element: {my_list}") # [15, 20, 'apple', 3.14, 20]
# Adding an element
my_list.append('banana')
print(f"List after appending 'banana': {my_list}") # [15, 20, 'apple', 3.14, 20, 'banana']
# Removing an element (by value)
my_list.remove(20)
print(f"List after removing the first occurrence of 20: {my_list}") # [15, 'apple', 3.14, 20, 'banana']
# Iterating through a List
print("Elements in the List:")
for item in my_list:
print(item)
my_tuple = (1, 'two', 3, 'two', 5)
print(f"Original Tuple: {my_tuple}") # (1, 'two', 3, 'two', 5)
# Accessing elements (indexing)
print(f"Element at position 2: {my_tuple[2]}") # 3
# Slicing
print(f"Slice from position 1 up to 4 (exclusive): {my_tuple[1:4]}") # ('two', 3, 'two')
# **Note:** Cannot add, remove, or change elements after creation
# Counting element occurrences
print(f"Count of 'two': {my_tuple.count('two')}") # 2
my_set = {100, 200, 300, 100, 400}
print(f"Original Set (duplicate 100 removed): {my_set}") # {100, 200, 300, 400}
# Adding an element
my_set.add(500)
print(f"Set after adding 500: {my_set}") # {100, 200, 300, 400, 500}
# Removing an element
my_set.discard(200) # .remove() raises an error if the element is not found
print(f"Set after discarding 200: {my_set}") # {100, 300, 400, 500}
# Basic Set Operations (Union, Intersection, Difference)
set_A = {1, 2, 3, 4}
set_B = {3, 4, 5, 6}
print(f"Union (A U B): {set_A.union(set_B)}") # {1, 2, 3, 4, 5, 6}
print(f"Intersection (A n B): {set_A.intersection(set_B)}") # {3, 4}
print(f"Difference (A - B): {set_A.difference(set_B)}") # {1, 2}
my_dict = {
'name': 'Alice',
'age': 30,
'city': 'New York'
}
print(f"Original Dictionary: {my_dict}")
# {'name': 'Alice', 'age': 30, 'city': 'New York'}
# Accessing value by Key
print(f"Name: {my_dict['name']}") # Alice
# Modifying or adding a new Key-Value pair
my_dict['age'] = 31 # Modifying
my_dict['job'] = 'Engineer' # Adding new
print(f"Dictionary after modification and addition: {my_dict}")
# {'name': 'Alice', 'age': 31, 'city': 'New York', 'job': 'Engineer'}
# Deleting a Key-Value pair
del my_dict['city']
print(f"Dictionary after deleting 'city': {my_dict}")
# {'name': 'Alice', 'age': 31, 'job': 'Engineer'}
# Iterating through the Dictionary
print("Key and Value pairs:")
for key, value in my_dict.items():
print(f"{key}: {value}")
# Getting all Keys or Values
print(f"Keys: {my_dict.keys()}") # dict_keys(['name', 'age', 'job'])
print(f"Values: {my_dict.values()}") # dict_values(['Alice', 31, 'Engineer'])
Quick Summary Table
| Collection | Ordered | Mutable | Duplicates Allowed | Primary Use Case |
|---|---|---|---|---|
| List | Yes | Yes | Yes | General purpose ordered sequence of items |
| Tuple | Yes | No | Yes | Immutable sequence for fixed data (e.g., coordinates) |
| Set | No | Yes | No | Storing a collection of unique items |
| Dictionary | Yes (since Py 3.7) | Yes | No (Keys must be unique) | Storing data mappings as Key: Value pairs |
Error Handling
try:
x = int("not a number")
except ValueError as e:
print(f"Error: {e}")
finally: # always executes. Optional
print("Execution completed.")
Object-Oriented Programming (OOP)
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
# Creating instances of the Dog class
dog1 = Dog("Buddy", 9)
dog2 = Dog("Miles", 4)
print(dog1.name) # Output: Buddy
print(dog2.age) # Output: 4
class Animal:
def speak(self):
return "Animal speaks"
class Cat(Animal):
def speak(self):
return "Meow"
cat = Cat()
print(cat.speak()) # Output: Meow
class BankAccount:
def __init__(self, balance):
self.__balance = balance # Private attribute
def deposit(self, amount):
if amount > 0:
self.__balance += amount
def get_balance(self):
return self.__balance
account = BankAccount(1000)
account.deposit(500)
print(account.get_balance()) # Output: 1500
class Bird:
def fly(self):
return "Bird is flying"
class Airplane:
def fly(self):
return "Airplane is flying"
def make_it_fly(flying_object):
print(flying_object.fly())
bird = Bird()
plane = Airplane()
make_it_fly(bird) # Output: Bird is flying
make_it_fly(plane) # Output: Airplane is flying
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self):
pass
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
rect = Rectangle(5, 10)
print(rect.area()) # Output: 50
Python Modules
A module is simply a Python file (.py) containing functions, classes, or variables that can be reused across different programs.
Example Module: math_utils.py
# math_utils.py
def add(a, b):
return a + b
def multiply(a, b):
return a * b
PI = 3.14159
Using a Module
import math_utils
print(math_utils.add(2, 3)) # Output: 5
print(math_utils.multiply(4, 5)) # Output: 20
print(math_utils.PI) # Output: 3.14159
Python Packages
A package is a collection of modules organized in a directory with a special file __init__.py, which tells Python that the directory should be treated as a package.
Example Package Structure
my_package/
│
├── __init__.py
├── module1.py
└── module2.py
Importing Modules from a Package
from my_package import module1
from my_package.module2 import some_function
module1.some_function()
some_function()
Key Differences
| Feature | Module | Package |
|---|---|---|
| Definition | A single .py file | A directory with multiple modules and __init__.py |
| Usage | Reusable code in small units | Groups related modules logically |
| Structure | Flat and simple | Hierarchical and scalable |
Best Practices
- Keep related functions and classes within the same module.
- Group modules logically into packages for larger projects.
- Use descriptive and consistent names for modules and packages.
- Avoid circular imports to maintain clean dependency flows.
Standard Library Modules
Python comes with a rich standard library of modules for various tasks:
os: Interact with the operating systemsys: Access system-specific parameters and functionsmath: Mathematical functionsdatetime: Work with dates and timesjson: Handle JSON datare: Regular expressionsrandom: Generate random numberscollections: Specialized container datatypes
File I/O
# Writing to a file
with open("test.txt", "w") as file:
file.write("Hello, World!")
# Reading from a file
with open("test.txt", "r") as file:
content = file.read()
print(content)
File Modes
"r": Read (default mode, file must exist)"w": Write (creates a new file or truncates existing file)"a": Append (creates a new file or appends to existing file)"b": Binary mode (e.g.,"rb"or"wb")"t": Text mode (default mode, e.g.,"rt"or"wt")
Working with File Paths
import os
# Get current working directory
cwd = os.getcwd()
print(f"Current Working Directory: {cwd}")
# Join paths
file_path = os.path.join(cwd, "test.txt")
print(f"File Path: {file_path}")
# Check if file exists
exists = os.path.exists(file_path)
print(f"File exists: {exists}")
# Get file size
size = os.path.getsize(file_path)
print(f"File size: {size} bytes")
Handling Large Files
# Reading large files line by line
with open("large_file.txt", "r") as file:
for line in file:
process(line) # Replace with actual processing logic
# Writing large files in chunks
with open("large_output.txt", "w") as file:
for chunk in generate_large_data(): # Replace with actual data generation logic
file.write(chunk)
CSV File Handling
import csv
# Writing to a CSV file
with open("data.csv", "w", newline='') as csvfile:
writer = csv.writer(csvfile)
writer.writerow(["Name", "Age", "City"])
writer.writerow(["Alice", 30, "New York"])
writer.writerow(["Bob", 25, "Los Angeles"])
# Reading from a CSV file
with open("data.csv", "r") as csvfile:
reader = csv.reader(csvfile)
for row in reader:
print(row)
JSON File Handling
import json
# Writing to a JSON file
data = {
"name": "Alice",
"age": 30,
"city": "New York"
}
with open("data.json", "w") as jsonfile:
json.dump(data, jsonfile)
# Reading from a JSON file
with open("data.json", "r") as jsonfile:
data = json.load(jsonfile)
print(data)
Advanced Python Concepts
1. Iterators & Generators
Iterators let you walk through data step-by-step. Generators yield values on demand, keeping things lightweight.
def countdown(n):
while n > 0:
yield n
n -= 1
for num in countdown(3):
print(num)
2. Decorators
Decorators wrap extra behavior around functions without rewriting them.
def log(fn):
def wrapper(*args, **kwargs):
print("Calling:", fn.__name__)
return fn(*args, **kwargs)
return wrapper
@log
def greet():
return "Hello!"
print(greet())
3. Context Managers
They handle setup + cleanup automatically.
class FileManager:
def __init__(self, path):
self.path = path
def __enter__(self):
self.f = open(self.path, "w")
return self.f
def __exit__(self, exc_type, exc_val, exc_tb):
self.f.close()
with FileManager("demo.txt") as f:
f.write("Hello world!")
4. Metaclasses
Metaclasses control how classes are created.
class UpperAttrMeta(type):
def __new__(mcls, name, bases, attrs):
uppercase = {
k.upper(): v for k, v in attrs.items() if not k.startswith("__")
}
return super().__new__(mcls, name, bases, uppercase)
class Demo(metaclass=UpperAttrMeta):
value = 10
print(hasattr(Demo, "VALUE")) # True
5. Async Programming
async + await help Python handle I/O-bound tasks smoothly.
import asyncio
async def fetch_data():
await asyncio.sleep(1)
return "done"
async def main():
result = await fetch_data()
print(result)
asyncio.run(main())
6. Descriptors
Descriptors let you customize attribute behavior.
class Positive:
def __set__(self, instance, value):
if value < 0:
raise ValueError("Must be positive")
instance.__dict__["value"] = value
def __get__(self, instance, owner):
return instance.__dict__["value"]
class Account:
value = Positive()
a = Account()
a.value = 50
print(a.value)
7. Type Hints & Static Analysis
Type hints make your intent clearer and help tools catch bugs early.
from typing import List
def average(nums: List[float]) -> float:
return sum(nums) / len(nums)
print(average([1.0, 2.0, 3.0]))
8. Memory Management
Python uses reference counting and garbage collection to manage memory automatically.
import sys
a = []
print(sys.getrefcount(a)) # Reference count
b = a
print(sys.getrefcount(a)) # Increased reference count
del b
print(sys.getrefcount(a)) # Decreased reference count
9. Multi-threading vs Multi-processing
- Multi-threading: Multiple threads within the same process share memory space. Good for I/O-bound tasks.
- Multi-processing: Separate memory space for each process. Better for CPU-bound tasks.
import threading
def worker():
print("Worker thread")
thread = threading.Thread(target=worker)
thread.start()
thread.join()
import multiprocessing
def worker():
print("Worker process")
process = multiprocessing.Process(target=worker)
process.start()
process.join()