<div dir="ltr"><div class="gmail_default" style="font-family:monospace,monospace">While I really can't continue to be active in this discussion now [*], here are some thoughts based on observations I made:</div><div class="gmail_default" style="font-family:monospace,monospace"><br></div><div class="gmail_default" style="font-family:monospace,monospace">These three PEPs are all essentially solving an occurrence of the same problem:</div><div class="gmail_default" style="font-family:monospace,monospace"><br></div><div class="gmail_default" style="font-family:monospace,monospace">PEP 549 Instance descriptors</div><div class="gmail_default" style="font-family:monospace,monospace">PEP 562 Module __getattr__</div><div class="gmail_default" style="font-family:monospace,monospace">PEP 560 Core support for generic types (the __class_getitem__ part)</div><div class="gmail_default" style="font-family:monospace,monospace"><br></div><div class="gmail_default"><font face="monospace, monospace"><a href="https://www.python.org/dev/peps/pep-0549/">https://www.python.org/dev/peps/pep-0549/</a></font><br></div><div class="gmail_default"><font face="monospace, monospace"><a href="https://www.python.org/dev/peps/pep-0562/">https://www.python.org/dev/peps/pep-0562/</a><br></font></div><div class="gmail_default" style="font-family:monospace,monospace"><a href="https://www.python.org/dev/peps/pep-0560/">https://www.python.org/dev/peps/pep-0560/</a><br></div><div class="gmail_default" style="font-family:monospace,monospace"><br></div><div class="gmail_default" style="font-family:monospace,monospace">PEPs 549 and 562 want an instance of ModuleType (i.e. modules) to define something on itself that looks like there was something defined on the class. For PEP 549 this is a property and for 562 it's a __getattr__ method.<br></div><div class="gmail_default" style="font-family:monospace,monospace"><br></div><div class="gmail_default" style="font-family:monospace,monospace">PEP 560 wants a __class_getitem__ method, defined on a class (instance of a metaclass), to look like there was a __getitem__ on the metaclass.</div><div class="gmail_default" style="font-family:monospace,monospace"><br></div><div class="gmail_default" style="font-family:monospace,monospace">PEP 560 is thus an attempt at a more fine-grained definition of a metaclass-like feature, where conflicts are less likely or can potentially be better dealth with. While PEPs 549 and 562 are doing a very similar thing to PEP 560 in theory, these use cases do not fall nicely into Nick's classification of uses for metaclasses in the email below.</div><div class="gmail_default" style="font-family:monospace,monospace"><br></div><div class="gmail_default" style="font-family:monospace,monospace">PEP 560 is trying to avoid a metaclass (a subclass of type) as an additional base class specifically for one class object). PEPs 549 and 562 are trying to avoid an additional class (a subclass of ModuleType) as an additional base class specifically for this one module.</div><div class="gmail_default" style="font-family:monospace,monospace"><br></div><div class="gmail_default" style="font-family:monospace,monospace">Whether or not fine-grainedness is the answer, it might make sense to list more different related use cases. Probably even the peps repo has more examples than the three I listed above.</div><div class="gmail_default" style="font-family:monospace,monospace"><br></div><div class="gmail_default" style="font-family:monospace,monospace">––Koos</div><div class="gmail_default"><font face="monospace, monospace"><br></font></div><div class="gmail_extra"><div class="gmail_default"><font face="monospace, monospace">[*] I'll try to be able to do what's nee½ded for the PEP 555 di</font><font face="monospace, monospace">scussion — no</font><span style="font-family:monospace,monospace">1/3</span><font face="monospace, monospace">w s</font><font face="monospace, monospace">til</font><font face="monospace, monospace">l on py</font><span style="font-family:monospace,monospace">thon-ideas.</span></div><div class="gmail_extra"><br></div><br><div class="gmail_quote">On Fri, Oct 13, 2017 at 9:30 AM, Nick Coghlan <span dir="ltr"><<a href="mailto:ncoghlan@gmail.com" target="_blank">ncoghlan@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On 13 October 2017 at 04:21, Martin Teichmann <span dir="ltr"><<a href="mailto:lkb.teichmann@gmail.com" target="_blank">lkb.teichmann@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">For me, the dataclasses were a typical example for inheritance, to be<br>
more precise, for metaclasses. I was astonished to see them<br>
implemented using decorators, and I was not the only one, citing<br>
Guido:<br>
<span><br>
> I think it would be useful to write 1-2 sentences about the problem with<br>
> inheritance -- in that case you pretty much have to use a metaclass, and the<br>
> use of a metaclass makes life harder for people who want to use their own<br>
> metaclass (since metaclasses don't combine without some manual<br>
> intervention).<br>
<br>
</span>Python is at a weird point here. At about every new release of Python,<br>
a new idea shows up that could be easily solved using metaclasses, yet<br>
every time we hesitate to use them, because of said necessary manual<br>
intervention for metaclass combination.<br></blockquote><div><br></div><div>Metaclasses currently tend to serve two distinct purposes:</div><div><br></div><div>1. Actually altering the runtime behaviour of a class and its children in non-standard ways (e.g. enums, ABCs, ORMs)</div>2. Boilerplate reduction in class definitions, reducing the amount of code you need to write as the author of that class<div><br></div><div>Nobody has a problem with using metaclasses for the first purpose - that's what they're for.</div><div><br></div><div>It's the second use case where they're problematic, as the fact that they're preserved on the class becomes a leaky implementation detail, and the lack of a JIT in CPython means they can also end up being expensive from a runtime performance perspective.</div><div><br></div><div>Mixin classes have the same problem: something that the author may want to handle as an internal implementation detail leaks through to the runtime state of the class object.<br></div> </div><div class="gmail_quote">Code generating decorators like functools.total_ordering and dataclasses.dataclass (aka attr.s) instead aim at the boilerplate reduction problem directly: they let you declare in the class body the parts that you need to specify as the class designer, and then fill in at class definition time the parts that can be inferred from that base.</div><div class="gmail_quote"><br></div><div class="gmail_quote">If all you have access to is the runtime class, it behaves almost exactly as if you had written out all the autogenerated methods by hand (there may be subtle differences in the method metadata, such as the values of `__qualname__` and `__globals__`).</div><div class="gmail_quote"><br></div><div class="gmail_quote">Such decorators also do more work at class definition time in order to reduce the amount of runtime overhead introduced by reliance on chained method calls in a non-JITted Python runtime.</div><div class="gmail_quote"><br></div><div class="gmail_quote">As such, the code generating decorators have a clear domain of applicability: boilerplate reduction for class definitions without impacting the way instances behave (other than attribute and method injection), and without implicitly impacting subclass definitions (other than through regular inheritance behaviour).</div><div class="gmail_quote"><br></div><div class="gmail_quote">As far as the dataclass interaction with `__slots__` goes, that's a problem largely specific to slots (and `__metaclass__` before it), in that they're the only characteristics of a class definition that affect how CPython allocates memory for the class object itself (the descriptors for the slots are stored as a pointer array after the class struct, rather than only in the class dict).</div><div class="gmail_quote"><br></div><div class="gmail_quote">Given PEP 526 variable annotations, __slots__ could potentially benefit from a __metaclass__ style makeover, allowing an "infer_slots=True" keyword argument to type.__new__ to request that the list of slots be inferred from __annotations__ (Slot inference would conflict with setting class level default values, but that's a real conflict, as you'd be trying to use the same name on the class object for both the slot descriptor and the default value)<br></div><div class="gmail_quote"><br></div><div class="gmail_quote"><div>Cheers,</div><div>Nick.<span class="gmail-HOEnZb"><font color="#888888"><br></font></span></div><span class="gmail-HOEnZb"><font color="#888888"><br></font></span></div><span class="gmail-HOEnZb"><font color="#888888">-- <br><div class="gmail-m_8247701793468695643gmail_signature">Nick Coghlan | <a href="mailto:ncoghlan@gmail.com" target="_blank">ncoghlan@gmail.com</a> | Brisbane, Australia</div>
</font></span></div></div>
<br>______________________________<wbr>_________________<br>
Python-Dev mailing list<br>
<a href="mailto:Python-Dev@python.org">Python-Dev@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/python-dev" rel="noreferrer" target="_blank">https://mail.python.org/<wbr>mailman/listinfo/python-dev</a><br>
Unsubscribe: <a href="https://mail.python.org/mailman/options/python-dev/k7hoven%40gmail.com" rel="noreferrer" target="_blank">https://mail.python.org/<wbr>mailman/options/python-dev/<wbr>k7hoven%40gmail.com</a><br>
<br></blockquote></div><br><br clear="all"><div><br></div>-- <br><div class="gmail_signature">+ Koos Zevenhoven + <a href="http://twitter.com/k7hoven" target="_blank">http://twitter.com/k7hoven</a> +</div>
</div></div>