Motivation
I have singleton objects I am replacing with new instances. I want to be sure that nobody uses stale references to invalidated objects. I have tried a few solutions (listed below) that haven't worked and now I'm wondering if this is a fools errand.
My desired user experience is something like
singleton = OriginalClass()
user_variable = singleton
...
make_radioactive(singleton)
singleton = NewSingletonClass()
# User code should also update here but what if they dont?
...
# If they didn't update correctly I want this to break
user_variable.do_something()
Exception: Object has been invalidated
Requirements:
- No added overhead to object before it is destroyed/deprecated
- Any attribute access or method calls on the old instance throws an exception of my choosing
- The new instance of singleton may be of the same or different type
Approaches considered and rejected
1: Override getattribute at runtime
def make_radioactive(some_object):
def throw(self, name):
raise Exception("Using an invalidated instance")
some_object.__getattribute__ = throw
I was hopeful about this but it does not work because of special method lookup rules. __getattribute__
is accessed through the class not the instance and monkeypatching it on the class would invalidate all instances not just one of them.
2: Erase __dict__
def make_radioactive(some_object):
some_object.__dict__ = {}
This is close to what I want but the exception users would see is
AttributeError: 'ClassType' object has no attribute 'attribute_name'
instead of
MyCustomExceptionType: You used an invalidated instance
And it only works on variables not methods
3: Require common base class and override __getattribute__
class Destroyable(abc.ABC):
def __init__(self):
self.__radioactive = False
def make_radioactive(self):
self.__radioactive = True
def __getattribute__(self, name):
if object.__getattribute__(self, '_radioactive'):
raise MyCustomException("Accessed an inavlidated object")
return object.__getattribute__(self, name)
This gives me a custom exception message but requires inheriting from a base class and adds overhead to normal object operations before make_radioactive
is called
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…