Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #26923 > unrolled thread

Arithmetic with Boolean values

Started byJohn Ladasky <john_ladasky@sbcglobal.net>
First post2012-08-11 15:30 -0700
Last post2012-08-14 18:32 +0200
Articles 17 — 13 participants

Back to article view | Back to comp.lang.python


Contents

  Arithmetic with Boolean values John Ladasky <john_ladasky@sbcglobal.net> - 2012-08-11 15:30 -0700
    Re: Arithmetic with Boolean values Chris Angelico <rosuav@gmail.com> - 2012-08-12 09:13 +1000
    Re: Arithmetic with Boolean values Chris Rebert <clp2@rebertia.com> - 2012-08-11 16:53 -0700
    Re: Arithmetic with Boolean values Terry Reedy <tjreedy@udel.edu> - 2012-08-11 20:25 -0400
    Re: Arithmetic with Boolean values Chris Angelico <rosuav@gmail.com> - 2012-08-12 10:31 +1000
    Re: Arithmetic with Boolean values MRAB <python@mrabarnett.plus.com> - 2012-08-12 01:36 +0100
    Re: Arithmetic with Boolean values Paul Rubin <no.email@nospam.invalid> - 2012-08-11 17:54 -0700
      Re: Arithmetic with Boolean values Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2012-08-12 11:22 +0000
        Re: Arithmetic with Boolean values Roy Smith <roy@panix.com> - 2012-08-12 07:40 -0400
          Re: Arithmetic with Boolean values Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2012-08-12 14:06 +0000
            Re: Arithmetic with Boolean values Paul Rubin <no.email@nospam.invalid> - 2012-08-12 09:59 -0700
              Re: Arithmetic with Boolean values Bernd Nawothnig <Bernd.Nawothnig@t-online.de> - 2012-08-12 19:21 +0200
              Re: Arithmetic with Boolean values Mark Lawrence <breamoreboy@yahoo.co.uk> - 2012-08-12 19:20 +0100
                Re: Arithmetic with Boolean values Roy Smith <roy@panix.com> - 2012-08-12 14:45 -0400
                Re: Arithmetic with Boolean values Alister <alister.ware@ntlworld.com> - 2012-08-12 20:13 +0000
                  Re: Arithmetic with Boolean values Gene Heskett <gheskett@wdtv.com> - 2012-08-12 20:29 -0400
                  Re: Arithmetic with Boolean values Hans Mulder <hansmu@xs4all.nl> - 2012-08-14 18:32 +0200

#26923 — Arithmetic with Boolean values

FromJohn Ladasky <john_ladasky@sbcglobal.net>
Date2012-08-11 15:30 -0700
SubjectArithmetic with Boolean values
Message-ID<58f60e60-1dc1-4265-a601-693d11b4bcec@googlegroups.com>
I have gotten used to switching back and forth between Boolean algebra and numerical values.  Python generally makes this quite easy.  I just found a case that surprises me.

Here is what I want to accomplish:  I want to process a list.  If the length of the list L is odd, I want to process it once.  If len(L) is even, I want to process it twice.  I thought I would set up a loop as follows:

for x in range(1 + not(len(L) % 2)):
    # Do stuff

This provoked a SyntaxError.  I investigated this further with my interpreter (ipython).

In [1]: L = range(5)

In [2]: L
Out[2]: [0, 1, 2, 3, 4]

In [3]: len(L)
Out[3]: 5

In [4]: len(L) % 2
Out[4]: 1

In [5]: not(1)
Out[5]: False

In [6]: not(len(L) % 2)
Out[6]: False

In [7]: 1 + not(len(L) % 2)
------------------------------------------------------------
   File "<ipython console>", line 1
     1 + not(len(L) % 2)
           ^
SyntaxError: invalid syntax

So as you can see, every thing is working fine until I attempt to add 1 and False.  However:

In [8]: 0 == False
Out[8]: True

In [9]: 1 == True
Out[9]: True

So, 0 and False do pass an equivalency test, as do 1 and True.  Furthermore:

In [10]: 1 + (len(L) % 2 == 0)
Out[10]: 1

Why is using a logical "not" function, as shown in [7], returning a different result than the test for equivalency as shown in [10]?

Of course I'm just going to use [10] in my program, but I'd like to understand the reason that I'm getting that SyntaxError.  I've been reading Python style guides, and at least one of them states a preference for using the "not" syntax over the "== 0" syntax.

I'm using Python 2.7, in case it matters.

[toc] | [next] | [standalone]


#26926

