<div dir="ltr">Hello developers,<div>I have written a functional reference implementation for the proposed continue class syntax which can be found at <a href="https://raw.githubusercontent.com/natelust/continueClassCpythonPatch/master/continueClass.patch">https://raw.githubusercontent.com/natelust/continueClassCpythonPatch/master/continueClass.patch</a> . This is a mercurial patch file created against python 3.5. An example of its functionality, and demonstration that it does not interfere with the existing continue keyword is as follows:</div><div><pre style="line-height:normal;word-wrap:break-word;white-space:pre-wrap"># Define a class Foo, taking a message as an argument
class Foo:
def __init__(self, message):
self.message = message
# Continue the definition of the class, adding a method to print
# the class message variable
continue class Foo:
def second(self):
print(self.message)
# Create an instance of the class
inst = Foo('Hello World')
# Demo the continued class
inst.second()
# Show that existing syntax still works
for i in range(5):
if i == 0:
continue
print(i)</pre><pre style="line-height:normal;word-wrap:break-word;white-space:pre-wrap"><br></pre><pre style="line-height:normal;word-wrap:break-word;white-space:pre-wrap"><font face="sans-serif" size="2">Thank you for your time and consideration, we will be happy to take any feedback or questions on the implementation.</font></pre><pre style="line-height:normal;word-wrap:break-word;white-space:pre-wrap"><font face="sans-serif" size="2">Nate Lust</font></pre></div><div><br></div></div><br><div class="gmail_quote"><div dir="ltr">On Tue, Sep 13, 2016 at 12:17 PM Pim Schellart <<a href="mailto:p.schellart@princeton.edu">p.schellart@princeton.edu</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Dear Python Developers,<br>
<br>
we have a potential idea for enhancing Python.<br>
Below you will find what the PEP might look like.<br>
A reference implementation has been written and will be posted in a follow up message.<br>
We are look forward to hearing your feedback and ideas.<br>
<br>
Kind regards,<br>
<br>
Pim Schellart & Nate Lust<br>
<br>
Abstract<br>
========<br>
<br>
This PEP proposes the introduction of new syntax to create a community standard,<br>
readable way to continue a definition for classes which are already defined.<br>
<br>
<br>
Rationale<br>
=========<br>
<br>
Extending existing classes with new members currently requires the members to be<br>
defined outside of class scope and then assigned to the class, as in::<br>
<br>
def foo(self):<br>
pass<br>
A.foo = foo<br>
del foo<br>
<br>
This pattern frequently occurs when extending classes from extension modules<br>
written in other languages, but is also not uncommon in pure Python code.<br>
<br>
This syntax is however cumbersome and error prone for the following reasons:<br>
<br>
1. The name of the new member might clash with an existing name at module<br>
scope.<br>
2. The developer might forget the assignment.<br>
3. The developer might forget to delete the temporary, leaving it at module<br>
scope where it is meaningless (or worse non functional as a stand alone<br>
function).<br>
<br>
Alternatives are to use inheritance, lambda or a decorator.<br>
<br>
Inheritance is not a good option for use with Python extension modules (written<br>
in for instance C / C++). The reason is that if in the other language the<br>
inheritance relation is A<-B, and this is exposed to Python, we can't add<br>
functionality to A in Python by subclassing A<-A' without also introducing B'<br>
that inherits from B and A'. Thus one change propagates all the way down the<br>
inheritance chain. Inheritance with pure Python classes exhibit the same issue.<br>
<br>
It might be tempting to avoid (1) and (2) by subclassing, reusing the name of<br>
the base class. However this approach suffers from two issues. The first issue,<br>
like above, has to do with the inheritance relation. If A subclasses A and B<br>
subclasses A (A<-A<-B), then calls to super in B may have unexpected behavior<br>
(anything using the method resolution order may exhibit the same<br>
unexpectedness). The second issue arises when class B inherits from class A<br>
before it is extended (A<-B) and then class A is extended though inheritance<br>
(A<-A). Class A will now have new methods and data members which are not<br>
present in B, as it is a subclass only of the original A. This would be<br>
confusing to anyone examining B as it would be apparently missing members of<br>
it's parent.<br>
<br>
Adding attributes to a class using lambda is not equivalent because it only<br>
allows for expressions and not statements.<br>
<br>
A class decorator (say "@continue_class(A)" that takes methods and attributes<br>
from the class and attaches them to the wrapped type) works, but is cumbersome<br>
and requires a new class name to be introduced for each extended type. Thus<br>
suffering from the same problems numbered (1) and (2) above.<br>
<br>
A function decorator could extend a class, but also requires defining a new name<br>
and suffers from problems (1) and (2).<br>
<br>
This proposal adds the keyword combination "continue class" which instructs the<br>
interpreter to add members to an existing class. This syntax requires no new<br>
keywords and allows all existing Python code to continue to function with no<br>
modification.<br>
<br>
By combining existing keywords it avoids name clashes. Precedents for this<br>
exists in "is not" and "yield from".<br>
<br>
Another big advantage of the "continue class" syntax is discoverability. For<br>
humans, the meaning of the syntax is evident, the class will be continued with<br>
the following block. Automated tools will also benefit from this syntax as<br>
parsing a file to discover the complete definition of a class will be easier<br>
than trying to detect 'monkey patching'.<br>
<br>
<br>
Semantics<br>
=========<br>
<br>
The following two snippets are semantically identical::<br>
<br>
continue class A:<br>
x = 5<br>
def foo(self):<br>
pass<br>
def bar(self):<br>
pass<br>
<br>
def foo(self):<br>
pass<br>
def bar(self):<br>
pass<br>
A.x = 5<br>
A.foo = foo<br>
A.bar = bar<br>
del foo<br>
del bar<br>
<br>
<br>
Alternatives<br>
============<br>
<br>
An alternative could be to allow a function definition to include a class<br>
specifier as in::<br>
<br>
def A.foo(self):<br>
pass<br>
<br>
<br>
Implementation<br>
==============<br>
<br>
Adapting Python's grammar to support the continue class keyword combination<br>
requires modifying the grammar file to parse for the new keyword combination.<br>
Additional changes to Python.asdl, ast.c, compile.c, symtable.c will be required<br>
to process the parsed syntax to byte code.<br>
<br>
A reference implementation (already written and posted separately) parses the<br>
continue class line for the name of the class to be modified and loads it. Next<br>
the body of the block is compiled into a code object scoped by the name of the<br>
class. The class and the code are used as arguments to a new built-in module,<br>
called __continue_class__. This function evaluates the code block, passing the<br>
results to setattr on the supplied class.<br>
_______________________________________________<br>
Python-ideas mailing list<br>
<a href="mailto:Python-ideas@python.org" target="_blank">Python-ideas@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/python-ideas" rel="noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/python-ideas</a><br>
Code of Conduct: <a href="http://python.org/psf/codeofconduct/" rel="noreferrer" target="_blank">http://python.org/psf/codeofconduct/</a><br>
</blockquote></div>