[Python-checkins] peps: Updated PEP 335, posted 25-Oct-2011.

guido.van.rossum python-checkins at python.org
Tue Oct 25 23:36:37 CEST 2011


http://hg.python.org/peps/rev/e197b2e8e14c
changeset:   3971:e197b2e8e14c
user:        Guido van Rossum <guido at google.com>
date:        Tue Oct 25 14:36:29 2011 -0700
summary:
  Updated PEP 335, posted 25-Oct-2011.

files:
  pep-0335.txt |  388 +++++++++++++++++++-------------------
  1 files changed, 198 insertions(+), 190 deletions(-)


diff --git a/pep-0335.txt b/pep-0335.txt
--- a/pep-0335.txt
+++ b/pep-0335.txt
@@ -2,13 +2,13 @@
 Title: Overloadable Boolean Operators
 Version: $Revision$
 Last-Modified: $Date$
-Author: Gregory Ewing <greg.ewing at canterbury.ac.nz>
+Author: Gregory Ewing <greg at cosc.canterbury.ac.nz>
 Status: Draft
 Type: Standards Track
 Content-Type: text/x-rst
 Created: 29-Aug-2004
 Python-Version: 3.3
-Post-History: 05-Sep-2004, 30-Sep-2011
+Post-History: 05-Sep-2004, 30-Sep-2011, 25-Oct-2011
 
 
 Abstract
@@ -66,13 +66,23 @@
 
 A workaround often suggested is to use the bitwise operators '&', '|'
 and '~' in place of 'and', 'or' and 'not', but this has some
-drawbacks.  The precedence of these is different in relation to the
-other operators, and they may already be in use for other purposes (as
-in example 1).  There is also the aesthetic consideration of forcing
-users to use something other than the most obvious syntax for what
-they are trying to express.  This would be particularly acute in the
-case of example 3, considering that boolean operations are a staple of
-SQL queries.
+drawbacks:
+
+* The precedence of these is different in relation to the other operators,
+  and they may already be in use for other purposes (as in example 1).
+
+* It is aesthetically displeasing to force users to use something other
+  than the most obvious syntax for what they are trying to express.  This
+  would be particularly acute in the case of example 3, considering that
+  boolean operations are a staple of SQL queries.
+
+* Bitwise operators do not provide a solution to the problem of
+  chained comparisons such as 'a < b < c' which involve an implicit
+  'and' operation. Such expressions currently cannot be used at all
+  on data types such as NumPy arrays where the result of a comparison
+  cannot be treated as having normal boolean semantics; they must be
+  expanded into something like (a < b) & (b < c), losing a considerable
+  amount of clarity.
 
 
 Rationale
@@ -208,7 +218,7 @@
     PyObject *PyObject_LogicalAnd1(PyObject *);
     PyObject *PyObject_LogicalOr1(PyObject *);
     PyObject *PyObject_LogicalAnd2(PyObject *, PyObject *);
-
+    PyObject *PyObject_LogicalOr2(PyObject *, PyObject *);
 
 
 Alternatives and Optimisations
@@ -242,40 +252,40 @@
 
 ::
 
-     if a and b:
-         statement1
-     else:
-         statement2
+    if a and b:
+        statement1
+    else:
+        statement2
 
 generates
 
 ::
 
-         LOAD_GLOBAL         a
-         POP_JUMP_IF_FALSE   false_branch
-         LOAD_GLOBAL         b
-         POP_JUMP_IF_FALSE   false_branch
-         <code for statement1>
-         JUMP_FORWARD        end_branch
-     false_branch:
-         <code for statement2>
-     end_branch:
+        LOAD_GLOBAL         a
+        POP_JUMP_IF_FALSE   false_branch
+        LOAD_GLOBAL         b
+        POP_JUMP_IF_FALSE   false_branch
+        <code for statement1>
+        JUMP_FORWARD        end_branch
+    false_branch:
+        <code for statement2>
+    end_branch:
 
 Under this proposal as described so far, it would become something like
 
 ::
 
-         LOAD_GLOBAL         a
-         LOGICAL_AND_1       test
-         LOAD_GLOBAL         b
-         LOGICAL_AND_2
-     test:
-         POP_JUMP_IF_FALSE   false_branch
-         <code for statement1>
-         JUMP_FORWARD        end_branch
-     false_branch:
-         <code for statement2>
-     end_branch:
+        LOAD_GLOBAL         a
+        LOGICAL_AND_1       test
+        LOAD_GLOBAL         b
+        LOGICAL_AND_2
+    test:
+        POP_JUMP_IF_FALSE   false_branch
+        <code for statement1>
+        JUMP_FORWARD        end_branch
+    false_branch:
+        <code for statement2>
+    end_branch:
 
 This involves executing one extra bytecode in the short-circuiting
 case and two extra bytecodes in the non-short-circuiting case.
@@ -286,16 +296,16 @@
 
 ::
 