FromChris Angelico <rosuav@gmail.com>
Date2012-08-12 09:13 +1000
Message-ID<mailman.3198.1344726798.4697.python-list@python.org>
In reply to#26923
On Sun, Aug 12, 2012 at 8:30 AM, John Ladasky
<john_ladasky@sbcglobal.net> wrote:
> In [7]: 1 + not(len(L) % 2)
> ------------------------------------------------------------
>    File "<ipython console>", line 1
>      1 + not(len(L) % 2)
>            ^
> SyntaxError: invalid syntax

This appears to be a limitation of the parser; it's trying to
interpret "not" as a binary operator.

1 + (not(len(L) % 2))

Works just fine with parentheses to enforce the correct interpretation.

This also works in Python 3.2, fwiw (except that you need
list(range(5)) to create the sample list).

ChrisA

[toc] | [prev] | [next] | [standalone]


#26927

FromChris Rebert <clp2@rebertia.com>
Date2012-08-11 16:53 -0700
Message-ID<mailman.3199.1344729188.4697.python-list@python.org>
In reply to#26923
On Sat, Aug 11, 2012 at 3:30 PM, John Ladasky
<john_ladasky@sbcglobal.net> wrote:
<snip>
> for x in range(1 + not(len(L) % 2)):
>     # Do stuff
>
> This provoked a SyntaxError.  I investigated this further with my interpreter (ipython).
<snip>
> In [5]: not(1)
> Out[5]: False
>
> In [6]: not(len(L) % 2)
> Out[6]: False
>
> In [7]: 1 + not(len(L) % 2)
> ------------------------------------------------------------
>    File "<ipython console>", line 1
>      1 + not(len(L) % 2)
>            ^
> SyntaxError: invalid syntax
<snip>
> Why is using a logical "not" function, as shown in [7], returning a different result than the test for equivalency as shown in [10]?

Note that, in Python, `not` is an unary operator (it's a language
keyword in fact), as opposed to a function:
Python 2.7.2 (default, Jun 20 2012, 16:23:33)
>>> len("abc")
3
>>> # functions are first-class entities in Python, so we can reference them
>>> len
<built-in function len>
>>> not(1)
False
>>> # but `not` isn't a function
>>> not
  File "<stdin>", line 1
    not
      ^
SyntaxError: invalid syntax
>>> # hence why we don't need to call it
>>> not 1
False

The parentheses in `not(foo)` are just grouping the `foo`
subexpression; they're not indicating a function call. Therefore, in
idiomatic Python, such parentheses are omitted whenever possible
(which is the majority of the time), and when they are absolutely
necessary, a space is included before the opening paren, because we're
not making a function call.

Thus, you're simply running into an operator precedence issue, which,
as Chris A. explained, can be remedied by adding grouping parens
around the entire `not` expression; e.g. `(not foo)`

Cheers,
Chris R.

[toc] | [prev] | [next] | [standalone]


#26929

FromTerry Reedy <tjreedy@udel.edu>
Date2012-08-11 20:25 -0400
Message-ID<mailman.3200.1344731198.4697.python-list@python.org>
In reply to#26923
On 8/11/2012 7:13 PM, Chris Angelico wrote:
> On Sun, Aug 12, 2012 at 8:30 AM, John Ladasky
> <john_ladasky@sbcglobal.net> wrote:
>> In [7]: 1 + not(len(L) % 2)
>> ------------------------------------------------------------
>>     File "<ipython console>", line 1
>>       1 + not(len(L) % 2)
>>             ^
>> SyntaxError: invalid syntax
>
> This appears to be a limitation of the parser; it's trying to
> interpret "not" as a binary operator.

I think not. It is lower precedence than all arithmetic operators. The 
following is worth knowing about and occasionally reviewing.
http://docs.python.org/py3k/reference/expressions.html#summary

() around % is not needed; not len(L) % 2 works same. So parser sees

1 + not len(L) % 2

with + given higher precedence than not, So it parses as (1 + not) and 
croaks, as indicated by caret. (We humans see that that is impossible 
and may boost the precedence in context.)

> 1 + (not(len(L) % 2))

== 1 + (not len(L) % 2)
>
> Works just fine with parentheses to enforce the correct interpretation.
>
> This also works in Python 3.2, fwiw (except that you need
> list(range(5)) to create the sample list).

-- 
Terry Jan Reedy

[toc] | [prev] | [next] | [standalone]


#26930

