[Python-checkins] peps: Some new ideas for PEP 3150

nick.coghlan python-checkins at python.org
Fri Aug 2 18:43:13 CEST 2013


http://hg.python.org/peps/rev/061a39bd358a
changeset:   5028:061a39bd358a
user:        Nick Coghlan <ncoghlan at gmail.com>
date:        Sat Aug 03 02:42:54 2013 +1000
summary:
  Some new ideas for PEP 3150

files:
  pep-3150.txt |  120 ++++++++++++++++++++++++++++----------
  1 files changed, 87 insertions(+), 33 deletions(-)


diff --git a/pep-3150.txt b/pep-3150.txt
--- a/pep-3150.txt
+++ b/pep-3150.txt
@@ -19,9 +19,11 @@
 Python statements that do not currently have an associated code suite. This
 clause will create a statement local namespace for additional names that are
 accessible in the associated statement, but do not become part of the
-containing namespace. To permit a sane implementation strategy, forward
-references to names from the ``given`` clause will need to be marked
-explicitly.
+containing namespace.
+
+Adoption of a new symbol, ``?``, is proposed to denote a forward reference
+to the namespace created by running the associated code suite. It will be
+a reference to a ``types.SimpleNamespace`` object.
 
 The primary motivation is to enable a more declarative style of programming,
 where the operation to be performed is presented to the reader first, and the
@@ -72,12 +74,16 @@
 name in the header line, with the actual definitions following in
 the indented clause. As a simple example::
 
-   sorted_data = sorted(data, key=.sort_key) given:
+   sorted_data = sorted(data, key=?.sort_key) given:
        def sort_key(item):
            return item.attr1, item.attr2
 
-The leading ``.`` on ``.sort_key`` indicates to the compiler that this
-is a forward reference to a name defined in the ``given`` clause.
+The new symbol ``?`` is used to refer to the given namespace. It would be a
+``types.SimpleNamespace`` instance, so ``?.sort_key`` functions as
+a forward reference to a name defined in the ``given`` clause.
+
+A docstring would be permitted in the given clause, and would be attached
+to the result namespace as its ``__doc__`` attribute.
 
 The ``pass`` statement is included to provide a consistent way to skip
 inclusion of a meaningful expression in the header line. While this is not
@@ -94,7 +100,7 @@
    # Explicit early binding via given clause
    seq = []
    for i in range(10):
-       seq.append(.f) given i=i:
+       seq.append(.f) given i=i in:
            def f():
                return i
    assert [f() for f in seq] == list(range(10))
@@ -105,7 +111,7 @@
 
 The following statement::
 
-   op(.f, .g) given bound_a=a, bound_b=b:
+   op(?.f, ?.g) given bound_a=a, bound_b=b in:
        def f():
            return bound_a + bound_b
        def g():
@@ -121,9 +127,10 @@
            return bound_a + bound_b
        def g():
            return bound_a - bound_b
-      return f, g
-   __ref1, __ref2 = __scope(__arg1)
-   op(__ref1, __ref2)
+      return types.SimpleNamespace(**locals())
+   __ref = __scope(__arg1, __arg2)
+   __ref.__doc__ = __scope.__doc__
+   op(__ref.f, __ref.g)
 
 A ``given`` clause is essentially a nested function which is created and
 then immediately executed. Unless explicitly passed in, names are looked
@@ -158,7 +165,7 @@
    yield_stmt: yield_expr [given_clause]
    raise_stmt: 'raise' [test ['from' test]] [given_clause]
    assert_stmt: 'assert' test [',' test] [given_clause]
