Các mẫu thiết kế lập trình function trong Python

Các mẫu thiết kế lập trình function trong Python

Lập trình hàm (functional programming) trong Python không chỉ là dùng map, filter, reduce. Các mẫu thiết kế (design patterns) hàm giúp code ngắn gọn, dễ test, ít bug và tận dụng đa nhân. Bài viết này giới thiệu 7 pattern phổ biến nhất.

Sơ đồ khái niệm cơ bản về pure function và impure function trong lập trình

1. Pure Functions (Hàm thuần túy)

Hàm thuần túy: cùng input luôn cho cùng output, không side effect (không sửa global state, không I/O, không mutate argument).

# Pure
def add(a, b):
    return a + b

# Impure - mutates argument
def append_item(lst, item):
    lst.append(item)  # side effect!
    return lst

# Pure version
def append_item_pure(lst, item):
    return lst + [item]

Lợi ích: Dễ test (không cần mock), dễ cache (memoization), an toàn cho đa luồng, dễ reasoning.

2. Higher-Order Functions (Hàm bậc cao)

Hàm nhận hàm khác làm tham số hoặc trả về hàm. Python hỗ trợ first-class functions.

def apply_twice(func, x):
    return func(func(x))

def add_one(x):
    return x + 1

result = apply_twice(add_one, 5)  # 7

# Built-in higher-order functions
numbers = [1, 2, 3, 4, 5]
doubled = list(map(lambda x: x * 2, numbers))
evens = list(filter(lambda x: x % 2 == 0, numbers))

3. Function Composition (Hợp thành hàm)

Kết nối output của hàm này làm input của hàm kia. Pipeline dữ liệu một chiều.


from functools import reduce

def compose(*funcs):
    return lambda x: reduce(lambda acc, f: f(acc), funcs, x)

# Usage
process = compose(str.strip, str.lower, lambda s: s.replace(' ', '_'))
clean = process("  Hello World  ")  # "hello_world"

# Or using pipe operator (Python 3.11+)
def pipe(x, *funcs):
    for f in funcs:
        x = f(x)
    return x

result = pipe("  Hello  ", str.strip, str.upper, len)  # 5

Sơ đồ pipeline function composition với các bước xử lý dữ liệu tuần tự

4. Currying & Partial Application

Currying: biến hàm nhiều tham số thành chuỗi hàm một tham số. Partial application: fix một số tham số trước.


from functools import partial

# Currying manual
def multiply_curried(a):
    def inner(b):
        return a * b
    return inner

times_3 = multiply_curried(3)
times_3(4)  # 12

# Partial application (thực tế hơn)
def power(base, exponent):
    return base ** 2

square = partial(power, exponent=2)
cube = partial(power, exponent=3)

square(5)  # 25
cube(3)    # 27

# Real-world: config functions
def connect_db(host, port, db_name, user, password):
    pass

connect_local = partial(connect_db, host='localhost', port=5432)
connect_prod = partial(connect_db, host='prod.db.com', port=5432)

5. Decorators as Higher-Order Functions

Decorator bản chất là higher-order function: nhận function, trả về function mới mở rộng hành vi.


import time
from functools import wraps

def timer(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start = time.perf_counter()
        result = func(*args, **kwargs)
        end = time.perf_counter()
        print(f"{func.__name__} took {end - start:.4f}s")
        return result
    return wrapper

@timer
def slow_function():
    time.sleep(0.1)

# Class-based decorator with state
class CountCalls:
    def __init__(self, func):
        self.func = func
        self.count = 0
    def __call__(self, *args, **kwargs):
        self.count += 1
        print(f"Call #{self.count}")
        return self.func(*args, **kwargs)

@CountCalls
def greet(name):
    return f"Hello {name}"

6. Memoization & Caching

Cache kết quả hàm tốn kém với cùng input. functools.lru_cache là built-in.


from functools import lru_cache

@lru_cache(maxsize=128)
def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

fibonacci(50)  # Tính ngay lập tức nhờ cache

# Custom cache với TTL
import time
def ttl_cache(ttl_seconds):
    cache = {}
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            key = (args, tuple(sorted(kwargs.items())))
            now = time.time()
            if key in cache and now - cache[key][1] < ttl_seconds:
                return cache[key][0]
            result = func(*args, **kwargs)
            cache[key] = (result, now)
            return result
        return wrapper
    return decorator

7. Strategy Pattern with Functions

Thay vì class hierarchy, dùng dict map string -> function. Python làm pattern này tự nhiên.


# Thay vì class PaymentStrategy...
def pay_credit_card(amount): return f"Charged ${amount} to credit card"
def pay_paypal(amount): return f"Paid ${amount} via PayPal"
def pay_crypto(amount): return f"Sent ${amount} in BTC"

STRATEGIES = {
    'credit': pay_credit_card,
    'paypal': pay_paypal,
    'crypto': pay_crypto,
}

def process_payment(method, amount):
    strategy = STRATEGIES.get(method)
    if not strategy:
        raise ValueError(f"Unknown method: {method}")
    return strategy(amount)

# Dễ mở rộng: chỉ thêm entry vào dict
STRATEGIES['apple_pay'] = lambda a: f"Apple Pay: ${a}"

Kết luận

Python không ép buộc lập trình hướng đối tượng. Các pattern hàm: pure functions, higher-order functions, composition, currying/partial, decorators, memoization, function strategy giúp code ngắn, rõ ràng, dễ bảo trì. Kết hợp với type hints (Callable, Protocol) cho an toàn tĩnh.

Nguồn: Python functools docs, Real Python Functional Programming, Python Patterns repo

Tôi là một lập trình viên IOS. Code chính là IOS nhưng thỉnnh thoảng vẫn đá sang Android hoặc web. Mặc dù không quá thông thạo nhưng tôi sẽ chia sẻ những kiến thức mà mình đã tìm hiểu, áp dụng qua.

Bài viết liên quan

OpenTelemetry Quan Sát Hệ Thống Phân Tán Từng Vết

OpenTelemetry là gì? OpenTelemetry là bộ công cụ mã nguồn mở, vendor-neutral để thu thập, export và quản lý tín hiệu quan sát từ hệ thống phân tán. Ba loại…

Xem thêm

Effective Go 1.23: Tính năng mới và best practices hiện đại

Go 1.23 phát hành tháng 8/2024 mang đến nhiều cải tiến quan trọng: iterators, telemetry, toolchain directives, và nhiều thay đổi trong standard library. Bài viết này tổng hợp những…

Xem thêm

GraphQL vs REST API: Lựa chọn cho dịch vụ web hiện đại?

GraphQL vs REST API: Lựa chọn cho dịch vụ web hiện đại? Khi xây dựng dịch vụ web hiện đại, GraphQL vs REST API là câu hỏi hàng đầu mỗi…

Xem thêm
0 0 đánh giá
Article Rating
Theo dõi
Thông báo của
guest
0 Comments
Cũ nhất
Mới nhất Được bỏ phiếu nhiều nhất