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.
python
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__
và __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.
python
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.
python
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.
python
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.
python
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.
python
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.