Khóa học python

Wrapper Class trong Python

0 phút đọc

Trong Python, wrapper class là một khái niệm quan trọng trong lập trình hướng đối tượng (OOP). Wrapper class được sử dụng để "bọc" (wrap) một đối tượng hoặc một hàm, cung cấp thêm chức năng hoặc thay đổi hành vi của đối tượng hoặc hàm đó mà không cần thay đổi mã nguồn gốc. Bài viết này sẽ hướng dẫn chi tiết về wrapper class trong Python, kèm theo các ví dụ minh họa cụ thể.

Giới thiệu về Wrapper Class

Wrapper Class là gì?

Wrapper class là một lớp được thiết kế để bao bọc một đối tượng hoặc một hàm, cung cấp thêm chức năng hoặc thay đổi hành vi của đối tượng hoặc hàm đó. Wrapper class thường được sử dụng để thêm các tính năng như logging, caching, kiểm tra quyền truy cập, và nhiều hơn nữa.

Lợi ích của Wrapper Class

  • Tái sử dụng mã nguồn: Wrapper class cho phép bạn tái sử dụng mã nguồn bằng cách thêm chức năng mới mà không cần thay đổi mã nguồn gốc.
  • Tách biệt mối quan tâm: Wrapper class giúp tách biệt các mối quan tâm khác nhau trong mã nguồn, làm cho mã dễ đọc và bảo trì hơn.
  • Thêm chức năng một cách linh hoạt: Bạn có thể dễ dàng thêm hoặc thay đổi chức năng của đối tượng hoặc hàm bằng cách sử dụng wrapper class.

Tạo Wrapper Class trong Python

Ví dụ cơ bản về Wrapper Class

Dưới đây là một ví dụ cơ bản về wrapper class trong Python. Chúng ta sẽ tạo một wrapper class để thêm chức năng logging cho một đối tượng.

class LoggerWrapper:
    def __init__(self, wrapped):
        self._wrapped = wrapped

    def __getattr__(self, name):
        attr = getattr(self._wrapped, name)
        if callable(attr):
            def wrapper(*args, **kwargs):
                print(f"Calling method {name} with arguments {args} and {kwargs}")
                result = attr(*args, **kwargs)
                print(f"Method {name} returned {result}")
                return result
            return wrapper
        else:
            return attr

class Calculator:
    def add(self, a, b):
        return a + b

    def multiply(self, a, b):
        return a * b

# Tạo đối tượng Calculator và LoggerWrapper
calc = Calculator()
wrapped_calc = LoggerWrapper(calc)

# Sử dụng đối tượng wrapped_calc
print(wrapped_calc.add(3, 5))
print(wrapped_calc.multiply(4, 6))

Output:

Calling method add with arguments (3, 5) and {}
Method add returned 8
8
Calling method multiply with arguments (4, 6) and {}
Method multiply returned 24
24

Sử dụng __getattr____setattr__

Trong ví dụ trên, chúng ta sử dụng phương thức __getattr__ để chuyển tiếp các thuộc tính và phương thức từ đối tượng được bọc (wrapped object) sang wrapper class. Phương thức __setattr__ có thể được sử dụng để xử lý việc gán giá trị cho các thuộc tính.

class LoggerWrapper:
    def __init__(self, wrapped):
        self._wrapped = wrapped

    def __getattr__(self, name):
        attr = getattr(self._wrapped, name)
        if callable(attr):
            def wrapper(*args, **kwargs):
                print(f"Calling method {name} with arguments {args} and {kwargs}")
                result = attr(*args, **kwargs)
                print(f"Method {name} returned {result}")
                return result
            return wrapper
        else:
            return attr

    def __setattr__(self, name, value):
        if name == "_wrapped":
            super().__setattr__(name, value)
        else:
            setattr(self._wrapped, name, value)

class Calculator:
    def __init__(self):
        self.result = 0

    def add(self, a, b):
        self.result = a + b
        return self.result

    def multiply(self, a, b):
        self.result = a * b
        return self.result

# Tạo đối tượng Calculator và LoggerWrapper
calc = Calculator()
wrapped_calc = LoggerWrapper(calc)

# Sử dụng đối tượng wrapped_calc
print(wrapped_calc.add(3, 5))
print(wrapped_calc.multiply(4, 6))
wrapped_calc.result = 100
print(wrapped_calc.result)

Output:

Calling method add with arguments (3, 5) and {}
Method add returned 8
8
Calling method multiply with arguments (4, 6) and {}
Method multiply returned 24
24
100

Ví dụ về Wrapper Class trong Python

Wrapper Class để thêm Logging

Dưới đây là một ví dụ về wrapper class để thêm chức năng logging cho một đối tượng.

class LoggerWrapper:
    def __init__(self, wrapped):
        self._wrapped = wrapped

    def __getattr__(self, name):
        attr = getattr(self._wrapped, name)
        if callable(attr):
            def wrapper(*args, **kwargs):
                print(f"Calling method {name} with arguments {args} and {kwargs}")
                result = attr(*args, **kwargs)
                print(f"Method {name} returned {result}")
                return result
            return wrapper
        else:
            return attr

class Calculator:
    def add(self, a, b):
        return a + b

    def multiply(self, a, b):
        return a * b

# Tạo đối tượng Calculator và LoggerWrapper
calc = Calculator()
wrapped_calc = LoggerWrapper(calc)