FromChris Angelico <rosuav@gmail.com>
Date2012-08-12 10:31 +1000
Message-ID<mailman.3201.1344731485.4697.python-list@python.org>
In reply to#26923
On Sun, Aug 12, 2012 at 10:25 AM, Terry Reedy <tjreedy@udel.edu> wrote:
> On 8/11/2012 7:13 PM, Chris Angelico wrote:
>> This appears to be a limitation of the parser; it's trying to
>> interpret "not" as a binary operator.
>
> I think not. It is lower precedence than all arithmetic operators.
> (We humans see that that is impossible and
> may boost the precedence in context.)

Ah, I stand corrected. And once again, I kinda expected Python to
follow the rules of my mental parser :)

Anyway, point stands that parens will fix the issue.

ChrisA

[toc] | [prev] | [next] | [standalone]


#26932

FromMRAB <python@mrabarnett.plus.com>
Date2012-08-12 01:36 +0100
Message-ID<mailman.3203.1344731811.4697.python-list@python.org>
In reply to#26923
On 11/08/2012 23:30, John Ladasky wrote:
> I have gotten used to switching back and forth between Boolean algebra and numerical values.  Python generally makes this quite easy.  I just found a case that surprises me.
>
> Here is what I want to accomplish:  I want to process a list.  If the length of the list L is odd, I want to process it once.  If len(L) is even, I want to process it twice.  I thought I would set up a loop as follows:
>
> for x in range(1 + not(len(L) % 2)):
>      # Do stuff
>
> This provoked a SyntaxError.  I investigated this further with my interpreter (ipython).
>
> In [1]: L = range(5)
>
> In [2]: L
> Out[2]: [0, 1, 2, 3, 4]
>
> In [3]: len(L)
> Out[3]: 5
>
> In [4]: len(L) % 2
> Out[4]: 1
>
> In [5]: not(1)
> Out[5]: False
>
> In [6]: not(len(L) % 2)
> Out[6]: False
>
> In [7]: 1 + not(len(L) % 2)
> ------------------------------------------------------------
>     File "<ipython console>", line 1
>       1 + not(len(L) % 2)
>             ^
> SyntaxError: invalid syntax
>
> So as you can see, every thing is working fine until I attempt to add 1 and False.  However:
>
> In [8]: 0 == False
> Out[8]: True
>
> In [9]: 1 == True
> Out[9]: True
>
> So, 0 and False do pass an equivalency test, as do 1 and True.  Furthermore:
>
> In [10]: 1 + (len(L) % 2 == 0)
> Out[10]: 1
>
> Why is using a logical "not" function, as shown in [7], returning a different result than the test for equivalency as shown in [10]?
>
> Of course I'm just going to use [10] in my program, but I'd like to understand the reason that I'm getting that SyntaxError.  I've been reading Python style guides, and at least one of them states a preference for using the "not" syntax over the "== 0" syntax.
>
> I'm using Python 2.7, in case it matters.
>
I think the problem is that "not" isn't a function as such - it doesn't 
require parentheses, for example.

The relevant syntax rules are:

a_expr ::= m_expr | a_expr "+" m_expr | a_expr "-" m_expr

m_expr ::= u_expr | m_expr "*" u_expr | m_expr "//" u_expr | m_expr "/"
u_expr | m_expr "%" u_expr

u_expr ::= power | "-" u_expr | "+" u_expr | "~" u_expr

power ::= primary ["**" u_expr]

primary ::= atom | attributeref | subscription | slicing | call

atom ::= identifier | literal | enclosure

enclosure ::= parenth_form | list_display | dict_display | set_display | 
generator_expression | yield_atom

call ::= primary "(" [argument_list [","] | comprehension] ")"

In order for your code to work I think we would need to have something 
like this:

primary ::= atom | attributeref | subscription | slicing | call | not_expr

not_expr ::= "not" parenth_form

[toc] | [prev] | [next] | [standalone]


#26934

FromPaul Rubin <no.email@nospam.invalid>
Date2012-08-11 17:54 -0700
Message-ID<7x4no96ib3.fsf@ruckus.brouhaha.com>
In reply to#26923
John Ladasky <john_ladasky@sbcglobal.net> writes:
> I have gotten used to switching back and forth between Boolean algebra
> and numerical values.  Python generally makes this quite easy. 

Generally ugly though, at least to my tastes.  "Explicit is better
than implicit" as the saying goes.

> If the length of the list L is odd, I want to process it once.  If
> len(L) is even, I want to process it twice....
>   for x in range(1 + not(len(L) % 2)):

If you really have to do something like that, I'd say

   for x in range(1 + (len(L) & 1)):

or

   for x in range(2 - len(L) % 2): 

are simpler and avoid those bogus bool conversions.  I'd prefer to
just say the intention:

   for x in range(1 if len(L)%2==1 else 2):

