Posted in

Python Functions nâng cao: Từ lambda đến decorators và best practices

Lambda decorators and best practices
Lambda decorators and best practices

Trong Python, functions không chỉ dừng lại ở mức định nghĩa cơ bản với def, tham số hay giá trị trả về. Bên cạnh đó còn có nhiều kỹ thuật nâng cao giúp việc viết hàm trở nên linh hoạt, hiệu quả và chuyên nghiệp hơn. Trong bài viết này, mình và bạn hãy cùng tìm hiểu những công cụ mạnh mẽ như lambda functions, higher-order functions, recursion, decorators, cũng như cách sử dụng function annotations và type hints để tăng tính rõ ràng cho code. Ngoài ra, bài viết cũng tổng hợp một số best practices quan trọng, giúp bạn xây dựng functions an toàn, dễ bảo trì và tối ưu hơn cho các dự án thực tế.

1. Lambda functions

Lambda là hàm anonymous (không tên) viết gọn trên một dòng bằng từ khóa lambda. Dùng tốt khi cần hàm nhỏ, tạm thời, thường xuất hiện cùng map, filter, sorted, v.v.

Syntax:

lambda parameters: expression

Ví dụ cơ bản

# square function using lambda
square = lambda x: x * x  # anonymous function assigned to name
print(square(5))  # Output: 25

With map / filter / sorted

numbers = [1, 2, 3, 4, 5]

# map: apply lambda to each element
squares = list(map(lambda x: x * x, numbers))
# Output: [1, 4, 9, 16, 25]

# filter: select elements
evens = list(filter(lambda x: x % 2 == 0, numbers))
# Output: [2, 4]

# sorted with custom key
words = ["apple", "Banana", "cherry"]
sorted_by_lower = sorted(words, key=lambda s: s.lower())
# Output: ['apple', 'Banana', 'cherry']

Notes / Cautions

  • Lambda nên ngắn và đơn giản. Nếu logic phức tạp, hãy dùng def để có tên rõ ràng và docstring.
  • Lambda không thay thế function có ý nghĩa (named function) trong code sản xuất vì khó debug và thiếu docstring.

2. Higher-order functions (HOF)

Higher-order functions là hàm nhận hàm làm tham số hoặc trả về hàm. Python coi hàm là first-class objects, nên HOF rất phổ biến.

Truyền function như tham số

def apply_operation(data, operation):
    """Apply operation to each item in data and return result list"""
    return [operation(x) for x in data]

def increment(x):
    return x + 1

values = [1, 2, 3]
print(apply_operation(values, increment))  # [2, 3, 4]

map, filter, reduce

  • map(func, iterable) — trả về iterator áp dụng func cho từng phần tử.
  • filter(func, iterable) — giữ phần tử khi func(element)True.
  • functools.reduce(func, iterable, initializer?) — gộp các phần tử lại.
from functools import reduce

nums = [1, 2, 3, 4]

# map
doubled = list(map(lambda x: x * 2, nums))  # [2, 4, 6, 8]

# filter
positive = list(filter(lambda x: x > 0, nums))  # [1, 2, 3, 4]

# reduce: compute factorial-like product
product = reduce(lambda a, b: a * b, nums)  # 24

List comprehensions vs map/filter

  • List comprehensions thường rõ ràng hơn và idiomatic trong Python.
  • map/filter có thể ngắn gọn khi kết hợp với lambda hoặc khi cần lazy evaluation (khi không chuyển về list ngay lập tức).

3. Recursion (Đệ quy)

Recursion: hàm gọi chính nó để giải quyết bài toán bằng cách chia nhỏ. Cần điểm dừng (base case) để tránh đệ quy vô hạn.

Example: factorial

def factorial(n):
    """Return factorial of n (n!)"""
    if n == 0:
        return 1
    return n * factorial(n - 1)

Fibonacci — naive vs memoized
Naive recursive Fibonacci có độ phức tạp n^2 (thực tế là exponential), rất chậm:

def fib_naive(n):
    if n < 2:
        return n
    return fib_naive(n - 1) + fib_naive(n - 2)

Dùng memoization (functools.lru_cache) để tối ưu:

from functools import lru_cache

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

Notes

  • CPython không hỗ trợ tail-call optimization — tránh viết recursion quá sâu; dùng iteration hoặc convert algorithm khi cần.
  • lru_cache rất hữu ích cho hàm thuần (pure) có nhiều tái sử dụng kết quả.

4. Decorator functions

Decorator là cách mở rộng hành vi của hàm mà không thay đổi mã nguồn gốc. Cú pháp @decorator đặt phía trên định nghĩa hàm.

  • Decorator logging đơn giản (Simple logging decorator)
import functools
import time

def timing_decorator(func):
    """A decorator that measures execution time"""
    @functools.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:.6f}s")
        return result
    return wrapper

@timing_decorator
def compute(n):
    """Compute sum of squares up to n"""
    return sum(i * i for i in range(n))

compute(100000)  # prints timing info
  • Decorator có tham số (decorator factory)
def repeat(times):
    """Create a decorator that repeats function call `times` times"""
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            result = None
            for _ in range(times):
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

@repeat(3)
def say_hi():
    print("Hi")

say_hi()  # prints "Hi" three times
  • Best practices for decorators
    • Luôn dùng functools.wraps để giữ lại metadata của hàm gốc (__name__, __doc__).
    • Giữ logic trong decorator độc lập, tránh side-effect ẩn.
    • Sử dụng decorator để tách cross-cutting concerns như logging, caching, authentication, rate-limiting.

5. Function annotations & type hints

Basic syntax

