(original) (raw)
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)