-         LOAD_GLOBAL         a
-         AND1_JUMP           true_branch, false_branch
-         LOAD_GLOBAL         b
-         AND2_JUMP_IF_FALSE  false_branch
-     true_branch:
-         <code for statement1>
-         JUMP_FORWARD        end_branch
-     false_branch:
-         <code for statement2>
-     end_branch:
+        LOAD_GLOBAL         a
+        AND1_JUMP           true_branch, false_branch
+        LOAD_GLOBAL         b
+        AND2_JUMP_IF_FALSE  false_branch
+    true_branch:
+        <code for statement1>
+        JUMP_FORWARD        end_branch
+    false_branch:
+        <code for statement2>
+    end_branch:
 
 Here, AND1_JUMP performs phase 1 processing as above,
 and then examines the result. If there is a result, it is popped
@@ -350,58 +360,58 @@
 
 ::
 
-     #-----------------------------------------------------------------
-     #
-     #   This example creates a subclass of numpy array to which
-     #   'and', 'or' and 'not' can be applied, producing an array
-     #   of booleans.
-     #
-     #-----------------------------------------------------------------
-
-     from numpy import array, ndarray
-
-     class BArray(ndarray):
-
-         def __str__(self):
-             return "barray(%s)" % ndarray.__str__(self)
-
-         def __and2__(self, other):
-             return self & other
-
-         def __or2__(self, other):
-             return self & other
-
-         def __not__(self):
-             return self == 0
-
-     def barray(*args, **kwds):
-         return array(*args, **kwds).view(type=BArray)
-
-     a0 = barray([0, 1, 2, 4])
-     a1 = barray([1, 2, 3, 4])
-     a2 = barray([5, 6, 3, 4])
-     a3 = barray([5, 1, 2, 4])
-
-     print("a0:", a0)
-     print("a1:", a1)
-     print("a2:", a2)
-     print("a3:", a3)
-     print("not a0:", not a0)
-     print("a0 == a1 and a2 == a3:", a0 == a1 and a2 == a3)
-     print("a0 == a1 or a2 == a3:", a0 == a1 or a2 == a3)
+    #-----------------------------------------------------------------
+    #
+    #   This example creates a subclass of numpy array to which
+    #   'and', 'or' and 'not' can be applied, producing an array
+    #   of booleans.
+    #
+    #-----------------------------------------------------------------
+    
+    from numpy import array, ndarray
+    
+    class BArray(ndarray):
+    
+        def __str__(self):
+            return "barray(%s)" % ndarray.__str__(self)
+    
+        def __and2__(self, other):
+            return (self & other)
+    
+        def __or2__(self, other):
+            return (self & other)
+    
+        def __not__(self):
+            return (self == 0)
+    
+    def barray(*args, **kwds):
+        return array(*args, **kwds).view(type = BArray)
+    
+    a0 = barray([0, 1, 2, 4])
+    a1 = barray([1, 2, 3, 4])
+    a2 = barray([5, 6, 3, 4])
+    a3 = barray([5, 1, 2, 4])
+    
+    print "a0:", a0
+    print "a1:", a1
+    print "a2:", a2
+    print "a3:", a3
+    print "not a0:", not a0
+    print "a0 == a1 and a2 == a3:", a0 == a1 and a2 == a3
+    print "a0 == a1 or a2 == a3:", a0 == a1 or a2 == a3
 
 Example 1 Output
 ----------------
 
 ::
 
-     a0: barray([0 1 2 4])
-     a1: barray([1 2 3 4])
-     a2: barray([5 6 3 4])
-     a3: barray([5 1 2 4])
-     not a0: barray([ True False False False])
-     a0 == a1 and a2 == a3: barray([False False False  True])
-     a0 == a1 or a2 == a3: barray([False False False  True])
+    a0: barray([0 1 2 4])
+    a1: barray([1 2 3 4])
+    a2: barray([5 6 3 4])
+    a3: barray([5 1 2 4])
+    not a0: barray([ True False False False])
+    a0 == a1 and a2 == a3: barray([False False False  True])
+    a0 == a1 or a2 == a3: barray([False False False  True])
 
 
 Example 2: Database Queries
@@ -409,112 +419,110 @@
 
 ::
 
