Advanced Techniques
Abstract Base Classes and Protocol Verification
Python provides advanced techniques to enhance duck typing with more structured approaches:
from abc import ABC, abstractmethod
from typing import Protocol
## Abstract Base Class Approach
class DataProcessor(ABC):
@abstractmethod
def process(self, data):
pass
## Protocol-based Approach
class Processable(Protocol):
def process(self, data) -> str:
...
def validate_processor(processor):
try:
hasattr(processor, 'process')
except AttributeError:
raise TypeError("Invalid processor")
Dynamic Method Resolution
graph TD
A[Dynamic Method Resolution] --> B[getattr()]
A --> C[hasattr()]
A --> D[__getattribute__()]
Advanced method resolution techniques:
class FlexibleObject:
def __getattr__(self, name):
def dynamic_method(*args, **kwargs):
print(f"Dynamically called method: {name}")
return dynamic_method
class SmartProxy:
def __init__(self, target):
self._target = target
def __getattr__(self, name):
return getattr(self._target, name)
| Technique |
Description |
Use Case |
| Custom Metaclass |
Modify class creation |
Advanced type checking |
| Dynamic Attribute Injection |
Add methods at runtime |
Flexible object manipulation |
| Protocol Enforcement |
Validate object capabilities |
Robust interface design |
Advanced Implementation Example
class DuckTypingMetaclass(type):
def __new__(cls, name, bases, attrs):
## Enforce method requirements
required_methods = ['process', 'validate']
for method in required_methods:
if method not in attrs:
raise TypeError(f"Missing required method: {method}")
return super().__new__(cls, name, bases, attrs)
class AdvancedProcessor(metaclass=DuckTypingMetaclass):
def process(self, data):
return data.upper()
def validate(self, data):
return len(data) > 0
## Runtime method composition
def compose_methods(obj, method_name, new_implementation):
setattr(obj.__class__, method_name, new_implementation)
## LabEx-style flexible object manipulation
processor = AdvancedProcessor()
compose_methods(processor, 'transform', lambda self, x: x.lower())
import dis
import timeit
def analyze_method_resolution():
def duck_typed_method(obj):
obj.process()
def type_checked_method(obj):
if hasattr(obj, 'process'):
obj.process()
## Bytecode and performance analysis
print(dis.dis(duck_typed_method))
print(timeit.timeit(duck_typed_method, number=10000))
Error Handling and Introspection
def safe_method_call(obj, method_name, *args, **kwargs):
try:
method = getattr(obj, method_name)
return method(*args, **kwargs)
except AttributeError:
print(f"Object lacks {method_name} method")
except Exception as e:
print(f"Error during method call: {e}")
By mastering these advanced techniques, Python developers can create more dynamic, flexible, and powerful code structures that leverage the full potential of duck typing.