Updates following recent discussions (#470)

This commit is contained in:
Ivan Levkivskyi 2017-11-14 20:57:23 +01:00 committed by Guido van Rossum
parent 2a0cc286f2
commit 8f2d854856
1 changed files with 59 additions and 6 deletions

View File

@ -1,5 +1,5 @@
PEP: 562
Title: Module __getattr__
Title: Module __getattr__ and __dir__
Author: Ivan Levkivskyi <levkivskyi@gmail.com>
Status: Draft
Type: Standards Track
@ -12,8 +12,9 @@ Post-History: 09-Sep-2017
Abstract
========
It is proposed to support a ``__getattr__`` function defined on modules to
provide basic customization of module attribute access.
It is proposed to support a ``__getattr__`` and ``__dir__`` functions defined
+on modules to provide basic customization of module attribute access.
Rationale
@ -79,6 +80,29 @@ An additional motivation for this proposal is that PEP 484 already defines
the use of module ``__getattr__`` for this purpose in Python stub files,
see [1]_.
In addition, to allow modifying result of a ``dir()`` call on a module
to show deprecated and other dynamically generated attributes, it is
proposed to support module level ``__dir__`` function. For example::
# lib.py
deprecated_names = ["old_function", ...]
__all__ = ["new_function_one", "new_function_two", ...]
def new_function_one(arg, other):
...
def new_function_two(arg, other):
...
def __dir__():
return sorted(__all__ + deprecated_names)
# main.py
import lib
dir(lib) # prints ["new_function_one", "new_function_two", "old_function", ...]
Specification
=============
@ -92,15 +116,44 @@ an ``AttributeError``::
This function will be called only if ``name`` is not found in the module
through the normal attribute lookup.
The ``__dir__`` function should accept no arguments, and return
a list of strings that represents the names accessible on module::
def __dir__() -> List[str]: ...
If present, this function overrides the standard ``dir()`` search on
a module.
The reference implementation for this PEP can be found in [2]_.
Backwards compatibility and impact on performance
=================================================
This PEP may break code that uses module level (global) name ``__getattr__``.
The performance implications of this PEP are minimal, since ``__getattr__``
is called only for missing attributes.
This PEP may break code that uses module level (global) names ``__getattr__``
and ``__dir__``. The performance implications of this PEP are minimal,
since ``__getattr__`` is called only for missing attributes.
Discussion
==========
Note that the use of module ``__getattr__`` requires care to keep the referred
objects pickleable. For example, the ``__name__`` attribute of a function
should correspond to the name with which it is accessible via
``__getattr__``::
def keep_pickleable(func):
func.__name__ = func.__name__.replace('_deprecated_', '')
func.__qualname__ = func.__qualname__.replace('_deprecated_', '')
return func
@keep_pickleable
def _deprecated_old_function(arg, other):
...
One should be also careful to avoid recursion as one would do with
a class level ``__getattr__``.
References