-     #-----------------------------------------------------------------
-     #
-     #   This example demonstrates the creation of a DSL for database
-     #   queries allowing 'and' and 'or' operators to be used to
-     #   formulate the query.
-     #
-     #-----------------------------------------------------------------
-
-     class SQLNode:
-
-         def __and2__(self, other):
-             return SQLBinop("and", self, other)
-
-         def __rand2__(self, other):
-             return SQLBinop("and", other, self)
-
-         def __eq__(self, other):
-             return SQLBinop("=", self, other)
-
-
-     class Table(SQLNode):
-
-         def __init__(self, name):
-             self.__tablename__ = name
-
-         def __getattr__(self, name):
-             return SQLAttr(self, name)
-
-         def __sql__(self):
-             return self.__tablename__
-
-
-     class SQLBinop(SQLNode):
-
-         def __init__(self, op, opnd1, opnd2):
-             self.op = op.upper()
-             self.opnd1 = opnd1
-             self.opnd2 = opnd2
-
-         def __sql__(self):
-             return "(%s %s %s)" % (sql(self.opnd1), self.op, sql(self.opnd2))
-
-
-     class SQLAttr(SQLNode):
-
-         def __init__(self, table, name):
-             self.table = table
-             self.name = name
-
-         def __sql__(self):
-             return "%s.%s" % (sql(self.table), self.name)
-
-
-     class SQLSelect(SQLNode):
-
-         def __init__(self, targets):
-             self.targets = targets
-             self.where_clause = None
-
-         def where(self, expr):
-             self.where_clause = expr
-             return self
-
-         def __sql__(self):
-             result = "SELECT %s" % ", ".join(sql(target) for target in self.targets)
-             if self.where_clause:
-                 result = "%s WHERE %s" % (result, sql(self.where_clause))
-             return result
-
-
-     def sql(expr):
-         if isinstance(expr, SQLNode):
-             return expr.__sql__()
-         elif isinstance(expr, str):
-             return "'%s'" % expr.replace("'", "''")
-         else:
-             return str(expr)
-
-
-     def select(*targets):
-         return SQLSelect(targets)
-
-
-#--------------------------------------------------------------------------------
-
-::
-     dishes = Table("dishes")
-     customers = Table("customers")
-     orders = Table("orders")
-
-     query = select(customers.name, dishes.price, orders.amount).where(
-         customers.cust_id == orders.cust_id and orders.dish_id == dishes.dish_id
-         and dishes.name == "Spam, Eggs, Sausages and Spam")
-
-     print(repr(query))
-     print(sql(query))
+    #-----------------------------------------------------------------
+    #
+    #   This example demonstrates the creation of a DSL for database
+    #   queries allowing 'and' and 'or' operators to be used to
+    #   formulate the query.
+    #
+    #-----------------------------------------------------------------
+    
+    class SQLNode(object):
+        
+        def __and2__(self, other):
+            return SQLBinop("and", self, other)
+    
+        def __rand2__(self, other):
+            return SQLBinop("and", other, self)
+    
+        def __eq__(self, other):
+            return SQLBinop("=", self, other)
+    
+    
+    class Table(SQLNode):
+    
+        def __init__(self, name):
+            self.__tablename__ = name
+            
+        def __getattr__(self, name):
+            return SQLAttr(self, name)
+        
+        def __sql__(self):
+            return self.__tablename__
+    
+    
+    class SQLBinop(SQLNode):
+    
+        def __init__(self, op, opnd1, opnd2):
+            self.op = op.upper()
+            self.opnd1 = opnd1
+            self.opnd2 = opnd2
+    
+        def __sql__(self):
+            return "(%s %s %s)" % (sql(self.opnd1), self.op, sql(self.opnd2))
+    
+    
+    class SQLAttr(SQLNode):
+    
+        def __init__(self, table, name):
+            self.table = table
+            self.name = name
+        
+        def __sql__(self):
+            return "%s.%s" % (sql(self.table), self.name)
+    
+    
+    class SQLSelect(SQLNode):
+    
+        def __init__(self, targets):
+            self.targets = targets
+            self.where_clause = None
+    
+        def where(self, expr):
+            self.where_clause = expr
+            return self
+        
+        def __sql__(self):
+            result = "SELECT %s" % ", ".join([sql(target) for target in self.targets])
+            if self.where_clause:
+                result = "%s WHERE %s" % (result, sql(self.where_clause))
+            return result
+    
+    
+    def sql(expr):
+        if isinstance(expr, SQLNode):
+            return expr.__sql__()
+        elif isinstance(expr, str):
+            return "'%s'" % expr.replace("'", "''")
+        else:
+            return str(expr)
+    
+    
+    def select(*targets):
+        return SQLSelect(targets)
+    
+    #-----------------------------------------------------------------
+    
+    dishes = Table("dishes")
+    customers = Table("customers")
+    orders = Table("orders")
+    
+    query = select(customers.name, dishes.price, orders.amount).where(
+        customers.cust_id == orders.cust_id and orders.dish_id == dishes.dish_id
+        and dishes.name == "Spam, Eggs, Sausages and Spam")
+    
+    print repr(query)
+    print sql(query)
 
 Example 2 Output
 ----------------
 
 ::
 
-     <__main__.SQLSelect object at 0x1cc830>
-     SELECT customers.name, dishes.price, orders.amount WHERE
-     (((customers.cust_id = orders.cust_id) AND (orders.dish_id =
-     dishes.dish_id)) AND (dishes.name = 'Spam, Eggs, Sausages and Spam'))
+    <__main__.SQLSelect object at 0x1cc830>
+    SELECT customers.name, dishes.price, orders.amount WHERE
+    (((customers.cust_id = orders.cust_id) AND (orders.dish_id =
+    dishes.dish_id)) AND (dishes.name = 'Spam, Eggs, Sausages and Spam'))
 
 
 Copyright

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


More information about the Python-checkins mailing list