[Python-Dev] ANN: PEP 335: Overloadable Boolean Operators

Robert Brewer fumanchu at amor.org
Tue Sep 14 22:41:57 CEST 2004


Phillip J. Eby wrote:
> At 11:39 AM 9/14/04 -0700, Robert Brewer wrote:
> >We already have a de facto "code literal syntax": lambdas.
> >
> >db.query(lambda x: x.y==z and foo*bar<27)
> 
> Right, but that requires non-portable bytecode disassembly.  
> If there was a simple way to convert from a function object
> to an AST, I'd be happy with that too.

If it were fast enough, I would too.

> > > But, even if PEP 335 *were* implemented, creating a query
> > > system using Python expressions would *still* be kludgy,
> > > because you still need "seed variables" in the current
> > > scope to write a query expression.
> > > In my example above, I didn't need to bind 'x' or 'y'
> > > or 'z' or 'foo' or 'bar', because the db.query() method
> > > is going to interpret those in some context.  If I
> > > were using a PEP 335-based query system, I'd have to
> > > initialize those variables to special querying objects first.
> >
> >A lot of that becomes a non-issue if you bind early. Once 
> the constants
> >are bound, you're left with attribute access on your core 
> objects (x.y)
> >and special functions (see logic.ieq or logic.today for 
> example). Again,
> >too, I can use the lambda to evaluate Python objects, the 
> 'Object' side
> >of "ORM". In that situation, the binding is a benefit.
> 
> I'm not following what you mean by "bind early".  My point 
> was that in 
> order to have bindings for seeds like 'x' and 'z' and 'foo', 
> most query 
> languages end up with hacks like 'tables.tablename.columname' or 
> '_.table.column' or other rigamarole, and that this is 
> usually more awkward 
> to deal with than the &/|/~ operator spelling.

Dejavu addresses that by separating the "table binding" from the
expression. That is, given:

z = "Hansel"
e = logic.Expression(lambda x: x.Name.startswith(z))
books = recall(myapp.Book, e)
authors = recall(myapp.Author, e)

...'x' isn't bound within the Expression declaration; it is supplied as
the first param to recall(). For example, you could apply the same
Expression to both a Book class/table and an Author class/table within
the same application, as above. IMO, this is a natural way to map the
lambda-calculus to a query language, where the bound variable =
ORM-object instances (a "table row"). But any free variables need to be
resolved ASAP; therefore, z gets evaluated completely and immediately;
Expression() rewrites the lambda co_code, replacing the closure lookup
with a LOAD_CONST (sticking the value of z into co_consts).

> > > That's why I say that an AST literal syntax would be much
> > > more useful to me than PEP 335 for this type of use case.
> >
> >I seem to recall my AST version was quite slow, in pure Python. Can't
> >recall whether that was all the tuple-unpacking or just my naive
> >function-call overhead at the time.
> 
> When I say AST, I just mean "some kind of syntax representation", not 
> necessarily the 'parser' module's current AST implementation.

Sure.

> However, I have found that it's possible to translate parser-module 
> AST's to query specifications quite efficiently in pure Python,
> such that the overhead is minor compared to whatever actual
> computation you're doing...

Hmm, perhaps I'll look again.

> >Anyway, for those reasons, I'm -0.5.
> 
> On what?  AST literals, or PEP 335?

The PEP. ASTs would be better. A builtin early-binder would make me
happiest, but I won't hold my breath. I don't think it would require new
syntax, either, just something like codewalk.EarlyBinder() and
.LambdaDecompiler() in a standard lib module somewhere. But I may go
back and look at ASTs again.


Robert Brewer
MIS
Amor Ministries
fumanchu at amor.org


More information about the Python-Dev mailing list