On Sat, Jul 2, 2016 at 10:50 AM, Martin Teichmann <lkb.teichm...@gmail.com> wrote: > Hi list, > > so this is the next round for PEP 487. During the last round, most of > the comments were in the direction that a two step approach for > integrating into Python, first in pure Python, later in C, was not a > great idea and everything should be in C directly. So I implemented it > in C, put it onto the issue tracker here: > http://bugs.python.org/issue27366, and also modified the PEP > accordingly.
Thanks! Reviewing inline below. > For those who had not been in the discussion, PEP 487 proposes to add > two hooks, __init_subclass__ which is a classmethod called whenever a > class is subclassed, and __set_owner__, a hook in descriptors which > gets called once the class the descriptor is part of is created. > > While implementing PEP 487 I realized that there is and oddity in the > type base class: type.__init__ forbids to use keyword arguments, even > for the usual three arguments it has (name, base and dict), while > type.__new__ allows for keyword arguments. As I plan to forward any > keyword arguments to the new __init_subclass__, I stumbled over that. > As I write in the PEP, I think it would be a good idea to forbid using > keyword arguments for type.__new__ as well. But if people think this > would be to big of a change, it would be possible to do it > differently. This is an area of exceeding subtlety (and also not very well documented/specified, probably). I'd worry that changing anything here might break some code. When a metaclass overrides neither __init__ nor __new__, keyword args will not work because type.__init__ forbids them. However when a metaclass overrides them and calls them using super(), it's quite possible that someone ended up calling super().__init__() with three positional args but super().__new__() with keyword args, since the call sites are distinct (in the overrides for __init__ and __new__ respectively). What's your argument for changing this, apart from a desire for more regularity? > Hoping for good comments > > Greetings > > Martin > > The PEP follows: > > PEP: 487 > Title: Simpler customisation of class creation > Version: $Revision$ > Last-Modified: $Date$ > Author: Martin Teichmann <lkb.teichm...@gmail.com>, > Status: Draft > Type: Standards Track > Content-Type: text/x-rst > Created: 27-Feb-2015 > Python-Version: 3.6 > Post-History: 27-Feb-2015, 5-Feb-2016, 24-Jun-2016, 2-Jul-2016 > Replaces: 422 > > > Abstract > ======== > > Currently, customising class creation requires the use of a custom metaclass. > This custom metaclass then persists for the entire lifecycle of the class, > creating the potential for spurious metaclass conflicts. > > This PEP proposes to instead support a wide range of customisation > scenarios through a new ``__init_subclass__`` hook in the class body, > and a hook to initialize attributes. > > The new mechanism should be easier to understand and use than > implementing a custom metaclass, and thus should provide a gentler > introduction to the full power Python's metaclass machinery. > > > Background > ========== > > Metaclasses are a powerful tool to customize class creation. They have, > however, the problem that there is no automatic way to combine metaclasses. > If one wants to use two metaclasses for a class, a new metaclass combining > those two needs to be created, typically manually. > > This need often occurs as a surprise to a user: inheriting from two base > classes coming from two different libraries suddenly raises the necessity > to manually create a combined metaclass, where typically one is not > interested in those details about the libraries at all. This becomes > even worse if one library starts to make use of a metaclass which it > has not done before. While the library itself continues to work perfectly, > suddenly every code combining those classes with classes from another library > fails. > > Proposal > ======== > > While there are many possible ways to use a metaclass, the vast majority > of use cases falls into just three categories: some initialization code > running after class creation, the initalization of descriptors and > keeping the order in which class attributes were defined. > > The first two categories can easily be achieved by having simple hooks > into the class creation: > > 1. An ``__init_subclass__`` hook that initializes > all subclasses of a given class. > 2. upon class creation, a ``__set_owner__`` hook is called on all the > attribute (descriptors) defined in the class, and > > The third category is the topic of another PEP 520. > > As an example, the first use case looks as follows:: > > >>> class SpamBase: > ... # this is implicitly a @classmethod > ... def __init_subclass__(cls, **kwargs): > ... cls.class_args = kwargs > ... super().__init_subclass__(cls, **kwargs) > > >>> class Spam(SpamBase, a=1, b="b"): > ... pass > > >>> Spam.class_args > {'a': 1, 'b': 'b'} > > The base class ``object`` contains an empty ``__init_subclass__`` > method which serves as an endpoint for cooperative multiple inheritance. > Note that this method has no keyword arguments, meaning that all > methods which are more specialized have to process all keyword > arguments. I'm confused. In the above example it would seem that the keyword args {'a': 1, 'b': 2} are passed right on to super9).__init_subclass__(). Do you mean that it ignores all keyword args? Or that it has no positional args? (Both of which would be consistent with the example.) > This general proposal is not a new idea (it was first suggested for > inclusion in the language definition `more than 10 years ago`_, and a > similar mechanism has long been supported by `Zope's ExtensionClass`_), > but the situation has changed sufficiently in recent years that > the idea is worth reconsidering for inclusion. Can you state exactly at which point during class initialization __init_class__() is called? (Surely by now, having implemented it, you know exactly where. :-) [This is as far as I got reviewing when the weekend activities interrupted me. In the light of ongoing discussion I'm posting this now -- I'll continue later.] -- --Guido van Rossum (python.org/~guido) _______________________________________________ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com