On 09/06/2017 08:26 AM, Guido van Rossum wrote:
So we've seen a real use case for __class__ assignment: deprecating things on access. That use case could also be solved if modules natively supported defining __getattr__ (with the same "only used if attribute not found otherwise" semantics as it has on classes), but it couldn't be solved using @property (or at least it would be quite hacky).
I guess it's a matter of perspective. I solved this problem using @property, and I don't think it's particularly hacky. (See my implementation at the bottom of this email). The worst thing it does is look up the current module via sys.modules[__name__]... which Nathaniel's code also must do. My example is a lot simpler than Nathaniel's code but it's just a proof-of-concept. Nathaniel's code does much more. In particular, I didn't override __dir__ to hide the deprecated attributes; doing that would mean assigning to __class__ just as Nathaniel does. (If you're actually curious to see it I could add that to the proof-of-concept.) IMO my PEP strikes the right balance. @property is far more popular than __getattr__ or __getattribute__; 19 times out of 20, people use @property. Meanwhile, people for whom @property is insufficient (like Nathaniel) can already assign to module.__class__ and override __getattr__, __getattribute__, __del__, or any other existing magic method. In other words: the commonplace is easy, and the unusual is possible. Perfect! //arry ----- /test_deprecated.py: import depmod print(depmod.depr1) # throws an exception depmod.py: # module with deprecated properties import sys _deprecated_properies = ( ("depr1", 33), ("depr2", 44), ) __module__ = sys.modules[__name__] def set_deprecated_property(name, value): @property def prop(self): raise RuntimeError(f"property '{name}' is deprecated") return value setattr(__module__, name, prop) for name, value in _deprecated_properies: set_deprecated_property(name, value)