[Python-ideas] New Python syntax for continuing definitions for existing classes

nate lust natelust at linux.com
Tue Sep 13 12:22:52 EDT 2016


Hello developers,
I have written a functional reference implementation for the proposed
continue class syntax which can be found at
https://raw.githubusercontent.com/natelust/continueClassCpythonPatch/master/continueClass.patch
.
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:

# 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)


Thank you for your time and consideration, we will be happy to take
any feedback or questions on the implementation.

Nate Lust



On Tue, Sep 13, 2016 at 12:17 PM Pim Schellart <p.schellart at princeton.edu>
wrote:

> Dear Python Developers,
>
> we have a potential idea for enhancing Python.
> Below you will find what the PEP might look like.
> A reference implementation has been written and will be posted in a follow
> up message.
> We are look forward to hearing your feedback and ideas.
>
> Kind regards,
>
> Pim Schellart & Nate Lust
>
> Abstract
> ========
>
> This PEP proposes the introduction of new syntax to create a community
> standard,
> readable way to continue a definition for classes which are already
> defined.
>
>
> Rationale
> =========
>
> Extending existing classes with new members currently requires the members
> to be
> defined outside of class scope and then assigned to the class, as in::
>
>   def foo(self):
>       pass
>   A.foo = foo
>   del foo
>
> This pattern frequently occurs when extending classes from extension
> modules
> written in other languages, but is also not uncommon in pure Python code.
>
> This syntax is however cumbersome and error prone for the following
> reasons:
>
>   1. The name of the new member might clash with an existing name at module
>      scope.
>   2. The developer might forget the assignment.
>   3. The developer might forget to delete the temporary, leaving it at
> module
>      scope where it is meaningless (or worse non functional as a stand
> alone
>      function).
>
> Alternatives are to use inheritance, lambda or a decorator.
>
> Inheritance is not a good option for use with Python extension modules
> (written
> in for instance C / C++).  The reason is that if in the other language the
> inheritance relation is A<-B, and this is exposed to Python, we can't add
> functionality to A in Python by subclassing A<-A' without also introducing
> B'
> that inherits from B and A'.  Thus one change propagates all the way down
> the
> inheritance chain.  Inheritance with pure Python classes exhibit the same
> issue.
>
> It might be tempting to avoid (1) and (2) by subclassing, reusing the name
> of
> the base class. However this approach suffers from two issues.  The first
> issue,
> like above, has to do with the inheritance relation.  If A subclasses A
> and B
> subclasses A (A<-A<-B), then calls to super in B may have unexpected
> behavior
> (anything using the method resolution order may exhibit the same
> unexpectedness).  The second issue arises when class B inherits from class
> A
> before it is extended (A<-B) and then class A is extended though
> inheritance
> (A<-A).  Class A will now have new methods and data members which are not
> present in B, as it is a subclass only of the original A.  This would be
> confusing to anyone examining B as it would be apparently missing members
> of
> it's parent.
>
> Adding attributes to a class using lambda is not equivalent because it only
> allows for expressions and not statements.
>
> A class decorator (say "@continue_class(A)" that takes methods and
> attributes
> from the class and attaches them to the wrapped type) works, but is
> cumbersome
> and requires a new class name to be introduced for each extended type.
> Thus
> suffering from the same problems numbered (1) and (2) above.
>
> A function decorator could extend a class, but also requires defining a
> new name
> and suffers from problems (1) and (2).
>
> This proposal adds the keyword combination "continue class" which
> instructs the
> interpreter to add members to an existing class.  This syntax requires no
> new
> keywords and allows all existing Python code to continue to function with
> no
> modification.
>
> By combining existing keywords it avoids name clashes.  Precedents for this
> exists in "is not" and "yield from".
>
> Another big advantage of the "continue class" syntax is discoverability.
> For
> humans, the meaning of the syntax is evident, the class will be continued
> with
> the following block.  Automated tools will also benefit from this syntax as
> parsing a file to discover the complete definition of a class will be
> easier
> than trying to detect 'monkey patching'.
>
>
> Semantics
> =========
>
> The following two snippets are semantically identical::
>
>   continue class A:
>       x = 5
>       def foo(self):
>           pass
>       def bar(self):
>           pass
>
>   def foo(self):
>       pass
>   def bar(self):
>       pass
>   A.x = 5
>   A.foo = foo
>   A.bar = bar
>   del foo
>   del bar
>
>
> Alternatives
> ============
>
> An alternative could be to allow a function definition to include a class
> specifier as in::
>
>   def A.foo(self):
>     pass
>
>
> Implementation
> ==============
>
> Adapting Python's grammar to support the continue class keyword combination
> requires modifying the grammar file to parse for the new keyword
> combination.
> Additional changes to Python.asdl, ast.c, compile.c, symtable.c will be
> required
> to process the parsed syntax to byte code.
>
> A reference implementation (already written and posted separately) parses
> the
> continue class line for the name of the class to be modified and loads
> it.  Next
> the body of the block is compiled into a code object scoped by the name of
> the
> class.  The class and the code are used as arguments to a new built-in
> module,
> called __continue_class__.  This function evaluates the code block,
> passing the
> results to setattr on the supplied class.
> _______________________________________________
> Python-ideas mailing list
> Python-ideas at python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20160913/4fceeb71/attachment.html>


More information about the Python-ideas mailing list