> This provoked a SyntaxError. 

"not" is a syntactic keyword and "1 + not" is syntactically invalid.
You could write "1 + (not ...)" as you discovered, but really, it's
hackish.

[toc] | [prev] | [next] | [standalone]


#26940

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2012-08-12 11:22 +0000
Message-ID<502791ea$0$29978$c3e8da3$5496439d@news.astraweb.com>
In reply to#26934
On Sat, 11 Aug 2012 17:54:40 -0700, Paul Rubin wrote:

> John Ladasky <john_ladasky@sbcglobal.net> writes:
[...]
>> If the length of the list L is odd, I want to process it once.  If
>> len(L) is even, I want to process it twice....
>>   for x in range(1 + not(len(L) % 2)):
> 
> If you really have to do something like that, I'd say
> 
>    for x in range(1 + (len(L) & 1)):
[snip]

I'd simplify it even more:

for x in (0,) if len(L)%2 else (0, 1):
    ...

which is even more explicit and simpler to read even though it is longer.



-- 
Steven

[toc] | [prev] | [next] | [standalone]


#26941

FromRoy Smith <roy@panix.com>
Date2012-08-12 07:40 -0400
Message-ID<roy-34CDF6.07403012082012@news.panix.com>
In reply to#26940
In article <502791ea$0$29978$c3e8da3$5496439d@news.astraweb.com>,
 Steven D'Aprano <steve+comp.lang.python@pearwood.info> wrote:

> for x in (0,) if len(L)%2 else (0, 1):
>     ...
> 
> which is even more explicit and simpler to read even though it is longer.

Ugh.

do_stuff()
if len(L) % 2 == 0:
   do_stuff()  # reprocess even-length list

Sure, it's 3 lines instead of one, but dead-obvious what the intention 
is.  I might even go for:

if len(L) % 2:
   do_stuff()
else:
   do_stuff()
   do_stuff()

There's two problems with all the looping suggestions people have given.  
One is that the computation of whether you need to do it once or twice 
is messy.  But, but bigger issue is you're trying to warp what's 
fundamentally a boolean value into a looping construct.  That's a 
cognitive mismatch.

[toc] | [prev] | [next] | [standalone]


#26944

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2012-08-12 14:06 +0000
Message-ID<5027b852$0$29978$c3e8da3$5496439d@news.astraweb.com>
In reply to#26941
On Sun, 12 Aug 2012 07:40:30 -0400, Roy Smith wrote:

> In article <502791ea$0$29978$c3e8da3$5496439d@news.astraweb.com>,
>  Steven D'Aprano <steve+comp.lang.python@pearwood.info> wrote:
> 
>> for x in (0,) if len(L)%2 else (0, 1):
>>     ...
>> 
>> which is even more explicit and simpler to read even though it is
>> longer.
> 
> Ugh.
> 
> do_stuff()
> if len(L) % 2 == 0:
>    do_stuff()  # reprocess even-length list
> 
> Sure, it's 3 lines instead of one, but dead-obvious what the intention
> is.

Well, sure, for that specific case that would work too. Using a for-loop 
to do something once is a little icky. But only a little.

Also, it scales to situations like "repeat 37 times when even, or 82 
times when odd" (or any other values).


> There's two problems with all the looping suggestions people have given.
> One is that the computation of whether you need to do it once or twice
> is messy.  But, but bigger issue is you're trying to warp what's
> fundamentally a boolean value into a looping construct.  That's a
> cognitive mismatch.

Really? You've never used a while loop?

while not finished:
    do_something()



There's nothing wrong with having a for-loop which iterates over a 
computed set of values:

