PEP: Ordered Class Definition Namespace
Hi all, Following discussion a few years back (and rough approval from Guido [1]), I started work on using OrderedDict for the class definition namespace by default. The bulk of the effort lay in implementing OrderedDict in C, which I got landed just in time for 3.5. The remaining work was quite minimal and the actual change is quite small. My intention was to land the patch soon, having gone through code review during PyCon. However, Nick pointed out to me the benefit of having a concrete point of reference for the change, as well as making sure it isn't a problem for other implementations. So in that spirit, here's a PEP for the change. Feedback is welcome, particularly from from other implementors. -eric [1] https://mail.python.org/pipermail/python-ideas/2013-February/019704.html ================================================== PEP: XXX Title: Ordered Class Definition Namespace Version: $Revision$ Last-Modified: $Date$ Author: Eric Snow <ericsnowcurrently@gmail.com> Status: Draft Type: Standards Track Content-Type: text/x-rst Created: 4-Jun-2016 Python-Version: 3.6 Post-History: 7-Jun-2016 Abstract ======== This PEP changes the default class definition namespace to ``OrderedDict``. Furthermore, the order in which the attributes are defined in each class body will now be preserved in ``type.__definition_order__``. This allows introspection of the original definition order, e.g. by class decorators. Note: just to be clear, this PEP is *not* about changing ``type.__dict__`` to ``OrderedDict``. Motivation ========== Currently the namespace used during execution of a class body defaults to dict. If the metaclass defines ``__prepare__()`` then the result of calling it is used. Thus, before this PEP, if you needed your class definition namespace to be ``OrderedDict`` you had to use 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. Given that we now have a C implementation of ``OrderedDict`` and that ``OrderedDict`` is the common use case for ``__prepare__()``, we have such an opportunity by defaulting to ``OrderedDict``. The usefulness of ``OrderedDict``-by-default is greatly increased if the definition order is directly introspectable on classes afterward, particularly by code that is independent of the original class definition. One of the original motivating use cases for this PEP is generic class decorators that make use of the definition order. Changing the default class definition namespace has been discussed a number of times, including on the mailing lists and in PEP 422 and PEP 487 (see the References section below). Specification ============= * the default class *definition* namespace is now ``OrderdDict`` * the order in which class attributes are defined is preserved in the new ``__definition_order__`` attribute on each class * "dunder" attributes (e.g. ``__init__``, ``__module__``) are ignored * ``__definition_order__`` is a tuple * ``__definition_order__`` is a read-only attribute * ``__definition_order__`` is always set: * if ``__definition_order__`` is defined in the class body then it is used * types that do not have a class definition (e.g. builtins) have their ``__definition_order__`` set to ``None`` * types for which `__prepare__()`` returned something other than ``OrderedDict`` (or a subclass) have their ``__definition_order__`` set to ``None`` The following code demonstrates roughly equivalent semantics:: class Meta(type): def __prepare__(cls, *args, **kwargs): return OrderedDict() class Spam(metaclass=Meta): ham = None eggs = 5 __definition_order__ = tuple(k for k in locals() if (!k.startswith('__') or !k.endswith('__'))) Note that [pep487_] proposes a similar solution, albeit as part of a broader proposal. Compatibility ============= This PEP does not break backward compatibility, except in the case that someone relies *strictly* on dicts as the class definition namespace. This shouldn't be a problem. Changes ============= In addition to the class syntax, the following expose the new behavior: * builtins.__build_class__ * types.prepare_class * types.new_class Other Python Implementations ============================ Pending feedback, the impact on Python implementations is expected to be minimal. If a Python implementation cannot support switching to `OrderedDict``-by-default then it can always set ``__definition_order__`` to ``None``. Implementation ============== The implementation is found in the tracker. [impl_] Alternatives ============ type.__dict__ as OrderedDict ---------------------------- Instead of storing the definition order in ``__definition_order__``, the now-ordered definition namespace could be copied into a new ``OrderedDict``. This would mostly provide the same semantics. However, using ``OrderedDict`` for ``type,__dict__`` would obscure the relationship with the definition namespace, making it less useful. Additionally, doing this would require significant changes to the semantics of the concrete dict C-API. 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. References ========== .. [impl] issue #24254 (https://bugs.python.org/issue24254) .. [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.
On 06/07/2016 10:51 AM, Eric Snow wrote:
My intention was to land the patch soon, having gone through code review during PyCon. However, Nick pointed out to me the benefit of having a concrete point of reference for the change, as well as making sure it isn't a problem for other implementations. So in that spirit, here's a PEP for the change. Feedback is welcome, particularly from from other implementors.
+1
Specification =============
* types for which `__prepare__()`` returned something other than ``OrderedDict`` (or a subclass) have their ``__definition_order__`` set to ``None``
I assume this check happens in type.__new__? If a non-OrderedDict is used as the namespace, but a __definition_order__ key and value are supplied, is it used or still set to None? -- ~Ethan~
On Tue, Jun 7, 2016 at 11:01 AM, Ethan Furman <ethan@stoneleaf.us> wrote:
On 06/07/2016 10:51 AM, Eric Snow wrote:
Specification =============
* types for which `__prepare__()`` returned something other than ``OrderedDict`` (or a subclass) have their ``__definition_order__`` set to ``None``
I assume this check happens in type.__new__? If a non-OrderedDict is used as the namespace, but a __definition_order__ key and value are supplied, is it used or still set to None?
A __definition_order__ in the class body always takes precedence. So a supplied value will be honored (and not replaced with None). -eric
On 06/07/2016 11:13 AM, Eric Snow wrote:
On Tue, Jun 7, 2016 at 11:01 AM, Ethan Furman <ethan@stoneleaf.us> wrote:
On 06/07/2016 10:51 AM, Eric Snow wrote:
Specification =============
* types for which `__prepare__()`` returned something other than ``OrderedDict`` (or a subclass) have their ``__definition_order__`` set to ``None``
I assume this check happens in type.__new__? If a non-OrderedDict is used as the namespace, but a __definition_order__ key and value are supplied, is it used or still set to None?
A __definition_order__ in the class body always takes precedence. So a supplied value will be honored (and not replaced with None).
Will the supplied __definition_order__ be made a tuple, and still be read-only? -- ~Ethan~
On Tue, Jun 7, 2016 at 11:45 AM, Ethan Furman <ethan@stoneleaf.us> wrote:
On 06/07/2016 11:13 AM, Eric Snow wrote:
A __definition_order__ in the class body always takes precedence. So a supplied value will be honored (and not replaced with None).
Will the supplied __definition_order__ be made a tuple, and still be read-only?
I had planned on leaving a supplied one alone. So no change to tuple. It remain a read-only attribute though, since that is handled via a descriptor (a la type.__dict__). -eric
On 06/07/2016 11:13 AM, Eric Snow wrote:
On Tue, Jun 7, 2016 at 11:01 AM, Ethan Furman <ethan@stoneleaf.us> wrote:
On 06/07/2016 10:51 AM, Eric Snow wrote:
Specification =============
* types for which `__prepare__()`` returned something other than ``OrderedDict`` (or a subclass) have their ``__definition_order__`` set to ``None``
I assume this check happens in type.__new__? If a non-OrderedDict is used as the namespace, but a __definition_order__ key and value are supplied, is it used or still set to None?
A __definition_order__ in the class body always takes precedence. So a supplied value will be honored (and not replaced with None).
Nice. I'll add it to the Enum, enum34, and aenum as soon as it lands (give or take a couple months ;) -- ~Ethan~
On 6/7/2016 1:51 PM, Eric Snow wrote:
Note: just to be clear, this PEP is *not* about changing ``type.__dict__`` to ``OrderedDict``.
By 'type', do you mean the one and one objected named 'type or the class being defined? To be really clear, will the following change?
class C: pass
type(C.__dict__) <class 'mappingproxy'>
If the proposal only affects (slows) the class definition process, and then only minimally, and has no effect on class use, then +1 on being able to avoid metaclass and prepare for its most common current usage. -- Terry Jan Reedy
On Tue, Jun 7, 2016 at 11:32 AM, Terry Reedy <tjreedy@udel.edu> wrote:
On 6/7/2016 1:51 PM, Eric Snow wrote:
Note: just to be clear, this PEP is *not* about changing
``type.__dict__`` to ``OrderedDict``.
By 'type', do you mean the one and one objected named 'type or the class being defined? To be really clear, will the following change?
class C: pass
type(C.__dict__) <class 'mappingproxy'>
I mean the latter, "type" -> the class being defined.
If the proposal only affects (slows) the class definition process, and then only minimally, and has no effect on class use, then +1 on being able to avoid metaclass and prepare for its most common current usage.
That is all correct. -eric
On Tue, Jun 07, 2016 at 11:39:06AM -0700, Eric Snow wrote:
On Tue, Jun 7, 2016 at 11:32 AM, Terry Reedy <tjreedy@udel.edu> wrote:
On 6/7/2016 1:51 PM, Eric Snow wrote:
Note: just to be clear, this PEP is *not* about changing
``type.__dict__`` to ``OrderedDict``.
By 'type', do you mean the one and one objected named 'type or the class being defined? To be really clear, will the following change?
class C: pass
type(C.__dict__) <class 'mappingproxy'>
I mean the latter, "type" -> the class being defined.
Could you clarify that in the PEP please? Like Terry, I too found it unclear. I think there are a couple of places where you refer to `type` and it isn't clear whether you mean builtins.type or something else. -- Steve
On Tue, Jun 7, 2016 at 6:09 PM, Steven D'Aprano <steve@pearwood.info> wrote:
On Tue, Jun 07, 2016 at 11:39:06AM -0700, Eric Snow wrote:
I mean the latter, "type" -> the class being defined.
Could you clarify that in the PEP please? Like Terry, I too found it unclear. I think there are a couple of places where you refer to `type` and it isn't clear whether you mean builtins.type or something else.
Yep. Done. -eric
From: Eric Snow Sent: Tuesday, June 07, 2016 1:52 PM To: Python-Dev Subject: [Python-Dev] PEP: Ordered Class Definition Namespace
Currently the namespace used during execution of a class body defaults to dict. If the metaclass defines ``__prepare__()`` then the result of calling it is used. Thus, before this PEP, if you needed your class definition namespace to be ``OrderedDict`` you had to use a metaclass.
Formatting nit: ``dict``
Specification =============
* the default class *definition* namespace is now ``OrderdDict`` * the order in which class attributes are defined is preserved in the new ``__definition_order__`` attribute on each class * "dunder" attributes (e.g. ``__init__``, ``__module__``) are ignored
What does this imply? If I define some __dunder__ methods, will they simply not be present in __definition_order__? What if I want to keep the order of those? While keeping the order of these might be meaningless in most cases, I don't think there's really a huge problem in doing so. Maybe I'm overthinking it.
* ``__definition_order__`` is a tuple * ``__definition_order__`` is a read-only attribute * ``__definition_order__`` is always set:
* if ``__definition_order__`` is defined in the class body then it is used * types that do not have a class definition (e.g. builtins) have their ``__definition_order__`` set to ``None`` * types for which `__prepare__()`` returned something other than ``OrderedDict`` (or a subclass) have their ``__definition_order__`` set to ``None``
I would probably like a ``type.definition_order`` method, for which the return value is bound to __definition_order__ when the class is created (much like the link between ``type.mro`` and ``cls.__mro__``. Additionally I'm not sure if setting the attribute to None is a good idea; I'd have it as an empty tuple. Then again I tend to overthink a lot.
The following code demonstrates roughly equivalent semantics::
class Meta(type): def __prepare__(cls, *args, **kwargs): return OrderedDict()
class Spam(metaclass=Meta): ham = None eggs = 5 __definition_order__ = tuple(k for k in locals() if (!k.startswith('__') or !k.endswith('__')))
Mixing up C and Python syntax here.
However, using ``OrderedDict`` for ``type,__dict__`` would obscure the relationship with the definition namespace, making it less useful. Additionally, doing this would require significant changes to the semantics of the concrete dict C-API.
Formatting nit: ``dict`` I'm +1 on the whole idea (one of my common uses of metaclasses was to keep the definition order *somewhere*). Thank you for doing that! -Emanuel
On Tue, Jun 7, 2016 at 11:36 AM, Émanuel Barry <vgr255@live.ca> wrote:
From: Eric Snow * "dunder" attributes (e.g. ``__init__``, ``__module__``) are ignored
What does this imply? If I define some __dunder__ methods, will they simply not be present in __definition_order__? What if I want to keep the order of those? While keeping the order of these might be meaningless in most cases, I don't think there's really a huge problem in doing so. Maybe I'm overthinking it.
"dunder" names (not just methods) will not be present in __definition_order__. I'll add an explanation to the PEP. The gist of it is that they are reserved for use by the interpreter and will always clutter up __definition_order__. Since needing dunder names included in __definition_order__ would be rather exceptional, and there are other options available, leaving them out by default is a matter of practicality.
* ``__definition_order__`` is a tuple * ``__definition_order__`` is a read-only attribute * ``__definition_order__`` is always set:
* if ``__definition_order__`` is defined in the class body then it is used * types that do not have a class definition (e.g. builtins) have their ``__definition_order__`` set to ``None`` * types for which `__prepare__()`` returned something other than ``OrderedDict`` (or a subclass) have their ``__definition_order__`` set to ``None``
I would probably like a ``type.definition_order`` method, for which the return value is bound to __definition_order__ when the class is created (much like the link between ``type.mro`` and ``cls.__mro__``.
What is the value of type.definition_order()? If you need a mutable copy then pass __definition_order__ to list().
Additionally I'm not sure if setting the attribute to None is a good idea; I'd have it as an empty tuple. Then again I tend to overthink a lot.
None indicates that there is no order. An empty tuple indicates that there were no attributes.
__definition_order__ = tuple(k for k in locals() if (!k.startswith('__') or !k.endswith('__')))
Mixing up C and Python syntax here.
nice catch :)
I'm +1 on the whole idea (one of my common uses of metaclasses was to keep the definition order *somewhere*). Thank you for doing that!
:) -eric
From: Eric Snow Sent: Tuesday, June 07, 2016 2:52 PM To: Émanuel Barry Cc: Python-Dev Subject: Re: [Python-Dev] PEP: Ordered Class Definition Namespace
"dunder" names (not just methods) will not be present in __definition_order__. I'll add an explanation to the PEP. The gist of it is that they are reserved for use by the interpreter and will always clutter up __definition_order__. Since needing dunder names included in __definition_order__ would be rather exceptional, and there are other options available, leaving them out by default is a matter of practicality.
Good point. I'll assume that if we need that we'll do something in the metaclass.
What is the value of type.definition_order()? If you need a mutable copy then pass __definition_order__ to list().
I think I explained it backwards. I meant to have a method on ``type`` (which metaclasses can override at will) which will set what is passed to the resulting __definition_order__ attribute. But it might not be needed, as we can probably sneak that inside the namespace in the metaclass' __new__.
Additionally I'm not sure if setting the attribute to None is a good idea; I'd have it as an empty tuple. Then again I tend to overthink a lot.
None indicates that there is no order. An empty tuple indicates that there were no attributes.
Fair enough.
-eric
-Emanuel
On 7 June 2016 at 10:51, Eric Snow <ericsnowcurrently@gmail.com> wrote:
Specification =============
* the default class *definition* namespace is now ``OrderdDict`` * the order in which class attributes are defined is preserved in the new ``__definition_order__`` attribute on each class * "dunder" attributes (e.g. ``__init__``, ``__module__``) are ignored * ``__definition_order__`` is a tuple * ``__definition_order__`` is a read-only attribute
Thinking about the class decorator use case, I think this may need to be reconsidered, as class decorators may: 1. Remove class attributes 2. Add class attributes This will then lead to __definition_order__ getting out of sync with the current state of the class namespace. One option for dealing with that would be to make type.__setattr__ and type.__delattr__ aware of __definition_order__, and have them replace the tuple with a new one as needed. If we did that, then the main question would be whether updating an existing attribute changed the definition order, and I'd be inclined to say "No" (to minimise the side effects of monkey-patching). The main alternative would be to make __definition_order__ writable, so the default behaviour would be for it to reflect the original class body, but decorators would be free to update it to reflect their changes, as well as to make other modifications (e.g. stripping out all callables from the list). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
On Tue, Jun 7, 2016 at 12:30 PM, Nick Coghlan <ncoghlan@gmail.com> wrote:
On 7 June 2016 at 10:51, Eric Snow <ericsnowcurrently@gmail.com> wrote:
* ``__definition_order__`` is a tuple * ``__definition_order__`` is a read-only attribute
Thinking about the class decorator use case, I think this may need to be reconsidered, as class decorators may:
1. Remove class attributes 2. Add class attributes
This will then lead to __definition_order__ getting out of sync with the current state of the class namespace.
I'm not clear on your point. Decorators are applied after the class has been created. Hence they have no impact on the class's definition order. I'd expect __definition_order__ to strictly represent what happened in the class body during definition, and not anything afterward. Certainly __definition_order__ might not align with __dict__ (or dir()); we don't have any way to guarantee that it would, do we? If anything, the ability to diff __definition_order__ and __dict__ is a positive, since it allows you to see changes on the class since it was defined.
One option for dealing with that would be to make type.__setattr__ and type.__delattr__ aware of __definition_order__, and have them replace the tuple with a new one as needed. If we did that, then the main question would be whether updating an existing attribute changed the definition order, and I'd be inclined to say "No" (to minimise the side effects of monkey-patching).
The main alternative would be to make __definition_order__ writable, so the default behaviour would be for it to reflect the original class body, but decorators would be free to update it to reflect their changes, as well as to make other modifications (e.g. stripping out all callables from the list).
I think both of those make __definition_order__ more complicated and less useful. As the PEP stands, folks can be confident in what __definition_order__ represents. What would you consider to be the benefit of a mutable (or replaceable) __definition_order__ that outweighs the benefit of a simpler definition of what's in it. BTW, thanks for bringing this up. :) -eric
On 7 June 2016 at 14:20, Eric Snow <ericsnowcurrently@gmail.com> wrote:
On Tue, Jun 7, 2016 at 12:30 PM, Nick Coghlan <ncoghlan@gmail.com> wrote:
The main alternative would be to make __definition_order__ writable, so the default behaviour would be for it to reflect the original class body, but decorators would be free to update it to reflect their changes, as well as to make other modifications (e.g. stripping out all callables from the list).
I think both of those make __definition_order__ more complicated and less useful. As the PEP stands, folks can be confident in what __definition_order__ represents. What would you consider to be the benefit of a mutable (or replaceable) __definition_order__ that outweighs the benefit of a simpler definition of what's in it.
Mainly the fact that class decorators and metaclasses can't hide the difference between "attributes defined in the class body" and "attributes injected by a decorator or metaclass". I don't have a concrete use case for that, it just bothers me on general principles when we have things the interpreter can do that can't readily be emulated in Python code. However, if it proves to be a hassle in practice, making it writable can be done later based on specific use cases, so I don't mind if the PEP stays as it is on that front. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
On Tue, Jun 7, 2016 at 2:34 PM, Nick Coghlan <ncoghlan@gmail.com> wrote:
On 7 June 2016 at 14:20, Eric Snow <ericsnowcurrently@gmail.com> wrote:
What would you consider to be the benefit of a mutable (or replaceable) __definition_order__ that outweighs the benefit of a simpler definition of what's in it.
Mainly the fact that class decorators and metaclasses can't hide the difference between "attributes defined in the class body" and "attributes injected by a decorator or metaclass". I don't have a concrete use case for that, it just bothers me on general principles when we have things the interpreter can do that can't readily be emulated in Python code.
Yeah, I see what you mean.
However, if it proves to be a hassle in practice, making it writable can be done later based on specific use cases, so I don't mind if the PEP stays as it is on that front.
Agreed. -eric
On 06/07/2016 02:20 PM, Eric Snow wrote:
On Tue, Jun 7, 2016 at 12:30 PM, Nick Coghlan wrote:
On 7 June 2016 at 10:51, Eric Snow wrote:
* ``__definition_order__`` is a tuple * ``__definition_order__`` is a read-only attribute
Thinking about the class decorator use case, I think this may need to be reconsidered, as class decorators may:
1. Remove class attributes 2. Add class attributes
This will then lead to __definition_order__ getting out of sync with the current state of the class namespace.
I'm not clear on your point. Decorators are applied after the class has been created. Hence they have no impact on the class's definition order. I'd expect __definition_order__ to strictly represent what happened in the class body during definition, and not anything afterward.
Certainly __definition_order__ might not align with __dict__ (or dir()); we don't have any way to guarantee that it would, do we? If anything, the ability to diff __definition_order__ and __dict__ is a positive, since it allows you to see changes on the class since it was defined.
One option for dealing with that would be to make type.__setattr__ and type.__delattr__ aware of __definition_order__, and have them replace the tuple with a new one as needed. If we did that, then the main question would be whether updating an existing attribute changed the definition order, and I'd be inclined to say "No" (to minimise the side effects of monkey-patching).
The main alternative would be to make __definition_order__ writable, so the default behaviour would be for it to reflect the original class body, but decorators would be free to update it to reflect their changes, as well as to make other modifications (e.g. stripping out all callables from the list).
I think both of those make __definition_order__ more complicated and less useful. As the PEP stands, folks can be confident in what __definition_order__ represents. What would you consider to be the benefit of a mutable (or replaceable) __definition_order__ that outweighs the benefit of a simpler definition of what's in it.
I think the question is which is more useful? - a definition order that lists items that are not in the class, as well as not having items that are in the class (set by the decorator) or - a definition order that is representative of the class state after all decorators have been applied One argument for the latter is that, even though the class has been technically "defined" (class body executed, type.__new__ called, etc.), applying decorators feels like continued class definition. One argument for the former is simplified implementation, and is definition order really important after the class body has been executed? (okay, two arguments ;) Perhaps the best thing is just to make it writeable -- after all, if __class__, __name__, etc., can all be changed, why should __definition_order__ be special? -- ~Ethan~
On Tue, Jun 7, 2016 at 2:34 PM, Ethan Furman <ethan@stoneleaf.us> wrote:
On 06/07/2016 02:20 PM, Eric Snow wrote:
I think both of those make __definition_order__ more complicated and less useful. As the PEP stands, folks can be confident in what __definition_order__ represents. What would you consider to be the benefit of a mutable (or replaceable) __definition_order__ that outweighs the benefit of a simpler definition of what's in it.
I think the question is which is more useful?
- a definition order that lists items that are not in the class, as well as not having items that are in the class (set by the decorator)
or
- a definition order that is representative of the class state after all decorators have been applied
"definition" refers explicitly to the execution of the class body in a class statement. So what you've described is a bit confusing to me. If we're talking about some other semantics then the name "__definition_order__" is misleading. Also, consider that __definition_order__ is, IMHO, most useful when interpreted as the actual order of attributes in the class definition body. The point is that code outside the class body can leverage the order of assigned names within that block. So, relative to the class definition, I'm not clear on valid use cases that divorce themselves from the class definition, such that either of your scenarios is relevant. Semantics that relate more to the class namespace (__dict__) are a separate matter from this PEP. I'd welcome a broader solution that still met the needs at which __definition_order__ is aiming. For example, consider if the class's __dict__ (or rather the proxied value) were OrderedDict. In fact, Guido was originally (in 2013) amenable to that idea. However, I tried it and making it work was a challenge due to use of the concrete dict C-API. I'd be glad if it was worked out. In the meantime, this PEP is more focused on a practical representation of the ordering information inside just the class definition body.
One argument for the latter is that, even though the class has been technically "defined" (class body executed, type.__new__ called, etc.), applying decorators feels like continued class definition.
Perhaps. That doesn't align with my intuition on decorators, but I'll readily concede that my views aren't always particularly representative of everyone else. :) That said, there are many different uses for decorators and modifying the class namespace (__dict__) isn't the only one (and in my experience not necessarily the most common).
One argument for the former is simplified implementation,
I'm not sure what you're implying about the implementation. Do you mean that it's easier than just letting __definition_order__ be writable (or mutable)? It's actually slightly more work to make it a read-only attr. Perhaps you mean that the semantics in the PEP are easier to implement than something that tracks changes to the class namespace (__dict__) after definition is over? Probably, though I don't see anything like that happening (other than if OrderedDict were used for __dict__).
and is definition order really important after the class body has been executed? (okay, two arguments ;)
Given that the focus is on class definition, I'd argue no. :)
Perhaps the best thing is just to make it writeable -- after all, if __class__, __name__, etc., can all be changed, why should __definition_order__ be special?
Not all attrs are writable and it's a case-by-case situation: some of the ones that are writable started out read-only and changed once there was a valid reason. If anything, it's arguably safer in general to take an immutable-by-default approach. -eric
On 06/07/2016 03:27 PM, Eric Snow wrote:
Not all attrs are writable and it's a case-by-case situation: some of the ones that are writable started out read-only and changed once there was a valid reason. If anything, it's arguably safer in general to take an immutable-by-default approach.
I'm sold. Leave it read-only. :) -- ~Ethan~
On Jun 7, 2016, at 10:51 AM, Eric Snow <ericsnowcurrently@gmail.com> wrote:
This PEP changes the default class definition namespace to ``OrderedDict``.
I think this would be a nice improvement.
Furthermore, the order in which the attributes are defined in each class body will now be preserved in ``type.__definition_order__``. This allows introspection of the original definition order, e.g. by class decorators.
I'm unclear on why this would be needed. Wouldn't the OrderedDict be sufficient for preserving definition order? Raymond
On 7 June 2016 at 16:03, Raymond Hettinger <raymond.hettinger@gmail.com> wrote:
On Jun 7, 2016, at 10:51 AM, Eric Snow <ericsnowcurrently@gmail.com> wrote:
This PEP changes the default class definition namespace to ``OrderedDict``.
I think this would be a nice improvement.
Furthermore, the order in which the attributes are defined in each class body will now be preserved in ``type.__definition_order__``. This allows introspection of the original definition order, e.g. by class decorators.
I'm unclear on why this would be needed. Wouldn't the OrderedDict be sufficient for preserving definition order?
By the time decorators run, the original execution namespace is no longer available - the contents have been copied into the class dict, which will still be a plain dict (and there's a lot of code that calls PyDict_* APIs on tp_dict, so replacing the latter with a subclass is neither trivial nor particularly safe in the presence of extension modules). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
On Jun 7, 2016, at 4:12 PM, Nick Coghlan <ncoghlan@gmail.com> wrote:
By the time decorators run, the original execution namespace is no longer available - the contents have been copied into the class dict, which will still be a plain dict (and there's a lot of code that calls PyDict_* APIs on tp_dict, so replacing the latter with a subclass is neither trivial nor particularly safe in the presence of extension modules).
That makes sense. +1 all around. Raymond
On 07.06.16 20:51, Eric Snow wrote:
Hi all,
Following discussion a few years back (and rough approval from Guido [1]), I started work on using OrderedDict for the class definition namespace by default. The bulk of the effort lay in implementing OrderedDict in C, which I got landed just in time for 3.5. The remaining work was quite minimal and the actual change is quite small.
My intention was to land the patch soon, having gone through code review during PyCon. However, Nick pointed out to me the benefit of having a concrete point of reference for the change, as well as making sure it isn't a problem for other implementations. So in that spirit, here's a PEP for the change. Feedback is welcome, particularly from from other implementors.
Be aware that C implementation of OrderedDict still is not free from problems.
participants (8)
-
Eric Snow
-
Ethan Furman
-
Nick Coghlan
-
Raymond Hettinger
-
Serhiy Storchaka
-
Steven D'Aprano
-
Terry Reedy
-
Émanuel Barry