π¦ Python Wrapper Class β Decorators, Proxies, and Logging
π§² Introduction β What Are Wrapper Classes in Python?
In Python, a wrapper class is a class that encapsulates or wraps another object or function. It allows you to:
- Extend or modify the behavior of an existing object
- Add pre- or post-processing around method calls
- Log, validate, or restrict access to external objects
- Implement design patterns like decorator, proxy, or adapter
Wrapper classes are a clean way to reuse logic without modifying the original object or function.
π― In this guide, you’ll learn:
- What wrapper classes are in Python
- How to create them manually
- Real-world examples (logging, validation, decorators)
- Best practices and use cases
β What Is a Wrapper Class?
A wrapper class is a custom class that contains another class or function and interacts with it by forwarding calls, often with added logic.
Basic Structure:
class Wrapper:
def __init__(self, obj):
self._obj = obj
def method(self):
# Custom behavior
return self._obj.method()
π§ͺ Example β Wrapping a Class
class Calculator:
def add(self, a, b):
return a + b
class CalculatorWrapper:
def __init__(self, calculator):
self._calculator = calculator
def add(self, a, b):
print(f"Adding {a} + {b}")
return self._calculator.add(a, b)
c = Calculator()
w = CalculatorWrapper(c)
print(w.add(3, 4)) # Output: Adding 3 + 4 β 7
β The wrapper class adds logging before calling the original method.
π οΈ Real-World Use Case β File Access Logger
class FileWrapper:
def __init__(self, file):
self._file = file
def write(self, data):
print(f"Writing data: {data}")
self._file.write(data)
def __getattr__(self, name):
return getattr(self._file, name)
with open("log.txt", "w") as f:
fw = FileWrapper(f)
fw.write("Hello World")
fw.flush()
π‘ The wrapper logs writes while still exposing all file
methods using __getattr__
.
π§° Using Wrapper Class for Validation
class BankAccount:
def __init__(self):
self._balance = 0
def deposit(self, amount):
self._balance += amount
def withdraw(self, amount):
self._balance -= amount
def get_balance(self):
return self._balance
class SecureBankAccount:
def __init__(self, account):
self._account = account
def withdraw(self, amount):
if amount > self._account.get_balance():
raise ValueError("Insufficient funds")
self._account.withdraw(amount)
π Wrapping Functions β Manual Decorator Style
class FunctionWrapper:
def __init__(self, func):
self._func = func
def __call__(self, *args, **kwargs):
print(f"Calling {self._func.__name__} with {args}")
return self._func(*args, **kwargs)
@FunctionWrapper
def greet(name):
print(f"Hello, {name}!")
greet("Alice") # Logs the call before executing
β This is a class-based decorator, which wraps functions cleanly.
π Best Practices for Wrapper Classes
β Do This | β Avoid This |
---|---|
Use __getattr__ to proxy attributes | Rewriting all methods manually |
Keep wrappers focused and minimal | Overcomplicating logic |
Add logging, timing, validation, etc. | Mutating original object state blindly |
Use class-based decorators when needed | Wrapping just for fun |
π Summary β Recap & Next Steps
Python wrapper classes help you extend or control the behavior of existing objects without modifying them. They’re commonly used in logging, security, adapters, and decorators.
π Key Takeaways:
- β A wrapper class wraps another object/function
- β It forwards calls while adding behavior like logging or validation
- β
Use
__getattr__
to expose wrapped attributes dynamically - β Ideal for decorator, proxy, and adapter patterns
βοΈ Real-World Relevance:
Used in web frameworks, testing mocks, API wrappers, and third-party library extensions.
β FAQ β Python Wrapper Classes
β What is a wrapper class in Python?
β A wrapper class is a class that encapsulates another object to extend or alter its behavior.
β How do I forward method calls from the wrapper to the original?
β
Use __getattr__()
:
def __getattr__(self, name):
return getattr(self._obj, name)
β What are wrapper classes used for?
β Logging, access control, validation, mocking, adapting third-party libraries, and decorators.
β Can I wrap a function using a class?
β
Yes. Use __call__()
in the class to make it behave like a function (i.e., a class-based decorator).
β Is this the same as inheritance?
β No. A wrapper uses composition (has-a relationship), not inheritance (is-a relationship).
Share Now :