This page collects runnable examples of core Python: loading CSV data into built-in containers, defining functions, lambdas, decorators and closures, object-oriented classes, iterators and generators, and concurrency. The sections at the end tie the examples together with diagrams, a comparison of the containers, and common mistakes.
import csv
# Sample CSV data
with open('data.csv', 'r') as file:
reader = csv.reader(file)
# Skipping the header
next(reader)
# Reading into a list
data_list = [row for row in reader]
with open('data.csv', 'r') as file:
reader = csv.reader(file)
next(reader)
# Reading into a tuple
data_tuple = tuple(reader)
with open('data.csv', 'r') as file:
reader = csv.reader(file)
next(reader)
# Reading into a set
data_set = {tuple(row) for row in reader}
with open('data.csv', 'r') as file:
reader = csv.DictReader(file)
# Reading into a dictionary
data_dict = [row for row in reader]
print('List:', data_list)
print('Tuple:', data_tuple)
print('Set:', data_set)
print('Dictionary:', data_dict)
This Python program demonstrates how to read data from a CSV file and load it into different data structures like Lists, Tuples, Sets, and Dictionaries.
def greet(name, msg='Hello'):
return {msg}, {name}!
print(greet('Alice')) # Output: Hello, Alice!
print(greet('Bob', 'Hi')) # Output: Hi, Bob!
# Inline anonymous function
square = lambda x: x * x
print(square(5)) # Output: 25
def decorator_func(func):
def wrapper():
print('Before function call')
func()
print('After function call')
return wrapper
@decorator_func
def say_hello():
print('Hello!')
say_hello()
# Function that returns another function
def make_multiplier(n):
def multiplier(x):
return x * n
return multiplier
times_two = make_multiplier(2)
print(times_two(5)) # Output: 10
# Passing a function as an argument
def apply_func(func, value):
return func(value)
print(apply_func(square, 4)) # Output: 16
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
def bark(self):
return 'Woof!'
my_dog = Dog('Buddy', 5)
print(my_dog.name) # Output: Buddy
print(my_dog.bark()) # Output: Woof!
class Animal:
def speak(self):
return 'Some sound'
class Cat(Animal):
def speak(self):
return 'Meow'
my_cat = Cat()
print(my_cat.speak()) # Output: Meow
class Person:
def __init__(self, name, age):
self.__name = name # Private attribute
self.age = age
def get_name(self):
return self.__name
person = Person('Alice', 30)
print(person.get_name()) # Output: Alice
# print(person.__name) # This would raise an AttributeError
class Book:
def __init__(self, title, author):
self.title = title
self.author = author
def __str__(self):
return f'{self.title} by {self.author}'
book = Book('1984', 'George Orwell')
print(book) # Output: 1984 by George Orwell
my_list = [1, 2, 3, 4, 5]
my_tuple = (1, 2, 3, 4, 5)
my_set = {1, 2, 3, 4, 5}
my_dict = {'a': 1, 'b': 2, 'c': 3}
# Iterating over a list
for item in my_list:
print(item)
# Iterating over a tuple
for item in my_tuple:
print(item)
# Iterating over a set
for item in my_set:
print(item)
# Iterating over a dictionary
for key, value in my_dict.items():
print(key, value)
# Basic generator function
def my_generator():
yield 1
yield 2
yield 3
for value in my_generator():
print(value)
# Generator expression
gen_exp = (x for x in range(4))
for value in gen_exp:
print(value)
This Python program demonstrates how to iterate over different data structures i
(Lists, Tuples, Sets, and Dictionaries) and how to use generators.
# Multithreading: Multiple threads within the same process
import threading
def print_numbers():
for i in range(5):
print(i)
thread = threading.Thread(target=print_numbers)
thread.start()
# Multiprocessing: Multiple processes with separate memory spaces
import multiprocessing
def print_numbers_mp():
for i in range(5):
print(i)
process = multiprocessing.Process(target=print_numbers_mp)
process.start()
process.join()
# Asyncio: Writing asynchronous code with async and await
import asyncio
async def async_print_numbers():
for i in range(5):
print(i)
await asyncio.sleep(1)
async def main():
await async_print_numbers()
asyncio.run(main())
The CSV example loads the same rows into four containers, and each answers different questions efficiently. A list keeps rows in file order and supports indexing and slicing. A tuple is a fixed record that can be hashed, so it can be stored in a set or used as a dictionary key. A set removes duplicates and answers membership questions in constant average time. A dictionary maps a key, such as an id column, to the row, giving direct access without scanning. For readable code, csv.DictReader, dataclasses, or typing.NamedTuple give each field a name rather than a position.
| Container | Lookup | Ordered | Mutable | Hashable |
|---|---|---|---|---|
| list | O(n) by value, O(1) by index | Yes | Yes | No |
| tuple | O(n) by value, O(1) by index | Yes | No | Yes, if elements are |
| set | O(1) average | No | Yes | No (frozenset is) |
| dict | O(1) average by key | Insertion order | Yes | No |
When you read obj.attr, Python checks data descriptors on the class (such as properties), then the instance's own dictionary, then the class and its bases in method resolution order (MRO), which you can inspect with Type.__mro__. Methods are functions stored on the class; accessing them through an instance binds self automatically. Inheritance and polymorphism in the examples work because a subclass method earlier in the MRO shadows the base version, and super() continues the lookup from the next class in the MRO. Python encapsulation is by convention: a single leading underscore means internal, and a double underscore triggers name mangling to avoid accidental clashes in subclasses, not to enforce privacy.
The iterator and generator examples rely on the same protocol. Any object with an __iter__ method returning an object with __next__ can drive a for loop; a generator function creates such an object automatically and pauses at each yield, keeping its local variables alive between values. That makes generators the natural way to stream large CSV files row by row without loading them into memory, and to build processing pipelines where each stage pulls from the previous one. The concurrency example adds the last piece: threads for waiting on I/O, and processes or native extensions for heavy computation.
import csv, io, functools, time
from dataclasses import dataclass
from concurrent.futures import ThreadPoolExecutor
data = io.StringIO("id,name,dept,salary\n1,Ana,eng,120\n2,Bo,ops,90\n3,Cy,eng,110\n")
@dataclass(frozen=True)
class Employee:
id: int
name: str
dept: str
salary: int
def timed(fn): # decorator
@functools.wraps(fn)
def wrapper(*args, **kw):
t = time.perf_counter()
try:
return fn(*args, **kw)
finally:
print(f"{fn.__name__}: {time.perf_counter() - t:.6f}s")
return wrapper
@timed
def load(fh):
return [Employee(int(r["id"]), r["name"], r["dept"], int(r["salary"]))
for r in csv.DictReader(fh)]
def by_dept(rows): # generator
groups = {}
for e in rows:
groups.setdefault(e.dept, []).append(e)
yield from groups.items()
staff = load(data)
for dept, people in by_dept(staff):
print(dept, sum(p.salary for p in people))
with ThreadPoolExecutor(max_workers=4) as pool: # I/O-bound work in threads
print(list(pool.map(lambda e: e.name.upper(), staff)))
def f(x=[])) are created once and shared across calls; use None and create inside.functools.wraps hide the wrapped function's name and docstring.