[Baypiggies] overriding boolean and,or operators?

Alex Martelli aleax at google.com
Tue Jul 13 00:55:38 CEST 2010


`and` and `or` cannot be overridden; they always perform their
short-circuit evaluation functionality, no matter what the types on
either side.  I understand your surprise, because you think of them as
operator, but they're like other keywords such as `lambda`, `if`,
`else`... they **control what gets executed, when, and whether the
execution happens at all in a certain circumstance**.  Consider:

>>> dis.dis(compile('x & y', 'eval', 'eval'))
  1           0 LOAD_NAME                0 (x)
              3 LOAD_NAME                1 (y)
              6 BINARY_AND
              7 RETURN_VALUE

THIS is the semantics of an actual operator: BOTH operands get
evaluated (here, just a LOAD_NAME for each), THEN the operator's code
gets control (and can be overridden).  Vs:

>>> dis.dis(compile('x and y', 'eval', 'eval'))
  1           0 LOAD_NAME                0 (x)
              3 JUMP_IF_FALSE            4 (to 10)
              6 POP_TOP
              7 LOAD_NAME                1 (y)
        >>   10 RETURN_VALUE

as you see, in bytecode terms, 'and' means JUMP_IF_FALSE -- **no**
Python-level code (potentially written by the user in an override)
ever executes as part of this "SO-CALLED" operator -- which isn't
really one, deep down: it's a *control structure*, like e.g.
if/else... which ALSO cannot be overridden of course:

>>> dis.dis(compile('x if y else z', 'eval', 'eval'))
  1           0 LOAD_NAME                0 (y)
              3 JUMP_IF_FALSE            5 (to 11)
              6 POP_TOP
              7 LOAD_NAME                1 (x)
             10 RETURN_VALUE
        >>   11 POP_TOP
             12 LOAD_NAME                2 (z)
             15 RETURN_VALUE

Note the extreme similarity of this bytecode to that of the 'and'
so-called "operator" -- 'and' is simpler, of course, but very much
akin in semantics and implementation.

You cannot override 'and' and 'or' just like you cannot override
'if/else' or 'lambda'.


Alex


On Mon, Jul 12, 2010 at 3:01 PM, Stephen Lacy <slacy at slacy.com> wrote:
> Ah, that Infix example is really cute, but not exactly what I was hoping
> for.
>
> I'm actually playing with a bit of trickery -- the __eq__() operator doesn't
> need to return a boolean type (like I think __bool__() does). It can return
> any object.  You can use this trick to make __eq__() into a factory method
> and have it return an object that *represents* the comparison without
> actually *doing* the comparison.  This is useful for things like ORM
> mappers, where you take the Python expression, traverse the expression tree,
> translate it into SQL, and then execute it.  I'm basing my ideas on the
> implementation of Column comparators in SQLAlchemy, which you can see some
> examples of here:
> http://www.sqlalchemy.org/docs/sqlexpression.html#operators  But I'm not
> working with SQL, I'm trying to do this for another query language.
>
> I'm having trouble expressing "and" and "or" in a nice Pythonic way, and if
> you look at the SQLAlchemy source, they use and_() and or_() methods, which
> I'd like to try to avoid. I was hoping for some trick, akin to the Infix
> thing you mentioned, but that would be a little more pythonic.  (And, I'm
> surprised that you can override pretty much everything except for 'and' and
> 'or')
>
> Here's a code example I wrote to get the juices flowing:
>
> http://dpaste.com/217476/
>
> Line 60 is where things get interesting, I have to use bitwise "and" instead
> of boolean and, because as far as I can tell, there's no override for
> boolean and....
>
> Steve
>
> On Mon, Jul 12, 2010 at 2:14 PM, Brent Pedersen <bpederse at gmail.com> wrote:
>>
>> On Mon, Jul 12, 2010 at 11:21 AM, Stephen Lacy <slacy at slacy.com> wrote:
>> > Hi,
>> >
>> > According to http://docs.python.org/library/operator.html boolean
>> > operators
>> > ==, <, >, etc. can be overridden via __eq__(), __lt__(), __gt__(), etc.
>> >
>> > They also mention *bitwise* and/or operators via __and__() and __or__().
>> >
>> > But, I'd like to override the *boolean* operators 'and' and 'or'.  Is
>> > this
>> > possible?
>> >
>> > Background:
>> >
>> > I'm experimenting with a library that takes a python expression like
>> > this:
>> >
>> > "(a == b) or (c and d)"
>> >
>> > And instead of evaluating it via the interpreter, creates (and returns)
>> > a
>> > representation of said boolean decision tree such that it can be
>> > evaluated
>> > dynamically and/or converted to some other form, like prefix or postfix
>> > (this is just an example and for my own exploration and deeper
>> > understanding
>> > of operator overrides).
>> >
>> > I can get this to work if I use the syntax "(a == b) | (c & d)" but I
>> > would
>> > prefer to use the more pythonic and syntactically correct "and" and
>> > "or".
>> > Is this possible?
>> >
>> > Steve
>> >
>> > _______________________________________________
>> > Baypiggies mailing list
>> > Baypiggies at python.org
>> > To change your subscription options or unsubscribe:
>> > http://mail.python.org/mailman/listinfo/baypiggies
>> >
>>
>> not quite sure i follow your use-case, but...
>> you can also override __nonzero__ which i think is what gets called
>> when you use bool(),
>> but you'll probably still need a bit more, you can add some sugar using
>> this:
>> http://code.activestate.com/recipes/384122-infix-operators/
>>
>> so you'd have your classes implement __bool_or__ (or whatever you want
>> to call it) and then use:
>>
>> OR = Infix(lambda a, b: a.__bool_or__(b))
>>
>> MyClass(22) |OR| MyClass(0)
>>
>> where MyClass implements __bool_or__
>>
>> -brent
>
>
> _______________________________________________
> Baypiggies mailing list
> Baypiggies at python.org
> To change your subscription options or unsubscribe:
> http://mail.python.org/mailman/listinfo/baypiggies
>


More information about the Baypiggies mailing list