# Sử dụng đối tượng wrapped_calc
print(wrapped_calc.add(3, 5))
print(wrapped_calc.multiply(4, 6))

Output:

Calling method add with arguments (3, 5) and {}
Method add returned 8
8
Calling method multiply with arguments (4, 6) and {}
Method multiply returned 24
24

Wrapper Class để thêm Caching

Dưới đây là một ví dụ về wrapper class để thêm chức năng caching cho một đối tượng.

class CacheWrapper:
    def __init__(self, wrapped):
        self._wrapped = wrapped
        self._cache = {}

    def __getattr__(self, name):
        attr = getattr(self._wrapped, name)
        if callable(attr):
            def wrapper(*args, **kwargs):
                key = (name, args, tuple(kwargs.items()))
                if key in self._cache:
                    print(f"Returning cached result for {name} with arguments {args} and {kwargs}")
                    return self._cache[key]
                result = attr(*args, **kwargs)
                self._cache[key] = result
                return result
            return wrapper
        else:
            return attr

class Calculator:
    def add(self, a, b):
        return a + b

    def multiply(self, a, b):
        return a * b

# Tạo đối tượng Calculator và CacheWrapper
calc = Calculator()
wrapped_calc = CacheWrapper(calc)

# Sử dụng đối tượng wrapped_calc
print(wrapped_calc.add(3, 5))
print(wrapped_calc.add(3, 5))  # Sử dụng kết quả từ cache
print(wrapped_calc.multiply(4, 6))
print(wrapped_calc.multiply(4, 6))  # Sử dụng kết quả từ cache

Output:

8
Returning cached result for add with arguments (3, 5) and {}
8
24
Returning cached result for multiply with arguments (4, 6) and {}
24

Sử dụng Decorator để Tạo Wrapper Class

Decorator là gì?

Decorator là một hàm hoặc lớp được sử dụng để "bọc" một hàm hoặc lớp khác, thêm chức năng hoặc thay đổi hành vi của hàm hoặc lớp đó. Decorator thường được sử dụng để tạo các wrapper class một cách ngắn gọn và dễ đọc.

Ví dụ về Decorator để thêm Logging

Dưới đây là một ví dụ về decorator để thêm chức năng logging cho một hàm.

def log_decorator(func):
    def wrapper(*args, **kwargs):
        print(f"Calling function {func.__name__} with arguments {args} and {kwargs}")
        result = func(*args, **kwargs)
        print(f"Function {func.__name__} returned {result}")
        return result
    return wrapper

@log_decorator
def add(a, b):
    return a + b

@log_decorator
def multiply(a, b):
    return a * b

# Sử dụng các hàm được bọc bởi decorator
print(add(3, 5))
print(multiply(4, 6))

Output:

Calling function add with arguments (3, 5) and {}
Function add returned 8
8
Calling function multiply with arguments (4, 6) and {}
Function multiply returned 24
24

Ví dụ về Decorator để thêm Caching

Dưới đây là một ví dụ về decorator để thêm chức năng caching cho một hàm.

def cache_decorator(func):
    cache = {}
    def wrapper(*args, **kwargs):
        key = (args, tuple(kwargs.items()))
        if key in cache:
            print(f"Returning cached result for {func.__name__} with arguments {args} and {kwargs}")
            return cache[key]
        result = func(*args, **kwargs)
        cache[key] = result
        return result
    return wrapper

@cache_decorator
def add(a, b):
    return a + b

@cache_decorator
def multiply(a, b):
    return a * b

# Sử dụng các hàm được bọc bởi decorator
print(add(3, 5))
print(add(3, 5))  # Sử dụng kết quả từ cache
print(multiply(4, 6))
print(multiply(4, 6))  # Sử dụng kết quả từ cache

Output:

8
Returning cached result for add with arguments (3, 5) and {}
8
24
Returning cached result for multiply with arguments (4, 6) and {}
24

Các Thực Hành Tốt Nhất khi Sử Dụng Wrapper Class

Giữ cho Wrapper Class Đơn Giản

Wrapper class nên giữ cho mã nguồn đơn giản và dễ hiểu. Tránh thêm quá nhiều chức năng vào một wrapper class duy nhất.

Sử dụng Decorator khi Có Thể

Decorator cung cấp một cách ngắn gọn và dễ đọc để tạo các wrapper class. Sử dụng decorator khi có thể để giữ cho mã nguồn gọn gàng và dễ bảo trì.

Kiểm Tra Kỹ Lưỡng

Kiểm tra kỹ lưỡng các wrapper class để đảm bảo rằng chúng hoạt động đúng và không gây ra lỗi không mong muốn.

Kết luận

Wrapper class là một công cụ mạnh mẽ trong Python, cho phép bạn thêm chức năng hoặc thay đổi hành vi của đối tượng hoặc hàm mà không cần thay đổi mã nguồn gốc. Bằng cách sử dụng wrapper class và decorator, bạn có thể giữ cho mã nguồn của mình gọn gàng, dễ bảo trì và dễ mở rộng. Hy vọng rằng các ví dụ và hướng dẫn trong bài viết này sẽ giúp bạn hiểu rõ hơn về cách tạo và sử dụng wrapper class trong Python.

Avatar
Được viết bởi

TechMely Team

Gợi ý câu hỏi phỏng vấn

Gợi ý bài viết

Bình luận

Chưa có bình luận nào

Khoá học javascript từ cơ bản đến chuyên sâuYoutube Techmely