Type hints (PEP 484) giúp document code, hỗ trợ tooling (mypy, IDEs), nhưng không bắt buộc lúc runtime.

def greet(name: str, age: int = 18) -> str:
    """Return a greeting message"""
    return f"Hello {name}, you are {age}"

Using typing module

from typing import List, Optional, Callable

def process_items(items: List[int]) -> List[int]:
    return [i * 2 for i in items]

def apply_func(x: int, func: Callable[[int], int]) -> int:
    return func(x)

Optional & Union

from typing import Optional, Union

def parse_int(s: str) -> Optional[int]:
    try:
        return int(s)
    except ValueError:
        return None

def handle_value(v: Union[int, str]) -> str:
    return str(v)

Notes

  • Type hints improve readability and giúp static analysis phát hiện lỗi sớm.
  • Thực thi runtime type checking cần thư viện bên thứ ba (vd. typeguard, pydantic) nếu muốn enforce types.

6. Best practices khi viết function

Dưới đây là danh sách chi tiết các nguyên tắc và lý do thực tế khi áp dụng.

1. Hàm nhỏ và một nhiệm vụ duy nhất( Small & Single Responsibility)

  • Mỗi hàm chỉ nên làm một việc (SRP — Single Responsibility Principle).
  • Dễ test, dễ reuse.

2. Đặt tên rõ ràng (Clear naming)

  • Dùng snake_case, tên động từ cho hành động (get_user, calculate_tax).
  • Tránh viết tắt không rõ nghĩa.

3. Docstrings

  • Viết docstring ngắn gọn: mục đích, tham số, giá trị trả về, ngoại lệ.
  • Theo Google/NumPy style hoặc reStructuredText tùy team.

4. Tránh dùng giá trị mặc định có thể thay đổi (Avoid mutable default arguments)

# bad
def add_item(item, lst=[]):
    lst.append(item)
    return lst

# good
def add_item(item, lst=None):
    if lst is None:
        lst = []
    lst.append(item)
    return lst

5. Ưu tiên sử dụng hàm thuần (pure function) khi có thể ( Prefer pure functions when possible)

  • Pure = không có side-effect, cùng input luôn trả về cùng output.
  • Giúp test dễ hơn và dùng cache hiệu quả.

6. Xử lý lỗi bằng ngoại lệ (exceptions) (Handle errors with exceptions (not special return values))

  • Raise specific exceptions; document them trong docstring.
  • Ví dụ: raise ValueError("invalid age").

7. Sử dụng type hints (Use typing)

  • Thêm type hints để hỗ trợ IDE và static checking.

8. Giữ thứ tự tham số nhất quán(Keep parameter order consistent)

  • Positional required paramsoptional params *args **kwargs.
  • Consider using keyword-only arguments (*, or Python 3 keyword-only syntax) để tránh sai tham số.

9.Tận dụng thư viện chuẩn (Leverage standard library)

  • functools.partial, itertools cho performance and clarity.
  • functools.lru_cache cho caching các hàm thuần.

10. Viết test cho hàm (Write tests)

  • Unit tests cho từng hàm, dùng fixtures/parametrized tests để cover edge cases.

11. Thực hiện profiling và tối ưu khi cần (Profiling & optimization)

  • Profile only when needed; avoid premature optimization.
  • For heavy computations, consider algorithms, data structures, or C extensions / numpy.

12. Ghi chú độ phức tạp (Document complexity)

  • Nếu hàm có độ phức tạp thuật toán đáng kể, ghi chú time/space complexity trong docstring.

7. Kết luận

Mình và bạn vừa cùng nhau đi qua một chặng đường khá thú vị về functions trong Python – từ các khái niệm quen thuộc đến những kỹ thuật nâng cao như lambda functions, higher-order functions (map, filter, reduce, truyền hàm), recursion và cách tối ưu bằng memoization, decorator để mở rộng hành vi hàm, cho tới function annotations, type hints và cả bộ best practices thực tiễn.

Những kiến thức này không chỉ giúp code của chúng ta ngắn gọn và rõ ràng hơn, mà còn giúp tận dụng tối đa sức mạnh của Python với first-class functions và thư viện chuẩn cực kỳ phong phú.

Ở các phần tiếp theo, mình và bạn có thể cùng khám phá thêm các chủ đề hay ho hơn nữa: asynchronous functions (async/await), generators & coroutines, các decorator nâng cao, hay thậm chí là design patterns dựa trên functions – để kỹ năng Python của chúng ta ngày càng “xịn” hơn.


8. Tài liệu tham khảo (theo APA 7th edition)

  1. Python Software Foundation. (n.d.). The Python Tutorial: Defining functions; Lambda expressions; Decorators. Python.org. Retrieved September 27, 2025, from https://docs.python.org/3/tutorial/
  2. Python Software Foundation. (n.d.). functools — Higher-order functions and operations on callable objects. Python.org. Retrieved September 27, 2025, from https://docs.python.org/3/library/functools.html
  3. van Rossum, G., & Warsaw, B., & Coghlan, N. (n.d.). PEP 8 — Style Guide for Python Code. Python.org. Retrieved September 27, 2025, from https://peps.python.org/pep-0008/
  4. PEP 484. (n.d.). Type Hints. Python.org. Retrieved September 27, 2025, from https://peps.python.org/pep-0484/
  5. Sweigart, A. (2019). Automate the Boring Stuff with Python (2nd ed.). No Starch Press.
  6. Lutz, M. (2013). Learning Python (5th ed.). O’Reilly Media.

Leave a Reply

Your email address will not be published. Required fields are marked *