2016-06-07 20:44:13 -04:00
|
|
|
|
PEP: 520
|
2016-06-20 21:24:03 -04:00
|
|
|
|
Title: Preserving Class Attribute Definition Order
|
2016-06-07 20:44:13 -04:00
|
|
|
|
Version: $Revision$
|
|
|
|
|
Last-Modified: $Date$
|
|
|
|
|
Author: Eric Snow <ericsnowcurrently@gmail.com>
|
2016-09-05 20:22:36 -04:00
|
|
|
|
Status: Final
|
2016-06-07 20:44:13 -04:00
|
|
|
|
Type: Standards Track
|
|
|
|
|
Content-Type: text/x-rst
|
|
|
|
|
Created: 7-Jun-2016
|
|
|
|
|
Python-Version: 3.6
|
2016-06-24 17:48:12 -04:00
|
|
|
|
Post-History: 7-Jun-2016, 11-Jun-2016, 20-Jun-2016, 24-Jun-2016
|
2016-06-28 19:22:28 -04:00
|
|
|
|
Resolution: https://mail.python.org/pipermail/python-dev/2016-June/145442.html
|
2016-06-07 20:44:13 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Abstract
|
|
|
|
|
========
|
|
|
|
|
|
2016-06-24 17:48:12 -04:00
|
|
|
|
The class definition syntax is ordered by its very nature. Class
|
|
|
|
|
attributes defined there are thus ordered. Aside from helping with
|
|
|
|
|
readability, that ordering is sometimes significant. If it were
|
|
|
|
|
automatically available outside the class definition then the
|
|
|
|
|
attribute order could be used without the need for extra boilerplate
|
|
|
|
|
(such as metaclasses or manually enumerating the attribute order).
|
|
|
|
|
Given that this information already exists, access to the definition
|
|
|
|
|
order of attributes is a reasonable expectation. However, currently
|
|
|
|
|
Python does not preserve the attribute order from the class
|
|
|
|
|
definition.
|
|
|
|
|
|
|
|
|
|
This PEP changes that by preserving the order in which attributes
|
|
|
|
|
are introduced in the class definition body. That order will now be
|
|
|
|
|
preserved in the ``__definition_order__`` attribute of the class.
|
|
|
|
|
This allows introspection of the original definition order, e.g. by
|
|
|
|
|
class decorators.
|
2016-06-07 20:44:13 -04:00
|
|
|
|
|
2016-06-28 13:03:29 -04:00
|
|
|
|
Additionally, this PEP requires that the default class definition
|
|
|
|
|
namespace be ordered (e.g. ``OrderedDict``) by default. The long-
|
|
|
|
|
lived class namespace (``__dict__``) will remain a ``dict``.
|
2016-06-20 21:24:03 -04:00
|
|
|
|
|
2016-06-07 20:44:13 -04:00
|
|
|
|
|
|
|
|
|
Motivation
|
|
|
|
|
==========
|
|
|
|
|
|
2016-06-24 17:48:12 -04:00
|
|
|
|
The attribute order from a class definition may be useful to tools
|
|
|
|
|
that rely on name order. However, without the automatic availability
|
|
|
|
|
of the definition order, those tools must impose extra requirements on
|
|
|
|
|
users. For example, use of such a tool may require that your class use
|
|
|
|
|
a particular metaclass. Such requirements are often enough to
|
|
|
|
|
discourage use of the tool.
|
|
|
|
|
|
|
|
|
|
Some tools that could make use of this PEP include:
|
|
|
|
|
|
|
|
|
|
* documentation generators
|
|
|
|
|
* testing frameworks
|
|
|
|
|
* CLI frameworks
|
|
|
|
|
* web frameworks
|
|
|
|
|
* config generators
|
|
|
|
|
* data serializers
|
|
|
|
|
* enum factories (my original motivation)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Background
|
|
|
|
|
==========
|
|
|
|
|
|
|
|
|
|
When a class is defined using a ``class`` statement, the class body
|
|
|
|
|
is executed within a namespace. Currently that namespace defaults to
|
|
|
|
|
``dict``. If the metaclass defines ``__prepare__()`` then the result
|
|
|
|
|
of calling it is used for the class definition namespace.
|
|
|
|
|
|
2016-07-27 12:49:51 -04:00
|
|
|
|
After the execution completes, the definition namespace is
|
2016-06-28 17:35:22 -04:00
|
|
|
|
copied into a new ``dict``. Then the original definition namespace is
|
2016-06-24 17:48:12 -04:00
|
|
|
|
discarded. The new copy is stored away as the class's namespace and
|
|
|
|
|
is exposed as ``__dict__`` through a read-only proxy.
|
|
|
|
|
|
|
|
|
|
The class attribute definition order is represented by the insertion
|
|
|
|
|
order of names in the *definition* namespace. Thus, we can have
|
|
|
|
|
access to the definition order by switching the definition namespace
|
|
|
|
|
to an ordered mapping, such as ``collections.OrderedDict``. This is
|
|
|
|
|
feasible using a metaclass and ``__prepare__``, as described above.
|
|
|
|
|
In fact, exactly this is by far the most common use case for using
|
2016-06-28 13:03:29 -04:00
|
|
|
|
``__prepare__``.
|
2016-06-24 17:48:12 -04:00
|
|
|
|
|
|
|
|
|
At that point, the only missing thing for later access to the
|
|
|
|
|
definition order is storing it on the class before the definition
|
|
|
|
|
namespace is thrown away. Again, this may be done using a metaclass.
|
|
|
|
|
However, this means that the definition order is preserved only for
|
|
|
|
|
classes that use such a metaclass. There are two practical problems
|
|
|
|
|
with that:
|
2016-06-20 21:24:03 -04:00
|
|
|
|
|
|
|
|
|
First, it requires the use of a metaclass. Metaclasses introduce an
|
|
|
|
|
extra level of complexity to code and in some cases (e.g. conflicts)
|
|
|
|
|
are a problem. So reducing the need for them is worth doing when the
|
|
|
|
|
opportunity presents itself. PEP 422 and PEP 487 discuss this at
|
2016-06-28 13:03:29 -04:00
|
|
|
|
length. We have such an opportunity by using an ordered mapping (e.g.
|
|
|
|
|
``OrderedDict`` for CPython at least) for the default class definition
|
|
|
|
|
namespace, virtually eliminating the need for ``__prepare__()``.
|
2016-06-20 21:24:03 -04:00
|
|
|
|
|
|
|
|
|
Second, only classes that opt in to using the ``OrderedDict``-based
|
|
|
|
|
metaclass will have access to the definition order. This is problematic
|
|
|
|
|
for cases where universal access to the definition order is important.
|
2016-06-07 20:44:13 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Specification
|
|
|
|
|
=============
|
|
|
|
|
|
2016-06-20 21:24:03 -04:00
|
|
|
|
Part 1:
|
|
|
|
|
|
2016-06-24 17:48:12 -04:00
|
|
|
|
* all classes have a ``__definition_order__`` attribute
|
|
|
|
|
* ``__definition_order__`` is a ``tuple`` of identifiers (or ``None``)
|
2016-06-07 20:44:13 -04:00
|
|
|
|
* ``__definition_order__`` is always set:
|
|
|
|
|
|
2016-06-24 17:48:12 -04:00
|
|
|
|
1. during execution of the class body, the insertion order of names
|
|
|
|
|
into the class *definition* namespace is stored in a tuple
|
|
|
|
|
2. if ``__definition_order__`` is defined in the class body then it
|
2016-06-11 22:22:50 -04:00
|
|
|
|
must be a ``tuple`` of identifiers or ``None``; any other value
|
|
|
|
|
will result in ``TypeError``
|
2016-06-24 17:48:12 -04:00
|
|
|
|
3. classes that do not have a class definition (e.g. builtins) have
|
2016-06-07 20:44:13 -04:00
|
|
|
|
their ``__definition_order__`` set to ``None``
|
2016-06-28 17:38:09 -04:00
|
|
|
|
4. classes for which ``__prepare__()`` returned something other than
|
2016-06-07 20:44:13 -04:00
|
|
|
|
``OrderedDict`` (or a subclass) have their ``__definition_order__``
|
2016-06-24 17:48:12 -04:00
|
|
|
|
set to ``None`` (except where #2 applies)
|
2016-06-07 20:44:13 -04:00
|
|
|
|
|
2016-06-28 13:03:29 -04:00
|
|
|
|
Not changing:
|
|
|
|
|
|
|
|
|
|
* ``dir()`` will not depend on ``__definition_order__``
|
|
|
|
|
* descriptors and custom ``__getattribute__`` methods are unconstrained
|
|
|
|
|
regarding ``__definition_order__``
|
|
|
|
|
|
2016-06-20 21:24:03 -04:00
|
|
|
|
Part 2:
|
|
|
|
|
|
2016-06-28 13:03:29 -04:00
|
|
|
|
* the default class *definition* namespace is now an ordered mapping
|
|
|
|
|
(e.g. ``OrderdDict``)
|
|
|
|
|
* ``cls.__dict__`` does not change, remaining a read-only proxy around
|
|
|
|
|
``dict``
|
|
|
|
|
|
|
|
|
|
Note that Python implementations which have an ordered ``dict`` won't
|
2016-06-28 17:39:26 -04:00
|
|
|
|
need to change anything.
|
2016-06-20 21:24:03 -04:00
|
|
|
|
|
2016-06-28 13:03:29 -04:00
|
|
|
|
The following code demonstrates roughly equivalent semantics for both
|
|
|
|
|
parts 1 and 2::
|
2016-06-07 20:44:13 -04:00
|
|
|
|
|
|
|
|
|
class Meta(type):
|
2016-06-16 18:55:04 -04:00
|
|
|
|
@classmethod
|
2016-06-07 20:44:13 -04:00
|
|
|
|
def __prepare__(cls, *args, **kwargs):
|
|
|
|
|
return OrderedDict()
|
|
|
|
|
|
|
|
|
|
class Spam(metaclass=Meta):
|
|
|
|
|
ham = None
|
|
|
|
|
eggs = 5
|
2016-06-24 17:48:12 -04:00
|
|
|
|
__definition_order__ = tuple(locals())
|
2016-06-07 20:44:13 -04:00
|
|
|
|
|
|
|
|
|
Why a tuple?
|
|
|
|
|
------------
|
|
|
|
|
|
|
|
|
|
Use of a tuple reflects the fact that we are exposing the order in
|
|
|
|
|
which attributes on the class were *defined*. Since the definition
|
2016-06-16 18:55:04 -04:00
|
|
|
|
is already complete by the time ``__definition_order__`` is set, the
|
2016-06-07 20:44:13 -04:00
|
|
|
|
content and order of the value won't be changing. Thus we use a type
|
|
|
|
|
that communicates that state of immutability.
|
|
|
|
|
|
2016-06-28 16:40:13 -04:00
|
|
|
|
Why not a read-only attribute?
|
|
|
|
|
------------------------------
|
|
|
|
|
|
|
|
|
|
There are some valid arguments for making ``__definition_order__``
|
|
|
|
|
a read-only attribute (like ``cls.__dict__`` is). Most notably, a
|
|
|
|
|
read-only attribute conveys the nature of the attribute as "complete",
|
|
|
|
|
which is exactly correct for ``__definition_order__``. Since it
|
|
|
|
|
represents the state of a particular one-time event (execution of
|
|
|
|
|
the class definition body), allowing the value to be replaced would
|
|
|
|
|
reduce confidence that the attribute corresponds to the original class
|
|
|
|
|
body. Furthermore, often an immuntable-by-default approach helps to
|
|
|
|
|
make data easier to reason about.
|
2016-06-07 20:44:13 -04:00
|
|
|
|
|
2016-06-28 16:40:13 -04:00
|
|
|
|
However, in this case there still isn't a *strong* reason to counter
|
|
|
|
|
the well-worn precedent found in Python. Per Guido::
|
2016-06-07 20:44:13 -04:00
|
|
|
|
|
2016-06-28 16:40:13 -04:00
|
|
|
|
I don't see why it needs to be a read-only attribute. There are
|
|
|
|
|
very few of those -- in general we let users play around with
|
|
|
|
|
things unless we have a hard reason to restrict assignment (e.g.
|
|
|
|
|
the interpreter's internal state could be compromised). I don't
|
|
|
|
|
see such a hard reason here.
|
|
|
|
|
|
|
|
|
|
Also, note that a writeable ``__definition_order__`` allows dynamically
|
|
|
|
|
created classes (e.g. by Cython) to still have ``__definition_order__``
|
|
|
|
|
properly set. That could certainly be handled through specific class-
|
|
|
|
|
creation tools, such as ``type()`` or the C-API, without the need to
|
|
|
|
|
lose the semantics of a read-only attribute. However, with a writeable
|
|
|
|
|
attribute it's a moot point.
|
2016-06-07 20:44:13 -04:00
|
|
|
|
|
2016-06-24 17:48:12 -04:00
|
|
|
|
|
|
|
|
|
Why not "__attribute_order__"?
|
|
|
|
|
------------------------------
|
|
|
|
|
|
|
|
|
|
``__definition_order__`` is centered on the class definition
|
2016-06-07 20:44:13 -04:00
|
|
|
|
body. The use cases for dealing with the class namespace (``__dict__``)
|
|
|
|
|
post-definition are a separate matter. ``__definition_order__`` would
|
2016-06-11 22:22:50 -04:00
|
|
|
|
be a significantly misleading name for a feature focused on more than
|
|
|
|
|
class definition.
|
2016-06-07 20:44:13 -04:00
|
|
|
|
|
2016-06-24 17:48:12 -04:00
|
|
|
|
Why not ignore "dunder" names?
|
|
|
|
|
------------------------------
|
2016-06-07 20:44:13 -04:00
|
|
|
|
|
|
|
|
|
Names starting and ending with "__" are reserved for use by the
|
|
|
|
|
interpreter. In practice they should not be relevant to the users of
|
2016-06-07 23:16:56 -04:00
|
|
|
|
``__definition_order__``. Instead, for nearly everyone they would only
|
2016-06-28 13:03:29 -04:00
|
|
|
|
be clutter, causing the same extra work (filtering out the dunder
|
|
|
|
|
names) for the majority. In cases where a dunder name is significant,
|
|
|
|
|
the class definition *could* manually set ``__definition_order__``,
|
|
|
|
|
making the common case simpler.
|
|
|
|
|
|
|
|
|
|
However, leaving dunder names out of ``__definition_order__`` means
|
|
|
|
|
that their place in the definition order would be unrecoverably lost.
|
2016-07-11 11:14:08 -04:00
|
|
|
|
Dropping dunder names by default may inadvertently cause problems for
|
2016-06-28 13:03:29 -04:00
|
|
|
|
classes that use dunder names unconventionally. In this case it's
|
|
|
|
|
better to play it safe and preserve *all* the names from the class
|
|
|
|
|
definition. This isn't a big problem since it is easy to filter out
|
|
|
|
|
dunder names::
|
|
|
|
|
|
|
|
|
|
(name for name in cls.__definition_order__
|
|
|
|
|
if not (name.startswith('__') and name.endswith('__')))
|
|
|
|
|
|
|
|
|
|
In fact, in some application contexts there may be other criteria on
|
|
|
|
|
which similar filtering would be applied, such as ignoring any name
|
|
|
|
|
starting with "_", leaving out all methods, or including only
|
|
|
|
|
descriptors. Ultimately dunder names aren't a special enough case to
|
|
|
|
|
be treated exceptionally.
|
2016-06-24 17:48:12 -04:00
|
|
|
|
|
|
|
|
|
Note that a couple of dunder names (``__name__`` and ``__qualname__``)
|
|
|
|
|
are injected by default by the compiler. So they will be included even
|
|
|
|
|
though they are not strictly part of the class definition body.
|
|
|
|
|
|
2016-06-11 22:22:50 -04:00
|
|
|
|
Why None instead of an empty tuple?
|
|
|
|
|
-----------------------------------
|
|
|
|
|
|
|
|
|
|
A key objective of adding ``__definition_order__`` is to preserve
|
|
|
|
|
information in class definitions which was lost prior to this PEP.
|
|
|
|
|
One consequence is that ``__definition_order__`` implies an original
|
2016-07-11 11:14:08 -04:00
|
|
|
|
class definition. Using ``None`` allows us to clearly distinguish
|
2016-06-11 22:22:50 -04:00
|
|
|
|
classes that do not have a definition order. An empty tuple clearly
|
|
|
|
|
indicates a class that came from a definition statement but did not
|
|
|
|
|
define any attributes there.
|
|
|
|
|
|
|
|
|
|
Why None instead of not setting the attribute?
|
|
|
|
|
----------------------------------------------
|
|
|
|
|
|
|
|
|
|
The absence of an attribute requires more complex handling than ``None``
|
|
|
|
|
does for consumers of ``__definition_order__``.
|
|
|
|
|
|
|
|
|
|
Why constrain manually set values?
|
|
|
|
|
----------------------------------
|
|
|
|
|
|
|
|
|
|
If ``__definition_order__`` is manually set in the class body then it
|
|
|
|
|
will be used. We require it to be a tuple of identifiers (or ``None``)
|
|
|
|
|
so that consumers of ``__definition_order__`` may have a consistent
|
|
|
|
|
expectation for the value. That helps maximize the feature's
|
|
|
|
|
usefulness.
|
|
|
|
|
|
2016-06-16 18:55:04 -04:00
|
|
|
|
We could also also allow an arbitrary iterable for a manually set
|
|
|
|
|
``__definition_order__`` and convert it into a tuple. However, not
|
|
|
|
|
all iterables infer a definition order (e.g. ``set``). So we opt in
|
|
|
|
|
favor of requiring a tuple.
|
|
|
|
|
|
2016-06-28 13:03:29 -04:00
|
|
|
|
Why not hide __definition_order__ on non-type objects?
|
|
|
|
|
------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
Python doesn't make much effort to hide class-specific attributes
|
|
|
|
|
during lookup on instances of classes. While it may make sense
|
|
|
|
|
to consider ``__definition_order__`` a class-only attribute, hidden
|
|
|
|
|
during lookup on objects, setting precedent in that regard is
|
|
|
|
|
beyond the goals of this PEP.
|
|
|
|
|
|
2016-06-28 16:40:13 -04:00
|
|
|
|
What about __slots__?
|
|
|
|
|
---------------------
|
|
|
|
|
|
|
|
|
|
``__slots__`` will be added to ``__definition_order__`` like any
|
|
|
|
|
other name in the class definition body. The actual slot names
|
|
|
|
|
will not be added to ``__definition_order__`` since they aren't
|
|
|
|
|
set as names in the definition namespace.
|
|
|
|
|
|
2016-06-07 20:44:13 -04:00
|
|
|
|
Why is __definition_order__ even necessary?
|
|
|
|
|
-------------------------------------------
|
|
|
|
|
|
2016-06-07 23:16:56 -04:00
|
|
|
|
Since the definition order is not preserved in ``__dict__``, it is
|
2016-06-07 20:44:13 -04:00
|
|
|
|
lost once class definition execution completes. Classes *could*
|
|
|
|
|
explicitly set the attribute as the last thing in the body. However,
|
|
|
|
|
then independent decorators could only make use of classes that had done
|
|
|
|
|
so. Instead, ``__definition_order__`` preserves this one bit of info
|
|
|
|
|
from the class body so that it is universally available.
|
|
|
|
|
|
|
|
|
|
|
2016-06-20 22:14:02 -04:00
|
|
|
|
Support for C-API Types
|
|
|
|
|
=======================
|
|
|
|
|
|
|
|
|
|
Arguably, most C-defined Python types (e.g. built-in, extension modules)
|
|
|
|
|
have a roughly equivalent concept of a definition order. So conceivably
|
|
|
|
|
``__definition_order__`` could be set for such types automatically. This
|
|
|
|
|
PEP does not introduce any such support. However, it does not prohibit
|
2016-06-28 16:40:13 -04:00
|
|
|
|
it either. However, since ``__definition_order__`` can be set at any
|
|
|
|
|
time through normal attribute assignment, it does not need any special
|
|
|
|
|
treatment in the C-API.
|
2016-06-20 22:14:02 -04:00
|
|
|
|
|
2016-06-24 17:48:12 -04:00
|
|
|
|
The specific cases:
|
|
|
|
|
|
|
|
|
|
* builtin types
|
|
|
|
|
* PyType_Ready
|
|
|
|
|
* PyType_FromSpec
|
|
|
|
|
|
2016-06-20 22:14:02 -04:00
|
|
|
|
|
2016-06-07 20:44:13 -04:00
|
|
|
|
Compatibility
|
|
|
|
|
=============
|
|
|
|
|
|
|
|
|
|
This PEP does not break backward compatibility, except in the case that
|
|
|
|
|
someone relies *strictly* on ``dict`` as the class definition namespace.
|
2016-06-16 18:55:04 -04:00
|
|
|
|
This shouldn't be a problem since ``issubclass(OrderedDict, dict)`` is
|
|
|
|
|
true.
|
2016-06-07 20:44:13 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Changes
|
|
|
|
|
=============
|
|
|
|
|
|
|
|
|
|
In addition to the class syntax, the following expose the new behavior:
|
|
|
|
|
|
|
|
|
|
* builtins.__build_class__
|
|
|
|
|
* types.prepare_class
|
|
|
|
|
* types.new_class
|
|
|
|
|
|
2016-06-28 16:40:13 -04:00
|
|
|
|
Also, the 3-argument form of ``builtins.type()`` will allow inclusion
|
|
|
|
|
of ``__definition_order__`` in the namespace that gets passed in. It
|
|
|
|
|
will be subject to the same constraints as when ``__definition_order__``
|
|
|
|
|
is explicitly defined in the class body.
|
|
|
|
|
|
2016-06-07 20:44:13 -04:00
|
|
|
|
|
|
|
|
|
Other Python Implementations
|
|
|
|
|
============================
|
|
|
|
|
|
|
|
|
|
Pending feedback, the impact on Python implementations is expected to
|
2016-06-28 13:03:29 -04:00
|
|
|
|
be minimal. All conforming implementations are expected to set
|
|
|
|
|
``__definition_order__`` as described in this PEP.
|
2016-06-07 20:44:13 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Implementation
|
|
|
|
|
==============
|
|
|
|
|
|
|
|
|
|
The implementation is found in the tracker. [impl_]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Alternatives
|
|
|
|
|
============
|
|
|
|
|
|
2016-06-24 17:48:12 -04:00
|
|
|
|
An Order-preserving cls.__dict__
|
|
|
|
|
--------------------------------
|
2016-06-07 20:44:13 -04:00
|
|
|
|
|
|
|
|
|
Instead of storing the definition order in ``__definition_order__``,
|
|
|
|
|
the now-ordered definition namespace could be copied into a new
|
2016-06-07 23:09:27 -04:00
|
|
|
|
``OrderedDict``. This would then be used as the mapping proxied as
|
|
|
|
|
``__dict__``. Doing so would mostly provide the same semantics.
|
2016-06-07 20:44:13 -04:00
|
|
|
|
|
2016-06-07 23:09:27 -04:00
|
|
|
|
However, using ``OrderedDict`` for ``__dict__`` would obscure the
|
2016-06-07 20:44:13 -04:00
|
|
|
|
relationship with the definition namespace, making it less useful.
|
2016-06-24 17:48:12 -04:00
|
|
|
|
|
|
|
|
|
Additionally, (in the case of ``OrderedDict`` specifically) doing
|
|
|
|
|
this would require significant changes to the semantics of the
|
|
|
|
|
concrete ``dict`` C-API.
|
|
|
|
|
|
|
|
|
|
There has been some discussion about moving to a compact dict
|
|
|
|
|
implementation which would (mostly) preserve insertion order. However
|
|
|
|
|
the lack of an explicit ``__definition_order__`` would still remain
|
|
|
|
|
as a pain point.
|
2016-06-07 20:44:13 -04:00
|
|
|
|
|
|
|
|
|
A "namespace" Keyword Arg for Class Definition
|
|
|
|
|
----------------------------------------------
|
|
|
|
|
|
|
|
|
|
PEP 422 introduced a new "namespace" keyword arg to class definitions
|
|
|
|
|
that effectively replaces the need to ``__prepare__()``. [pep422_]
|
|
|
|
|
However, the proposal was withdrawn in favor of the simpler PEP 487.
|
|
|
|
|
|
2016-06-16 18:55:04 -04:00
|
|
|
|
A stdlib Metaclass that Implements __prepare__() with OrderedDict
|
|
|
|
|
-----------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
This has all the same problems as writing your own metaclass. The
|
|
|
|
|
only advantage is that you don't have to actually write this
|
|
|
|
|
metaclass. So it doesn't offer any benefit in the context of this
|
|
|
|
|
PEP.
|
|
|
|
|
|
|
|
|
|
Set __definition_order__ at Compile-time
|
|
|
|
|
----------------------------------------
|
|
|
|
|
|
|
|
|
|
Each class's ``__qualname__`` is determined at compile-time.
|
|
|
|
|
This same concept could be applied to ``__definition_order__``.
|
|
|
|
|
The result of composing ``__definition_order__`` at compile-time
|
|
|
|
|
would be nearly the same as doing so at run-time.
|
|
|
|
|
|
|
|
|
|
Comparative implementation difficulty aside, the key difference
|
|
|
|
|
would be that at compile-time it would not be practical to
|
|
|
|
|
preserve definition order for attributes that are set dynamically
|
|
|
|
|
in the class body (e.g. ``locals()[name] = value``). However,
|
|
|
|
|
they should still be reflected in the definition order. One
|
2016-07-11 11:14:08 -04:00
|
|
|
|
possible resolution would be to require class authors to manually
|
2016-06-16 18:55:04 -04:00
|
|
|
|
set ``__definition_order__`` if they define any class attributes
|
|
|
|
|
dynamically.
|
|
|
|
|
|
|
|
|
|
Ultimately, the use of ``OrderedDict`` at run-time or compile-time
|
|
|
|
|
discovery is almost entirely an implementation detail.
|
|
|
|
|
|
2016-06-07 20:44:13 -04:00
|
|
|
|
|
|
|
|
|
References
|
|
|
|
|
==========
|
|
|
|
|
|
|
|
|
|
.. [impl] issue #24254
|
|
|
|
|
(https://bugs.python.org/issue24254)
|
|
|
|
|
|
|
|
|
|
.. [nick_concern] Nick's concerns about mutability
|
|
|
|
|
(https://mail.python.org/pipermail/python-dev/2016-June/144883.html)
|
|
|
|
|
|
|
|
|
|
.. [pep422] PEP 422
|
|
|
|
|
(https://www.python.org/dev/peps/pep-0422/#order-preserving-classes)
|
|
|
|
|
|
|
|
|
|
.. [pep487] PEP 487
|
|
|
|
|
(https://www.python.org/dev/peps/pep-0487/#defining-arbitrary-namespaces)
|
|
|
|
|
|
|
|
|
|
.. [orig] original discussion
|
|
|
|
|
(https://mail.python.org/pipermail/python-ideas/2013-February/019690.html)
|
|
|
|
|
|
|
|
|
|
.. [followup1] follow-up 1
|
|
|
|
|
(https://mail.python.org/pipermail/python-dev/2013-June/127103.html)
|
|
|
|
|
|
|
|
|
|
.. [followup2] follow-up 2
|
|
|
|
|
(https://mail.python.org/pipermail/python-dev/2015-May/140137.html)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Copyright
|
|
|
|
|
===========
|
|
|
|
|
This document has been placed in the public domain.
|
2016-06-07 20:47:24 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
..
|
|
|
|
|
Local Variables:
|
|
|
|
|
mode: indented-text
|
|
|
|
|
indent-tabs-mode: nil
|
|
|
|
|
sentence-end-double-space: t
|
|
|
|
|
fill-column: 70
|
|
|
|
|
coding: utf-8
|
|
|
|
|
End:
|