-   given_clause: "given" (NAME '=' test)* ":" suite
+   given_clause: "given" [(NAME '=' test)+ "in"]":" suite
 
 (Note that ``expr_stmt`` in the grammar is a slight misnomer, as it covers
 assignment and augmented assignment in addition to simple expression
@@ -207,7 +214,7 @@
    flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt | yield_stmt
 
 In addition to the above changes, the definition of ``atom`` would be changed
-to also allow ``"." NAME``. The restriction of this usage to statements with
+to also allow ``?``. The restriction of this usage to statements with
 an associated ``given`` clause would be handled by a later stage of the
 compilation process (likely AST construction, which already enforces
 other restrictions where the grammar is overly permissive in order to
@@ -277,13 +284,14 @@
 However, while they are the initial motivating use case, limiting this
 feature solely to simple assignments would be overly restrictive. Once the
 feature is defined at all, it would be quite arbitrary to prevent its use
-for augmented assignments, return statements, yield expressions and
-arbitrary expressions that may modify the application state.
+for augmented assignments, return statements, yield expressions,
+comprehensions and arbitrary expressions that may modify the
+application state.
 
 The ``given`` clause may also function as a more readable
 alternative to some uses of lambda expressions and similar
 constructs when passing one-off functions to operations
-like ``sorted()``.
+like ``sorted()`` or in callback based event-driven programming.
 
 In module and class level code, the ``given`` clause will serve as a
 clear and reliable replacement for usage of the ``del`` statement to keep
@@ -350,7 +358,7 @@
 
     # would be equivalent to
 
-    seq2 = .result given seq=seq:
+    seq2 = ?.result given seq=seq:
         result = []
         for y in seq:
             if p(y):
@@ -367,7 +375,7 @@
 provide a precisely equivalent expansion for a generator expression. The
 closest it can get is to define an additional level of scoping::
 
-    seq2 = .g(seq) given:
+    seq2 = ?.g(seq) given:
         def g(seq):
             for y in seq:
                 if p(y):
@@ -375,6 +383,22 @@
                         if q(x):
                             yield x
 
+This limitation could be remedied by permitting the given clause to be
+a generator function, in which case ? would refer to a generator-iterator
+object rather than a simple namespace::
+
+    seq2 = ? given seq=seq in:
+        for y in seq:
+            if p(y):
+                for x in y:
+                    if q(x):
+                        yield x
+
+However, this would make the meaning of "?" quite ambiguous, even more so
+than is already the case for the meaning of ``def`` statements (which will
+usually have a docstring indicating whether or not a function definition is
+actually a generator)
+
 Explaining Decorator Clause Evaluation and Application
 ------------------------------------------------------
 
@@ -477,14 +501,19 @@
 I believe the proposal in this PEP would finally let Python get close to the
 "executable pseudocode" bar for the kind of thought expressed above::
 
-   sorted_list = sorted(original, key=.sort_key) given:
-       def sort_key(item):
+   sorted_list = sorted(original, key=?.key) given:
+       def key(item):
            return item.attr1, item.attr2
 
-Everything is in the same order as it was in the user's original thought, the
-only addition they have to make is to give the sorting criteria a name so that
-the usage can be linked up to the subsequent definition.
-   
+Everything is in the same order as it was in the user's original thought, and
+they don't even need to come up with a name for the sorting criteria: it is
+possible to reuse the keyword argument name directly.
+
+A possible enhancement to those proposal would be to provide a convenient
+shorthand syntax to say "use the given clause contents as keyword
+arguments". Even without dedicated syntax, that can be written simply as
+``**vars(?)``.
+
 
 Harmful to Introspection
 ~~~~~~~~~~~~~~~~~~~~~~~~
@@ -516,7 +545,7 @@
 This is more of a deficiency in the PEP rather than the idea, though. If
 it wasn't a real world problem, we wouldn't get so many complaints about
 the lack of multi-line lambda support and Ruby's block construct
-probaly wouldn't be quite so popular.
+probably wouldn't be quite so popular.
 
 
 Open Questions
@@ -525,9 +554,12 @@
 Syntax for Forward References
 -----------------------------
 
-The leading ``.`` arguably fails the "syntax shall not look like grit on
-Uncle Tim's monitor" test. However, it does have the advantages of being
-easy to type and already having an association with namespaces.
+The ``?`` symbol is proposed for forward references to the given namespace
+as it is short, currently unused and suggests "there's something missing
+here that will be filled in later".
+
+The proposal in the PEP doesn't neatly parallel any existing Python feature,
+so reusing an already used symbol has been deliberately avoided.
 
 
 Handling of ``nonlocal`` and ``global``
@@ -541,8 +573,8 @@
 functions were defined as in the expansion above.
 
 
-Detailed Semantics #3: Handling of ``break`` and ``continue``
--------------------------------------------------------------
+Handling of ``break`` and ``continue``
+--------------------------------------
 
 ``break`` and ``continue`` will operate as if the anonymous functions were
 defined as in the expansion above. They will be syntax errors if they occur
@@ -561,6 +593,25 @@
 Examples
 ========
 
+Defining callbacks for event driven programming::
+
+  # Current Python (definition before use)
+  def cb(sock):
+      # Do something with socket
+  def eb(exc):
+      logging.exception(
+          "Failed connecting to %s:%s", host, port)
+  loop.create_connection((host, port), cb, eb) given:
+
+  # Becomes:
+  loop.create_connection((host, port), ?.cb, ?.eb) given:
+      def cb(sock):
+          # Do something with socket
+      def eb(exc):
+          logging.exception(
+              "Failed connecting to %s:%s", host, port)
+
+
 Defining "one-off" classes which typically only have a single instance::
 
   # Current Python (instantiation after definition)
@@ -579,7 +630,7 @@
     ... # However many lines
 
   # Becomes:
-  public_name = .MeaningfulClassName(*params) given:
+  public_name = ?.MeaningfulClassName(*params) given:
     class MeaningfulClassName():
       ... # Should trawl the stdlib for an example of doing this
 
@@ -593,7 +644,7 @@
   del _createenviron
 
   # Becomes:
-  environ = ._createenviron() given:
+  environ = ?._createenviron() given:
       def _createenviron():
         ... # 27 line function
 
@@ -606,7 +657,7 @@
   return decorating_function
 
   # Becomes:
-  return .decorating_function given:
+  return ?.decorating_function given:
     # Cell variables rather than locals, but should give similar speedup
     tuple, sorted, len, KeyError = tuple, sorted, len, KeyError
     def decorating_function(user_function):
@@ -701,6 +752,9 @@
 .. [9] Possible PEP 3150 style guidelines (#2):
    http://mail.python.org/pipermail/python-ideas/2011-October/012341.html
 
+.. [10] Multi-line lambdas (again!)
+   http://mail.python.org/pipermail/python-ideas/2013-August/022526.html
+
 Copyright
 =========
 

-- 
Repository URL: http://hg.python.org/peps


More information about the Python-checkins mailing list