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

David Mertz mertz at gnosis.cx
Tue Sep 13 19:41:10 EDT 2016


Continuing the definition for a class feels to me like a strong
anti-pattern for Python. If you absolutely must do this, I guess the
presented decorator is available. It should be discouraged though, not be
part of new syntax.

I believe that if you find yourself doing this you should detect a bad
choice smell, and think about expressing your goal with inheritance,
delegation, or encapsulation instead.

On Sep 13, 2016 9:17 AM, "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/70626dd7/attachment-0001.html>


More information about the Python-ideas mailing list