Python এর functools মডিউল হল সবচেয়ে কম ব্যবহৃত কিন্তু শক্তিশালী স্ট্যান্ডার্ড লাইব্রেরি মডিউলগুলির মধ্যে একটি। 2026 সালে, ফাংক্টুলগুলি উচ্চ-ক্রম ফাংশন, মেমোাইজেশন, আংশিক প্রয়োগ এবং ফাংশন রচনার জন্য সরঞ্জাম সরবরাহ করে যা বয়লারপ্লেট দূর করে এবং কোডকে আরও অভিব্যক্তিপূর্ণ করে। এই সম্পূর্ণ নির্দেশিকা ব্যবহারিক উদাহরণ সহ প্রতিটি ফাংশন ফাংশন কভার করে।
📋 Table of Contents
functools.lru_cache এবং ক্যাশে
from functools import lru_cache, cache
import time
# Simple memoization — cache indefinitely
@cache # Python 3.9+, same as lru_cache(maxsize=None)
def fibonacci(n: int) -> int:
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
# LRU cache — keep only most recent N results
@lru_cache(maxsize=128)
def expensive_api_call(user_id: int) -> dict:
time.sleep(0.5) # simulate slow API
return {"id": user_id, "name": "User"}
# Cache info and management
print(fibonacci.cache_info()) # CacheInfo(hits=X, misses=Y, maxsize=None, currsize=N)
fibonacci.cache_clear()
# Method-level cache (instance-level, not shared across instances)
class DataService:
@lru_cache(maxsize=256)
def get_user(self, user_id: int) -> dict:
return fetch_from_db(user_id)
functools.partial — আংশিক অ্যাপ্লিকেশন
from functools import partial
import operator
# Create a new function with some args pre-filled
def power(base: float, exponent: float) -> float:
return base ** exponent
square = partial(power, exponent=2)
cube = partial(power, exponent=3)
print(square(5)) # 25.0
print(cube(3)) # 27.0
# Useful with map/filter
double = partial(operator.mul, 2)
numbers = [1, 2, 3, 4, 5]
doubled = list(map(double, numbers)) # [2, 4, 6, 8, 10]
# Partial with keyword args
import requests
get_from_api = partial(requests.get, headers={"Authorization": "Bearer token123"})
response = get_from_api("https://api.example.com/users")
# In configuration/dependency injection
from functools import partial
def create_user(db, email: str, role: str = "user") -> dict:
return db.insert("users", {"email": email, "role": role})
create_admin = partial(create_user, db=prod_db, role="admin")
admin = create_admin("admin@example.com")
functools.reduce
from functools import reduce
import operator
# Sum a list (use sum() instead in practice)
total = reduce(operator.add, [1, 2, 3, 4, 5]) # 15
# Product of list (no built-in)
product = reduce(operator.mul, [1, 2, 3, 4, 5]) # 120
# Flatten nested list
nested = [[1, 2], [3, 4], [5, 6]]
flat = reduce(operator.add, nested) # [1, 2, 3, 4, 5, 6]
# Compose functions (right to left)
def compose(*functions):
return reduce(lambda f, g: lambda x: f(g(x)), functions)
pipeline = compose(str.upper, str.strip, str.lower)
print(pipeline(" Hello World ")) # "HELLO WORLD"
# Deep dictionary merge
dicts = [{"a": 1}, {"b": 2, "c": 3}, {"d": 4}]
merged = reduce(lambda acc, d: {**acc, **d}, dicts) # {"a":1,"b":2,"c":3,"d":4}
functools.wraps
from functools import wraps
import time, logging
logger = logging.getLogger(__name__)
def log_calls(func):
@wraps(func) # preserves __name__, __doc__, __wrapped__, __annotations__
def wrapper(*args, **kwargs):
logger.info(f"Calling {func.__name__}")
result = func(*args, **kwargs)
logger.info(f"Done {func.__name__}")
return result
return wrapper
def measure(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs)
elapsed = time.perf_counter() - start
print(f"{func.__name__}: {elapsed*1000:.2f}ms")
return result
return wrapper
@log_calls
@measure
def process_data(data: list) -> list:
return sorted(data)
# Without @wraps, process_data.__name__ would be "wrapper"
print(process_data.__name__) # "process_data" (correct!)
functools.total_ordering
from functools import total_ordering
@total_ordering # generates __le__, __lt__, __ge__, __gt__ from __eq__ and one comparison
class Version:
def __init__(self, major: int, minor: int, patch: int = 0):
self.major = major
self.minor = minor
self.patch = patch
def __eq__(self, other: object) -> bool:
if not isinstance(other, Version):
return NotImplemented
return (self.major, self.minor, self.patch) == (other.major, other.minor, other.patch)
def __lt__(self, other: "Version") -> bool:
return (self.major, self.minor, self.patch) < (other.major, other.minor, other.patch)
def __repr__(self) -> str:
return f"Version({self.major}.{self.minor}.{self.patch})"
versions = [Version(2, 0), Version(1, 9, 5), Version(3, 0), Version(1, 9, 4)]
print(sorted(versions)) # [1.9.4, 1.9.5, 2.0, 3.0]
print(Version(1, 9) < Version(2, 0)) # True
print(Version(3, 0) >= Version(2, 1)) # True (generated!)
functools.singledispatch — পদ্ধতি ওভারলোডিং
from functools import singledispatch
@singledispatch
def process(obj):
raise TypeError(f"Cannot process {type(obj)}")
@process.register(int)
def _(obj: int) -> str:
return f"Integer: {obj}"
@process.register(str)
def _(obj: str) -> str:
return f"String: '{obj}'"
@process.register(list)
def _(obj: list) -> str:
return f"List with {len(obj)} items"
@process.register(dict)
def _(obj: dict) -> str:
return f"Dict with {len(obj)} keys: {list(obj.keys())}"
print(process(42)) # "Integer: 42"
print(process("hello")) # "String: 'hello'"
print(process([1, 2, 3])) # "List with 3 items"
# Useful for serialization/display of varied types without isinstance chains
functools.cached_property
from functools import cached_property
import statistics
class Dataset:
def __init__(self, data: list[float]):
self._data = data
@cached_property
def mean(self) -> float:
print("Computing mean...")
return statistics.mean(self._data)
@cached_property
def stdev(self) -> float:
print("Computing stdev...")
return statistics.stdev(self._data)
@cached_property
def sorted_data(self) -> list[float]:
print("Sorting...")
return sorted(self._data)
ds = Dataset([3, 1, 4, 1, 5, 9, 2, 6])
print(ds.mean) # "Computing mean..." then value
print(ds.mean) # value directly (cached)
print(ds.stdev) # "Computing stdev..." then value
পরিষ্কার, দক্ষ কোডের জন্য 2026 সালে Python functools অপরিহার্য। মেমোাইজেশনের জন্য @cache ব্যবহার করুন, কনফিগারেশন ইনজেকশনের জন্য আংশিক(), ডেকোরেটর ট্রান্সপারেন্সির জন্য @wraps, তুলনা ক্লাসের জন্য @total_ordering, টাইপ-ভিত্তিক প্রেরণের জন্য @singledispatch এবং অলস কম্পিউটেড অ্যাট্রিবিউটের জন্য ক্যাশেড_প্রপার্টি ব্যবহার করুন। এই সরঞ্জামগুলি বয়লারপ্লেট প্রতিস্থাপন করে এবং অভিপ্রায় স্পষ্ট করে।
🔗 Share this article
✍️ Leave a Comment