Iwo Herka <iwohe...@gmail.com> writes: > Let's say I want to implement immutability for user-defined class. > More precisely, a class that can be modified only in its (or its > super-class') __init__ method. My initial idea was to do it the > following fashion: > > def __setattr__(self, *args, **kwargs): > if sys._getframe(1).f_code.co_name == '__init__': > return super().__setattr__(*args, **kwargs) > raise AttributeError() > > What do you think of this approach? Is there a better one?
This is not easy to achieve in Python: Most instances of classes store their attributes in the so called "instance dict", accessed via "<i>.__dict__". Thus, usually, it is quite easy to avoid `__setattr__": just modify the instance dict directly. If your aim is to ensure that "normal use" will not inadvertantly modify your instance (not to enforce immutability even facing people ready to use implementation details to break it), then you might consider the use of a so called "metaclass". The "metaclass" is responsible to create the class object; thus, it can modify (add or delete) methods for the class to be constructed. The main problem in your task is to recognize when the initial "__init__" call has finished. Your approach above does not work, should "__init__" call other functions or methods. With a metaclass, you could ensure, that all "__init__" methods for classes constructed by it are instrumented. The instrumentation would ensure that the initial "__init__" call sets an instance attribute (say) "_initializing_" (to itself) (using implementation details) at its beginning and remove it at the end. This way, a "__setattr__" has an easy way to recognize the initialization phase. The approach above, would not work for recursively called "__init__" methods - but hopefully, such "__init__" implementations are extremely rare. -- https://mail.python.org/mailman/listinfo/python-list