Switch PEP 403 from : and @ symbols to postdef and def keywords
This commit is contained in:
parent
3377fbf36a
commit
7b0a3e1a8b
138
pep-0403.txt
138
pep-0403.txt
|
@ -1,5 +1,5 @@
|
||||||
PEP: 403
|
PEP: 403
|
||||||
Title: Statement local classes and functions
|
Title: Prefix syntax for post function definition operations
|
||||||
Version: $Revision$
|
Version: $Revision$
|
||||||
Last-Modified: $Date$
|
Last-Modified: $Date$
|
||||||
Author: Nick Coghlan <ncoghlan@gmail.com>
|
Author: Nick Coghlan <ncoghlan@gmail.com>
|
||||||
|
@ -15,17 +15,17 @@ Resolution: TBD
|
||||||
Abstract
|
Abstract
|
||||||
========
|
========
|
||||||
|
|
||||||
This PEP proposes the addition of ':' as a new class and function prefix
|
This PEP proposes the addition of ``postdef`` as a new function prefix
|
||||||
syntax (analogous to decorators) that permits a statement local function or
|
syntax (analogous to decorators) that permits the execution of a single simple
|
||||||
class definition to be appended to any Python statement that currently does
|
statement (potentially including substatements separated by semi-colons) after
|
||||||
not have an associated suite.
|
|
||||||
|
|
||||||
In addition, the new syntax would allow the '@' symbol to be used to refer
|
In addition, the new syntax would allow the 'def' keyword to be used to refer
|
||||||
to the statement local function or class without needing to repeat the name.
|
to the function being defined without needing to repeat the name.
|
||||||
|
|
||||||
When the ':' prefix syntax is used, the associated statement would be executed
|
When the 'postdef' prefix syntax is used, the associated statement would be
|
||||||
*instead of* the normal local name binding currently implicit in function
|
executed *in addition to* the normal local name binding implicit in function
|
||||||
and class definitions.
|
definitions. Any name collision are expected to be minor, analagous to those
|
||||||
|
encountered with ``for`` loop iteration variables.
|
||||||
|
|
||||||
This PEP is based heavily on many of the ideas in PEP 3150 (Statement Local
|
This PEP is based heavily on many of the ideas in PEP 3150 (Statement Local
|
||||||
Namespaces) so some elements of the rationale will be familiar to readers of
|
Namespaces) so some elements of the rationale will be familiar to readers of
|
||||||
|
@ -57,7 +57,7 @@ examples of the kind of code it is designed to simplify.
|
||||||
|
|
||||||
As a trivial example, weakref callbacks could be defined as follows::
|
As a trivial example, weakref callbacks could be defined as follows::
|
||||||
|
|
||||||
:x = weakref.ref(obj, @)
|
postdef x = weakref.ref(target, def)
|
||||||
def report_destruction(obj):
|
def report_destruction(obj):
|
||||||
print("{} is being destroyed".format(obj))
|
print("{} is being destroyed".format(obj))
|
||||||
|
|
||||||
|
@ -67,33 +67,39 @@ operation::
|
||||||
def report_destruction(obj):
|
def report_destruction(obj):
|
||||||
print("{} is being destroyed".format(obj))
|
print("{} is being destroyed".format(obj))
|
||||||
|
|
||||||
x = weakref.ref(obj, report_destruction)
|
x = weakref.ref(target, report_destruction)
|
||||||
|
|
||||||
That structure is OK when you're using the callable multiple times, but
|
That structure is OK when you're using the callable multiple times, but
|
||||||
it's irritating to be forced into it for one-off operations.
|
it's irritating to be forced into it for one-off operations.
|
||||||
|
|
||||||
Similarly, singleton classes could now be defined as::
|
Similarly, a sorted operation on a particularly poorly defined type could
|
||||||
|
now be defined as::
|
||||||
|
|
||||||
:instance = @()
|
postdef sorted_list = sorted(original, key=def)
|
||||||
class OnlyOneInstance:
|
def force_sort(item):
|
||||||
pass
|
try:
|
||||||
|
return item.calc_sort_order()
|
||||||
|
except NotSortableError:
|
||||||
|
return float('inf')
|
||||||
|
|
||||||
Rather than::
|
Rather than::
|
||||||
|
|
||||||
class OnlyOneInstance:
|
def force_sort(item):
|
||||||
pass
|
try:
|
||||||
|
return item.calc_sort_order()
|
||||||
|
except NotSortableError:
|
||||||
|
return float('inf')
|
||||||
|
|
||||||
instance = OnlyOneInstance()
|
sorted_list = sorted(original, key=force_sort)
|
||||||
|
|
||||||
And the infamous accumulator example could become::
|
And early binding semantics in a list comprehension could be attained via::
|
||||||
|
|
||||||
|
postdef funcs = [def(i) for i in range(10)]
|
||||||
|
def make_incrementor(i):
|
||||||
|
postdef return def
|
||||||
|
def incrementor(x):
|
||||||
|
return x + i
|
||||||
|
|
||||||
def counter():
|
|
||||||
x = 0
|
|
||||||
:return @
|
|
||||||
def increment():
|
|
||||||
nonlocal x
|
|
||||||
x += 1
|
|
||||||
return x
|
|
||||||
|
|
||||||
Proposal
|
Proposal
|
||||||
========
|
========
|
||||||
|
@ -101,16 +107,19 @@ Proposal
|
||||||
This PEP proposes the addition of an optional block prefix clause to the
|
This PEP proposes the addition of an optional block prefix clause to the
|
||||||
syntax for function and class definitions.
|
syntax for function and class definitions.
|
||||||
|
|
||||||
This block prefix would be introduced by a leading ``:`` and would be
|
This block prefix would be introduced by a leading ``postdef`` and would be
|
||||||
allowed to contain any simple statement (including those that don't
|
allowed to contain any simple statement (including those that don't
|
||||||
make any sense in that context - while such code would be legal,
|
make any sense in that context - while such code would be legal,
|
||||||
there wouldn't be any point in writing it).
|
there wouldn't be any point in writing it). This permissive structure is
|
||||||
|
easier to define and easier to explain, but a more restrictive approach that
|
||||||
|
only permits operations that "make sense" would also be possible (see PEP
|
||||||
|
3150 for a list of possible candidates)
|
||||||
|
|
||||||
The decorator symbol ``@`` would be repurposed inside the block prefix
|
The function definition keyword ``def`` would be repurposed inside the block prefix
|
||||||
to refer to the function or class being defined.
|
to refer to the function being defined.
|
||||||
|
|
||||||
When a block prefix is provided, it *replaces* the standard local
|
When a block prefix is provided, the standard local name binding implicit
|
||||||
name binding otherwise implicit in a class or function definition.
|
in the function definition still takes place.
|
||||||
|
|
||||||
|
|
||||||
Background
|
Background
|
||||||
|
@ -143,7 +152,7 @@ However, adopting Ruby's block syntax directly won't work for Python, since
|
||||||
the effectiveness of Ruby's blocks relies heavily on various conventions in
|
the effectiveness of Ruby's blocks relies heavily on various conventions in
|
||||||
the way functions are *defined* (specifically, Ruby's ``yield`` syntax to
|
the way functions are *defined* (specifically, Ruby's ``yield`` syntax to
|
||||||
call blocks directly and the ``&arg`` mechanism to accept a block as a
|
call blocks directly and the ``&arg`` mechanism to accept a block as a
|
||||||
functions final argument.
|
function's final argument).
|
||||||
|
|
||||||
Since Python has relied on named functions for so long, the signatures of
|
Since Python has relied on named functions for so long, the signatures of
|
||||||
APIs that accept callbacks are far more diverse, thus requiring a solution
|
APIs that accept callbacks are far more diverse, thus requiring a solution
|
||||||
|
@ -163,24 +172,35 @@ with something else (like assigning the result of the function to a value).
|
||||||
|
|
||||||
This PEP also achieves most of the other effects described in PEP 3150
|
This PEP also achieves most of the other effects described in PEP 3150
|
||||||
without introducing a new brainbending kind of scope. All of the complex
|
without introducing a new brainbending kind of scope. All of the complex
|
||||||
scoping rules in PEP 3150 are replaced in this PEP with the simple ``@``
|
scoping rules in PEP 3150 are replaced in this PEP with the simple ``def``
|
||||||
reference to the statement local function or class definition.
|
reference to the associated function definition.
|
||||||
|
|
||||||
|
|
||||||
Symbol Choice
|
Keyword Choice
|
||||||
==============
|
==============
|
||||||
|
|
||||||
The ':' symbol was chosen due to its existing presence in Python and its
|
|
||||||
association with 'functions in expressions' via ``lambda`` expressions. The
|
|
||||||
past Simple Implicit Lambda proposal (PEP ???) was also a factor.
|
|
||||||
|
|
||||||
The proposal definitely requires *some* kind of prefix to avoid parsing
|
The proposal definitely requires *some* kind of prefix to avoid parsing
|
||||||
ambiguity and backwards compatibility problems and ':' at least has the
|
ambiguity and backwards compatibility problems with existing constructs.
|
||||||
virtue of brevity. There's no obious alternative symbol that offers a
|
It also needs to be clearly highlighted to readers, since it declares that
|
||||||
clear improvement.
|
the following piece of code is going to be executed out of order.
|
||||||
|
|
||||||
Introducing a new keyword is another possibility, but I haven't come up
|
The 'postdef' keyword was chosen as a literal explanation of exactly what
|
||||||
with one that really has anything to offer over the leading colon.
|
the new clause does: execute the specified statement *after* the associated
|
||||||
|
function definition, even though it is physically written *before* the
|
||||||
|
definition in the source code.
|
||||||
|
|
||||||
|
|
||||||
|
Requirement to Name Functions
|
||||||
|
=============================
|
||||||
|
|
||||||
|
One of the objections to widespread use of lambda expressions is that they
|
||||||
|
have an atrocious effect on traceback intelligibility and other aspects of
|
||||||
|
introspection. Accordingly, this PEP requires that even throwaway functions
|
||||||
|
be given some kind of name.
|
||||||
|
|
||||||
|
To help encourage the use of meaningful names without users having to repeat
|
||||||
|
themselves, the PEP suggests the provision of the ``def`` shorthand reference
|
||||||
|
to the current function from the ``postdef`` clause.
|
||||||
|
|
||||||
|
|
||||||
Syntax Change
|
Syntax Change
|
||||||
|
@ -198,17 +218,17 @@ Changed::
|
||||||
atom: ('(' [yield_expr|testlist_comp] ')' |
|
atom: ('(' [yield_expr|testlist_comp] ')' |
|
||||||
'[' [testlist_comp] ']' |
|
'[' [testlist_comp] ']' |
|
||||||
'{' [dictorsetmaker] '}' |
|
'{' [dictorsetmaker] '}' |
|
||||||
NAME | NUMBER | STRING+ | '...' | 'None' | 'True' | 'False' | '@')
|
NAME | NUMBER | STRING+ | '...' | 'None' | 'True' | 'False' | 'def')
|
||||||
|
|
||||||
New::
|
New::
|
||||||
|
|
||||||
blockprefix: ':' simple_stmt
|
blockprefix: 'postdef' simple_stmt
|
||||||
block: blockprefix (decorated | classdef | funcdef)
|
block: blockprefix funcdef
|
||||||
|
|
||||||
The above is the general idea, but I suspect that change to the 'atom'
|
The above is the general idea, but I suspect that the change to the 'atom'
|
||||||
definition would cause an ambiguity problem in the parser when it comes to
|
definition may cause an ambiguity problem in the parser when it comes to
|
||||||
detecting decorator lines. So the actual implementation would be more complex
|
detecting function definitions. So the actual implementation may need to be
|
||||||
than that.
|
more complex than that.
|
||||||
|
|
||||||
Grammar: http://hg.python.org/cpython/file/default/Grammar/Grammar
|
Grammar: http://hg.python.org/cpython/file/default/Grammar/Grammar
|
||||||
|
|
||||||
|
@ -219,13 +239,12 @@ Possible Implementation Strategy
|
||||||
This proposal has one titanic advantage over PEP 3150: implementation
|
This proposal has one titanic advantage over PEP 3150: implementation
|
||||||
should be relatively straightforward.
|
should be relatively straightforward.
|
||||||
|
|
||||||
Both the class and function definition statements emit code to perform
|
The post definition statement can be incorporated into the AST for the
|
||||||
the local name binding for their defined name. Implementing this PEP
|
function node and simply visited out of sequence.
|
||||||
should just require intercepting that code generation and replacing
|
|
||||||
it with the code in the block prefix.
|
|
||||||
|
|
||||||
The one potentially tricky part is working out how to allow the dual
|
The one potentially tricky part is working out how to allow the dual
|
||||||
use of '@' without rewriting half the grammar definition.
|
use of 'def' without rewriting half the grammar definition.
|
||||||
|
|
||||||
|
|
||||||
More Examples
|
More Examples
|
||||||
=============
|
=============
|
||||||
|
@ -273,6 +292,9 @@ TO DO
|
||||||
|
|
||||||
Sort out links and references to everything :)
|
Sort out links and references to everything :)
|
||||||
|
|
||||||
|
Start of python-ideas thread:
|
||||||
|
http://mail.python.org/pipermail/python-ideas/2011-October/012276.html
|
||||||
|
|
||||||
|
|
||||||
Acknowledgements
|
Acknowledgements
|
||||||
================
|
================
|
||||||
|
|
Loading…
Reference in New Issue