if len(L)%2:
    items = range(len(L)//2 + 1)
else:
    items = range(len(L)//2)
for x in items:
    ...


which can be simplified to:

for x in range(len(L)//2 + len(L)%2):
    ...


-- 
Steven

[toc] | [prev] | [next] | [standalone]


#26946

FromPaul Rubin <no.email@nospam.invalid>
Date2012-08-12 09:59 -0700
Message-ID<7x393sxcz9.fsf@ruckus.brouhaha.com>
In reply to#26944
> which can be simplified to:
> for x in range(len(L)//2 + len(L)%2):

for x in range(sum(divmod(len(L), 2))): ...

[toc] | [prev] | [next] | [standalone]


#26947

FromBernd Nawothnig <Bernd.Nawothnig@t-online.de>
Date2012-08-12 19:21 +0200
Message-ID<295lf9-aga.ln1@bernd.nawothnig.dialin.t-online.de>
In reply to#26946
On 2012-08-12, Paul Rubin wrote:
>> which can be simplified to:
>> for x in range(len(L)//2 + len(L)%2):
>
> for x in range(sum(divmod(len(L), 2))): ...

nice solution.



Bernd

-- 
"Die Antisemiten vergeben es den Juden nicht, dass die Juden Geist
haben - und Geld." [Friedrich Nietzsche]

[toc] | [prev] | [next] | [standalone]


#26948

FromMark Lawrence <breamoreboy@yahoo.co.uk>
Date2012-08-12 19:20 +0100
Message-ID<mailman.3208.1344795566.4697.python-list@python.org>
In reply to#26946
On 12/08/2012 17:59, Paul Rubin wrote:
>> which can be simplified to:
>> for x in range(len(L)//2 + len(L)%2):
>
> for x in range(sum(divmod(len(L), 2))): ...
>

So who's going to be first in with "and thou shalt not count to 4..."?

-- 
Cheers.

Mark Lawrence.

[toc] | [prev] | [next] | [standalone]


#26949

FromRoy Smith <roy@panix.com>
Date2012-08-12 14:45 -0400
Message-ID<roy-0B5EBC.14451212082012@news.panix.com>
In reply to#26948
In article <mailman.3208.1344795566.4697.python-list@python.org>,
 Mark Lawrence <breamoreboy@yahoo.co.uk> wrote:

> On 12/08/2012 17:59, Paul Rubin wrote:
> >> which can be simplified to:
> >> for x in range(len(L)//2 + len(L)%2):
> >
> > for x in range(sum(divmod(len(L), 2))): ...
> >
> 
> So who's going to be first in with "and thou shalt not count to 4..."?

You, apparently.

[toc] | [prev] | [next] | [standalone]


#26953

FromAlister <alister.ware@ntlworld.com>
Date2012-08-12 20:13 +0000
Message-ID<A7UVr.32318$aR.12800@fx06.am4>
In reply to#26948
On Sun, 12 Aug 2012 19:20:26 +0100, Mark Lawrence wrote:

> On 12/08/2012 17:59, Paul Rubin wrote:
>>> which can be simplified to:
>>> for x in range(len(L)//2 + len(L)%2):
>>
>> for x in range(sum(divmod(len(L), 2))): ...
>>
>>
> So who's going to be first in with "and thou shalt not count to 4..."?

Five is right out



-- 
Insanity is the final defense ... It's hard to get a refund when the
salesman is sniffing your crotch and baying at the moon.

[toc] | [prev] | [next] | [standalone]


#26962

FromGene Heskett <gheskett@wdtv.com>
Date2012-08-12 20:29 -0400
Message-ID<mailman.3215.1344818163.4697.python-list@python.org>
In reply to#26953
On Sunday 12 August 2012 20:27:13 Alister did opine:

> On Sun, 12 Aug 2012 19:20:26 +0100, Mark Lawrence wrote:
> > On 12/08/2012 17:59, Paul Rubin wrote:
> >>> which can be simplified to:
> >> 
> >>> for x in range(len(L)//2 + len(L)%2):
> >> for x in range(sum(divmod(len(L), 2))): ...
> > 
> > So who's going to be first in with "and thou shalt not count to 4..."?
> 
> Five is right out

Can some smart ass (like me) suggest 69!

If it doesn't get summarily tossed, it could take a week or so to run. :-)

Cheers, Gene
-- 
"There are four boxes to be used in defense of liberty:
 soap, ballot, jury, and ammo. Please use in that order."
-Ed Howdershelt (Author)
My web page: <http://coyoteden.dyndns-free.com:85/gene> is up!
e-credibility: the non-guaranteeable likelihood that the electronic data
you're seeing is genuine rather than somebody's made-up crap.
		-- Karl Lehenbauer

[toc] | [prev] | [next] | [standalone]


#27050

FromHans Mulder <hansmu@xs4all.nl>
Date2012-08-14 18:32 +0200
Message-ID<502a7da3$0$6936$e4fe514c@news2.news.xs4all.nl>
In reply to#26953
On 12/08/12 22:13:20, Alister wrote:
> On Sun, 12 Aug 2012 19:20:26 +0100, Mark Lawrence wrote:
> 
>> On 12/08/2012 17:59, Paul Rubin wrote:
>>>> which can be simplified to:
>>>> for x in range(len(L)//2 + len(L)%2):
>>>
>>> for x in range(sum(divmod(len(L), 2))): ...
>>>
>>>
>> So who's going to be first in with "and thou shalt not count to 4..."?
> 
> Five is right out

Neither count thou two, excepting that thou then proceed to three

-- HansM



[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web