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/ee8d909e34a2b28d55b5c6137707e8861eee3234/trio/_deprecate.py#L102-L138

And here's what it looks like in use:
  https://github.com/njsmith/trio/blob/ee8d909e34a2b28d55b5c6137707e8861eee3234/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)