More PEP 549 formatting fixes. This time for sure!
This commit is contained in:
parent
c0028cb607
commit
f34e19c9f6
114
pep-0549.rst
114
pep-0549.rst
|
@ -13,90 +13,90 @@ Post-History: 4-Sep-2017
|
||||||
Abstract
|
Abstract
|
||||||
========
|
========
|
||||||
|
|
||||||
Python's descriptor protocol requires that descriptors
|
Python's descriptor protocol requires that descriptors
|
||||||
be members of the *type* of an object. This PEP proposes
|
be members of the *type* of an object. This PEP proposes
|
||||||
an extension to the descriptor protocol allowing use of
|
an extension to the descriptor protocol allowing use of
|
||||||
the descriptor protocol for members of *instances.* This
|
the descriptor protocol for members of *instances.* This
|
||||||
would permit using properties in modules.
|
would permit using properties in modules.
|
||||||
|
|
||||||
Rationale
|
Rationale
|
||||||
=========
|
=========
|
||||||
|
|
||||||
Python's descriptor protocol guides programmers towards
|
Python's descriptor protocol guides programmers towards
|
||||||
elegant API design. If your class supports a data-like
|
elegant API design. If your class supports a data-like
|
||||||
member, and you *might* someday need to run code when
|
member, and you *might* someday need to run code when
|
||||||
changing the member's value, you're encouraged to
|
changing the member's value, you're encouraged to
|
||||||
simply declare it as a simple data member of the class
|
simply declare it as a simple data member of the class
|
||||||
for now. If in the future you do need to run code, you
|
for now. If in the future you do need to run code, you
|
||||||
can change it to a "property", and happily the API doesn't
|
can change it to a "property", and happily the API doesn't
|
||||||
change.
|
change.
|
||||||
|
|
||||||
Unfortunately this doesn't work with modules. Modules are
|
Unfortunately this doesn't work with modules. Modules are
|
||||||
instances of a single generic ``module`` type, and it's not
|
instances of a single generic ``module`` type, and it's not
|
||||||
feasible to modify or subclass this type to add a property
|
feasible to modify or subclass this type to add a property
|
||||||
to one's module. This means that programmers facing this
|
to one's module. This means that programmers facing this
|
||||||
API design decision, where the data-like member is a singleton
|
API design decision, where the data-like member is a singleton
|
||||||
stored in a module, must preemptively add ugly "getters"
|
stored in a module, must preemptively add ugly "getters"
|
||||||
and "setters" for the data.
|
and "setters" for the data.
|
||||||
|
|
||||||
Adding support for module properties in pure Python is possible
|
Adding support for module properties in pure Python is possible
|
||||||
only by using hacks like:
|
only by using hacks like:
|
||||||
|
|
||||||
* peeking in ``sys.getframe()``,
|
* peeking in ``sys.getframe()``,
|
||||||
|
|
||||||
* changing the type of an object after it's created, or
|
* changing the type of an object after it's created, or
|
||||||
|
|
||||||
* replacing the object stored in ``sys.modules``.
|
* replacing the object stored in ``sys.modules``.
|
||||||
|
|
||||||
These techniques can be made to work, but they're fragile.
|
These techniques can be made to work, but they're fragile.
|
||||||
|
|
||||||
This PEP proposes a per-type opt-in extension to the descriptor
|
This PEP proposes a per-type opt-in extension to the descriptor
|
||||||
protocol specifically designed to enable properties in modules.
|
protocol specifically designed to enable properties in modules.
|
||||||
The mechanism is a way to honor the descriptor protocol for
|
The mechanism is a way to honor the descriptor protocol for
|
||||||
members of *instances* of a class without the member being declared
|
members of *instances* of a class without the member being declared
|
||||||
as a class variable.
|
as a class variable.
|
||||||
|
|
||||||
Although this is being proposed as a general mechanism, the author
|
Although this is being proposed as a general mechanism, the author
|
||||||
currently only forsees this as being useful for module objects.
|
currently only forsees this as being useful for module objects.
|
||||||
|
|
||||||
Implementation
|
Implementation
|
||||||
==============
|
==============
|
||||||
|
|
||||||
The basic idea is simple: modify the ``tp_descr_get`` and ``tp_descr_set``
|
The basic idea is simple: modify the ``tp_descr_get`` and ``tp_descr_set``
|
||||||
functions exposed by ``PyModule_Type`` to inspect the attribute interacted
|
functions exposed by ``PyModule_Type`` to inspect the attribute interacted
|
||||||
with, and if it supports the descriptor protocol, call the relevant
|
with, and if it supports the descriptor protocol, call the relevant
|
||||||
exposed function.
|
exposed function.
|
||||||
|
|
||||||
Our implementation faces two challenges:
|
Our implementation faces two challenges:
|
||||||
|
|
||||||
1. Since this code will be run every time an attribute is looked up on a
|
1. Since this code will be run every time an attribute is looked up on a
|
||||||
method, it needs to add very little overhead in the general case,
|
method, it needs to add very little overhead in the general case,
|
||||||
where the object stored in the attribute is not a descriptor.
|
where the object stored in the attribute is not a descriptor.
|
||||||
|
|
||||||
2. Since functions are descriptors, we must take care to *not* honor
|
2. Since functions are descriptors, we must take care to *not* honor
|
||||||
the descriptor protocol for all objects. Otherwise, all module-level
|
the descriptor protocol for all objects. Otherwise, all module-level
|
||||||
functions will suddenly become bound to the module instance as if
|
functions will suddenly become bound to the module instance as if
|
||||||
they were method calls on the module object. The module handle would
|
they were method calls on the module object. The module handle would
|
||||||
be passed in as a "self" argument to all module-level functions.
|
be passed in as a "self" argument to all module-level functions.
|
||||||
|
|
||||||
Both challenges can be solved with the same approach: we define a new
|
Both challenges can be solved with the same approach: we define a new
|
||||||
"fast subclass" flag that means "This object is a desciptor, and it
|
"fast subclass" flag that means "This object is a desciptor, and it
|
||||||
should be honored directly when this object is looked up as an
|
should be honored directly when this object is looked up as an
|
||||||
attribute of an instance". So far the only placed where this flag
|
attribute of an instance". So far the only placed where this flag
|
||||||
is set is on ``PyProperty_Type``.
|
is set is on ``PyProperty_Type``.
|
||||||
|
|
||||||
Prototype
|
Prototype
|
||||||
=========
|
=========
|
||||||
|
|
||||||
A prototype of this functionality is under development
|
A prototype of this functionality is under development
|
||||||
at GitHub [github]_.
|
at GitHub [github]_.
|
||||||
|
|
||||||
Acknowledgements
|
Acknowledgements
|
||||||
================
|
================
|
||||||
|
|
||||||
Armin Rigo essentially proposed this mechanism when presented
|
Armin Rigo essentially proposed this mechanism when presented
|
||||||
with the idea of "module properties", and educated the author
|
with the idea of "module properties", and educated the author
|
||||||
both on the complexities of the problem and the proper solution.
|
both on the complexities of the problem and the proper solution.
|
||||||
|
|
||||||
References
|
References
|
||||||
==========
|
==========
|
||||||
|
@ -107,7 +107,7 @@ References
|
||||||
Copyright
|
Copyright
|
||||||
---------
|
---------
|
||||||
|
|
||||||
This document has been placed in the public domain.
|
This document has been placed in the public domain.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue