PEP 562: module __getattr__ (#412)
This is an alternative (or complementary?) proposal to PEP 549.
This commit is contained in:
parent
4c8bf1956e
commit
877ece9427
|
@ -0,0 +1,105 @@
|
||||||
|
PEP: 562
|
||||||
|
Title: Module __getattr__
|
||||||
|
Author: Ivan Levkivskyi <levkivskyi@gmail.com>
|
||||||
|
Status: Draft
|
||||||
|
Type: Standards Track
|
||||||
|
Content-Type: text/x-rst
|
||||||
|
Created: 09-Sep-2017
|
||||||
|
Python-Version: 3.7
|
||||||
|
Post-History: 09-Sep-2017
|
||||||
|
|
||||||
|
|
||||||
|
Abstract
|
||||||
|
========
|
||||||
|
|
||||||
|
It is proposed to support ``__getattr__`` function defined on modules to
|
||||||
|
provide basic customization of module attribute access.
|
||||||
|
|
||||||
|
|
||||||
|
Rationale
|
||||||
|
=========
|
||||||
|
|
||||||
|
It is sometimes convenient to customize or otherwise have control over
|
||||||
|
access to module attributes. A typical example is managing deprecation
|
||||||
|
warnings. Typical workarounds are assigning ``__class__`` of a module object
|
||||||
|
to a custom subclass of ``types.ModuleType`` or substituting ``sys.modules``
|
||||||
|
item with a custom wrapper instance. It would be convenient to simplify this
|
||||||
|
procedure by recognizing ``__getattr__`` defined directly in a module that
|
||||||
|
would act like a normal ``__getattr__`` method, except that it will be defined
|
||||||
|
on module *instances*. For example::
|
||||||
|
|
||||||
|
# lib.py
|
||||||
|
|
||||||
|
from warnings import warn
|
||||||
|
|
||||||
|
deprecated_names = ["old_function", ...]
|
||||||
|
|
||||||
|
def _deprecated_old_function(arg, other):
|
||||||
|
...
|
||||||
|
|
||||||
|
def __getattr__(name):
|
||||||
|
if name in deprecated_names:
|
||||||
|
warn(f"{name} is deprecated", DeprecationWarning)
|
||||||
|
return globals()[f"_deprecated_{name}"]
|
||||||
|
raise AttributeError(f"module {__name__} has no attribute {name}")
|
||||||
|
|
||||||
|
# main.py
|
||||||
|
|
||||||
|
from lib import old_function # Works, but emits the warning
|
||||||
|
|
||||||
|
There is a related proposal PEP 549 that proposes to support instance
|
||||||
|
properties for a similar functionality. The difference is this PEP proposes
|
||||||
|
a faster and simpler mechanism, but provides more basic customization.
|
||||||
|
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]_.
|
||||||
|
|
||||||
|
|
||||||
|
Specification
|
||||||
|
=============
|
||||||
|
|
||||||
|
The ``__getattr__`` function at the module level should accept one argument
|
||||||
|
which is a name of an attribute and return the computed value or raise
|
||||||
|
an ``AttributeError``::
|
||||||
|
|
||||||
|
def __getattr__(name: str) -> Any: ...
|
||||||
|
|
||||||
|
This function will be called only if ``name`` is not found in the module
|
||||||
|
through the normal attribute lookup.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
|
||||||
|
References
|
||||||
|
==========
|
||||||
|
|
||||||
|
.. [1] PEP 484 section about ``__getattr__`` in stub files
|
||||||
|
(https://www.python.org/dev/peps/pep-0484/#stub-files)
|
||||||
|
|
||||||
|
.. [2] The reference implementation
|
||||||
|
(https://github.com/ilevkivskyi/cpython/pull/3/files)
|
||||||
|
|
||||||
|
|
||||||
|
Copyright
|
||||||
|
=========
|
||||||
|
|
||||||
|
This document has been placed in the public domain.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
..
|
||||||
|
Local Variables:
|
||||||
|
mode: indented-text
|
||||||
|
indent-tabs-mode: nil
|
||||||
|
sentence-end-double-space: t
|
||||||
|
fill-column: 70
|
||||||
|
coding: utf-8
|
||||||
|
End:
|
Loading…
Reference in New Issue