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). Is there a real use case for @property? Otherwise, if we're going to mess with module's getattro, it makes more sense to add __getattr__, which would have made Nathaniel's use case somewhat simpler. (Except for the __dir__ thing -- what else might we need?) On Tue, Sep 5, 2017 at 3:52 PM, Nathaniel Smith <njs@pobox.com> wrote:
On Tue, Sep 5, 2017 at 3:03 PM, Larry Hastings <larry@hastings.org> wrote:
I've written a PEP proposing a language change:
https://www.python.org/dev/peps/pep-0549/
The TL;DR summary: add support for property objects to modules. I've already posted a prototype.
Interesting idea! It's definitely less arcane than the __class__ assignment support that was added in 3.5. I guess the question is whether to add another language feature here, or to provide better documentation/helpers for the existing feature.
If anyone's curious what the __class__ trick looks like in practice, here's some simple deprecation machinery: https://github.com/njsmith/trio/blob/ee8d909e34a2b28d55b5c6137707e8 861eee3234/trio/_deprecate.py#L102-L138
And here's what it looks like in use: https://github.com/njsmith/trio/blob/ee8d909e34a2b28d55b5c6137707e8 861eee3234/trio/__init__.py#L91-L115
Advantages of PEP 549: - easier to explain and use
Advantages of the __class__ trick: - faster (no need to add an extra step to the normal attribute lookup fast path); only those who need the feature pay for it
- exposes the full power of Python's class model. Notice that the above code overrides __getattr__ but not __dir__, so the attributes are accessible via direct lookup but not listed in dir(mod). This is on purpose, for two reasons: (a) tab completion shouldn't be suggesting deprecated attributes, (b) when I did expose them in __dir__, I had trouble with test runners that iterated through dir(mod) looking for tests, and ended up spewing tons of spurious deprecation warnings. (This is especially bad when you have a policy of running your tests with DeprecationWarnings converted to errors.) I don't think there's any way to do this with PEP 549.
- already supported in CPython 3.5+ and PyPy3, and with a bit of care can be faked on all older CPython releases (including, crucially, CPython 2). PEP 549 OTOH AFAICT will only be usable for packages that have 3.7 as their minimum supported version.
I don't imagine that I would actually use PEP 549 any time in the foreseeable future, due to the inability to override __dir__ and the minimum version requirement. If you only need to support CPython 3.5+ and PyPy3 5.9+, then you can effectively get PEP 549's functionality at the cost of 3 lines of code and a block indent:
import sys, types class _MyModuleType(types.ModuleType): @property def ...
@property def ... sys.modules[__name__].__class__ = _MyModuleType
It's definitely true though that they're not the most obvious lines of code :-)
-n
-- Nathaniel J. Smith -- https://vorpus.org _______________________________________________ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/ guido%40python.org
-- --Guido van Rossum (python.org/~guido)