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).
import depmod
print(depmod.depr1) # throws an exception
# 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)