Practical Use Cases
Data Validation in Real-World Applications
Financial Transaction Validation
class MonetaryValue:
def __init__(self, currency='USD'):
self._value = 0
self._currency = currency
def __get__(self, obj, objtype=None):
return self._value
def __set__(self, obj, value):
if not isinstance(value, (int, float)):
raise TypeError("Value must be a number")
if value < 0:
raise ValueError("Monetary value cannot be negative")
self._value = round(value, 2)
class BankAccount:
balance = MonetaryValue()
overdraft_limit = MonetaryValue()
def __init__(self, initial_balance=0):
self.balance = initial_balance
self.overdraft_limit = 500
Configuration Management
class ConfigurationSetting:
def __init__(self, default=None, validator=None):
self._value = default
self._validator = validator
def __get__(self, obj, objtype=None):
return self._value
def __set__(self, obj, value):
if self._validator and not self._validator(value):
raise ValueError("Invalid configuration value")
self._value = value
def positive_integer(value):
return isinstance(value, int) and value > 0
class ServerConfig:
max_connections = ConfigurationSetting(default=100, validator=positive_integer)
timeout = ConfigurationSetting(default=30, validator=positive_integer)
Use Case Scenarios
Scenario |
Descriptor Benefit |
Example Application |
Input Validation |
Centralized validation |
Form data processing |
Configuration Management |
Controlled attribute access |
System settings |
Data Transformation |
Automatic type conversion |
Data processing pipelines |
Lazy Loading and Caching
class LazyLoadedProperty:
def __init__(self, function):
self._function = function
self._value = None
self._computed = False
def __get__(self, obj, objtype=None):
if not self._computed:
self._value = self._function(obj)
self._computed = True
return self._value
class DataProcessor:
@LazyLoadedProperty
def expensive_computation(self):
## Simulate expensive data processing
import time
time.sleep(2)
return sum(range(1000000))
Logging and Monitoring Descriptor
class LoggedAttribute:
def __init__(self):
self._value = None
def __get__(self, obj, objtype=None):
print(f"Accessing {self._value}")
return self._value
def __set__(self, obj, value):
print(f"Setting value to {value}")
self._value = value
class SystemMonitor:
cpu_usage = LoggedAttribute()
memory_usage = LoggedAttribute()
Descriptor Workflow
graph TD
A[Attribute Access] --> B{Descriptor Defined?}
B -->|Yes| C[Invoke Descriptor Method]
B -->|No| D[Standard Attribute Access]
C --> E{Validation Required?}
E -->|Yes| F[Perform Validation]
E -->|No| G[Return/Set Value]
F --> H{Validation Passed?}
H -->|Yes| G
H -->|No| I[Raise Exception]
LabEx Pro Tip
Descriptors provide a powerful abstraction for implementing complex attribute management strategies across various domains, from data validation to performance optimization.
Advanced Considerations
- Performance implications of descriptor methods
- Interaction with inheritance and method resolution order
- Combining multiple descriptor techniques
- Debugging and tracing descriptor behavior