Creating Custom Proxies
Advanced Proxy Design Patterns
class ProxyMeta(type):
def __new__(cls, name, bases, attrs):
## Add logging or validation logic
attrs['_proxy_created'] = True
return super().__new__(cls, name, bases, attrs)
class LoggingProxy(metaclass=ProxyMeta):
def __init__(self, target):
self._target = target
def __getattr__(self, name):
print(f"Accessing method: {name}")
return getattr(self._target, name)
Descriptor-Based Proxies
class AccessControlDescriptor:
def __init__(self, permissions=None):
self.permissions = permissions or {}
def __get__(self, instance, owner):
def wrapper(method):
def check_access(*args, **kwargs):
## Implement access control logic
if self.check_permission(method.__name__):
return method(*args, **kwargs)
raise PermissionError("Access denied")
return check_access
return wrapper
def check_permission(self, method_name):
return self.permissions.get(method_name, False)
Comprehensive Proxy Implementation
class ComplexProxy:
def __init__(self, target):
self._target = target
self._cache = {}
def __getattr__(self, name):
## Caching mechanism
if name not in self._cache:
method = getattr(self._target, name)
def cached_method(*args, **kwargs):
cache_key = (name, args, frozenset(kwargs.items()))
if cache_key not in self._cache:
self._cache[cache_key] = method(*args, **kwargs)
return self._cache[cache_key]
return cached_method
return self._cache[name]
Proxy Design Patterns
graph TD
A[Base Proxy] --> B[Virtual Proxy]
A --> C[Protection Proxy]
A --> D[Caching Proxy]
A --> E[Logging Proxy]
Proxy Pattern Comparison
| Proxy Type |
Key Characteristics |
Use Case |
| Virtual Proxy |
Lazy Loading |
Resource Management |
| Protection Proxy |
Access Control |
Security |
| Caching Proxy |
Result Memoization |
Performance Optimization |
| Logging Proxy |
Method Tracking |
Debugging |
Advanced Proxy Techniques
Decorator-Based Proxies
def proxy_decorator(cls):
class ProxyWrapper:
def __init__(self, *args, **kwargs):
self._wrapped = cls(*args, **kwargs)
def __getattr__(self, name):
print(f"Accessing: {name}")
return getattr(self._wrapped, name)
return ProxyWrapper
Error Handling in Proxies
class RobustProxy:
def __init__(self, target):
self._target = target
def __getattr__(self, name):
try:
method = getattr(self._target, name)
def safe_method(*args, **kwargs):
try:
return method(*args, **kwargs)
except Exception as e:
print(f"Error in {name}: {e}")
raise
return safe_method
except AttributeError:
raise AttributeError(f"Method {name} not found")
LabEx Proxy Best Practices
At LabEx, we recommend:
- Keep proxy logic minimal and focused
- Use proxies for cross-cutting concerns
- Implement clear error handling
- Profile performance impact
- Minimal overhead for simple proxies
- Significant impact for complex proxy logic
- Use caching and lazy evaluation strategically