Google Gruppi non supporta più i nuovi post o le nuove iscrizioni Usenet. I contenuti storici continuano a essere visibili.

Operator Precedence/Boolean Logic

208 visualizzazioni
Passa al primo messaggio da leggere

Elizabeth Weiss

da leggere,
21 giu 2016, 23:40:2221/06/16
a
Hi There,

I am a little confused as to how this is False:

False==(False or True)

I would think it is True because False==False is true.

I think the parenthesis are confusing me.

(False==False) or True

This is True. Is it because False==False? And True==False is not True but that does not change that this is True.

If someone could please explain as I am teaching Python to myself and am stuck on this that would be great.
Thank you for your help!

Ben Finney

da leggere,
21 giu 2016, 23:59:3721/06/16
a
Elizabeth Weiss <cak...@gmail.com> writes:

> Hi There,

Welcome! Your questions are fine here, but you may like to know that we
also have a beginner-specific forum for collaborative tutoring
<URL:https://mail.python.org/mailman/listinfo/tutor>.

> I am a little confused as to how this is False:
> False==(False or True)
>
> I would think it is True because False==False is true.

What does ‘(False or True)’ evaluate to, when you try it in the REPL?

> I think the parenthesis are confusing me.
> (False==False) or True
>
> This is True. Is it because False==False? And True==False is not True
> but that does not change that this is True.

Heh. You express the confusion quite well :-)

Try the component expressions in the REPL (the interactive interpreter
session) and see if that helps::

>>> False or True

>>> (False or True)

>>> True == False

>>> (True == False)

>>> False == False

>>> (False == False)


Then, once you think you understand what those expressions evaluate to,
look again at how those results would work in a more complex
expression::

>>> False == (False or True)

>>> (False == False) or True


> Thank you for your help!

I hope that helps.

--
\ “[W]e are still the first generation of users, and for all that |
`\ we may have invented the net, we still don't really get it.” |
_o__) —Douglas Adams |
Ben Finney

Steven D'Aprano

da leggere,
22 giu 2016, 02:03:4522/06/16
a
On Wednesday 22 June 2016 13:40, Elizabeth Weiss wrote:

> Hi There,
>
> I am a little confused as to how this is False:
>
> False==(False or True)
>
> I would think it is True because False==False is true.

Remember that parentheses are always evaluated first. So Python evaluates:

False or True

first, which evaluates as True. Then it evaluates False == True, which is
obviously False.

Why is "False or True" True? Well, consider this question:

Who is allowed on the rides at the amusement park?
- people over 18, regardless of their height;
- people under 18, if they are "this tall" (4ft 6in) or greater.

Is Fred (16 years old, and 5ft 6in tall) allowed on the ride? Only if:
- he is over 18, or taller than "this tall";
- which is "False or True"
- which is True



Does that help?


--
Steve

Christian Gollwitzer

da leggere,
22 giu 2016, 02:26:3922/06/16
a
Am 22.06.16 um 05:40 schrieb Elizabeth Weiss:
> I am a little confused as to how this is False:
>
> False==(False or True)
>
> I would think it is True because False==False is true.
>
> I think the parenthesis are confusing me.

Are you thinking, by any chance, that "or" indicates a choice? Comparing
False to either False "or" True? That is not the case.

"or" is an operator. "False or True" is *computed* and gives True, which
is then compared to False by "==". Python works in these steps:

1) False == (False or True)
2) False == (True)
3) False


Christian

Jussi Piitulainen

da leggere,
22 giu 2016, 03:15:0222/06/16
a
Similarly:

1) "coffee" == ("coffee" or "tea")
2) "coffee" == "coffee"
3) True

1) "tea" == ("coffee" or "tea")
2) "tea" == "coffee"
3) False

In programming languages that allow it, want("coffee" or "tea") is
probably not intended. One has to (want("coffee") or want("tea")).

I'm not trying to confuse. I'm trying to further illustrate how the
programming language notation differs from ordinary structures of
languages like English that may seem analogous until one learns that
they aren't, quite.

Lawrence D’Oliveiro

da leggere,
22 giu 2016, 03:42:2422/06/16
a
On Wednesday, June 22, 2016 at 3:40:22 PM UTC+12, Elizabeth Weiss wrote:
> I am a little confused as to how this is False:
>
> False==(False or True)
>
> I would think it is True because False==False is true.
>
> I think the parenthesis are confusing me.

No, it is the meanings of the boolean operators in Python. The rules are:

* boolean operators don’t have to operate on boolean values. The language spec <https://docs.python.org/3/reference/expressions.html#boolean-operations> says:

“...the following values are interpreted as false: False, None, numeric
zero of all types, and empty strings and containers (including strings,
tuples, lists, dictionaries, sets and frozensets). All other values are
interpreted as true.”

I feel that’s a needlessly complicated rule. It would have been simpler if boolean operators (and conditional expressions like in if-statements and while-statements) only allowed values of boolean types. But that’s one of the few warts in the design of Python...

* the meaning of “A or B” is: “return A if it evaluates to true, else return B”. Correspondingly, the meaning of “A and B” is: “return A if it evaluates to false, else return B”.

Does that give you enough clues to understand what is going on?

Jorge Gimeno

da leggere,
22 giu 2016, 06:48:5322/06/16
a
> --
> https://mail.python.org/mailman/listinfo/python-list
>

You have 2 comparisons here . The first is inside the parenthesis, (False
or True) evaluates to True. What remains of the expression is False ==
True, which is False.

-Jorge
(Reposted because I replied to the OP directly, instead of to the list)

Random832

da leggere,
22 giu 2016, 10:10:5822/06/16
a
On Tue, Jun 21, 2016, at 23:40, Elizabeth Weiss wrote:
> Hi There,
>
> I am a little confused as to how this is False:
>
> False==(False or True)
>
> I would think it is True because False==False is true.

"False or True" is True, and then it reduces to "False == True" which is
false.

There's no "x == (y or z)" construct to compare x separately to both y
and z, the "or" will evaluate to the first one that's true and then is
used in the rest of the expression. If you wanted to write "x == y or x
== z" with only a single x, you'd do "x in (y, z)".

Erik

da leggere,
22 giu 2016, 15:47:2122/06/16
a
On 22/06/16 04:40, Elizabeth Weiss wrote:
> I am a little confused as to how this is False:
>
> False==(False or True)

Other people have explained why the expression evaluates as it does -
the sub-expression "False or True" evaluates to True (as one of the
operands is truthy). Your expression then becomes "False == True", which
is of course false.

To get the construct you were expecting (is the thing on the left hand
side equal to one of the things on the right hand side), you can use
Python's "in" keyword to "search" a collection (list, tuple, set,
dictionary etc) that contains the things you are trying to match:

>>> False in (False, True) # tuple

>>> False in [False, True] # list

>>> False in {False, True} # set

>>> False in {False: None, True: None} # dict

HTH,
E.

Larry Hudson

da leggere,
22 giu 2016, 23:12:5222/06/16
a
On 06/22/2016 12:42 AM, Lawrence D’Oliveiro wrote:
[snip]
> I feel that’s a needlessly complicated rule. It would have been simpler if boolean operators (and conditional expressions like in if-statements and while-statements) only allowed values of boolean types. But that’s one of the few warts in the design of Python...
>

Wart?? I *strongly* disagree. I find it one of the strengths of Python, it enhances Python's
expressiveness. Of course, everyone is entitled to their own opinion...and this is mine.

--
-=- Larry -=-

Steven D'Aprano

da leggere,
22 giu 2016, 23:59:4422/06/16
a
Allowing any value as a truth value is just applying the principle of
duck-typing to booleans.

There are a pair of canonical truth values, namely True and False, but any
object can quack like a truth value. We often call them:

- true and false (as opposed to True and False);
- true-like and false-like;
- truthy and falsey

values.

Among the builtins, there's a general principle:

- values that represent something should be truthy;
- values that represent nothing should be falsey.

So we have falsey values:

- None
- zeroes (0, 0.0, 0j, etc)
- empty dict {}
- empty sets and frozensets
- empty strings '' and b'' (in Python 2: u'' and '')
- empty lists, tuples and other sequences

and truthy values:

- object
- non-zero numbers
- non-empty dicts
- non-empty sets and frozensets
- non-empty strings
- non-empty sequences

This is an improvement over other languages like Javascript, Ruby, etc where
the division between truthy and falsey appears to be fairly arbitrary.




--
Steven

Elizabeth Weiss

da leggere,
23 giu 2016, 00:19:2523/06/16
a
On Tuesday, June 21, 2016 at 11:59:37 PM UTC-4, Ben Finney wrote:
Thank you, Ben!

Elizabeth Weiss

da leggere,
23 giu 2016, 00:20:4823/06/16
a
On Tuesday, June 21, 2016 at 11:59:37 PM UTC-4, Ben Finney wrote:
Thank you, Ben!

Elizabeth Weiss

da leggere,
23 giu 2016, 00:21:4923/06/16
a
Thanks, Jussi! Very helpful.

Elizabeth Weiss

da leggere,
23 giu 2016, 00:22:2223/06/16
a
Thanks, Lawrence!

Elizabeth Weiss

da leggere,
23 giu 2016, 00:24:0223/06/16
a
Thanks, Steven!

Lawrence D’Oliveiro

da leggere,
23 giu 2016, 00:47:1623/06/16
a
On Thursday, June 23, 2016 at 3:12:52 PM UTC+12, Larry Hudson wrote:
> On 06/22/2016 12:42 AM, Lawrence D’Oliveiro wrote:
>> * boolean operators don’t have to operate on boolean values. The
>> language spec
>> <https://docs.python.org/3/reference/expressions.html#boolean-operations>
>> says:
>>
>> “...the following values are interpreted as false: False, None, numeric
>> zero of all types, and empty strings and containers (including strings,
>> tuples, lists, dictionaries, sets and frozensets). All other values are
>> interpreted as true.”
>>
>> I feel that’s a needlessly complicated rule. It would have been simpler if
>> boolean operators (and conditional expressions like in if-statements and
>> while-statements) only allowed values of boolean types. But that’s one of
>> the few warts in the design of Python...
>
> Wart?? I *strongly* disagree. I find it one of the strengths of Python,
> it enhances Python's expressiveness.

Tightening it up would rule out a whole class of common errors, from misunderstanding (or forgetting) the rule about what exactly gets interpreted as true and what as false <https://bugs.python.org/issue13936> <http://stackoverflow.com/questions/28116931/datetime-time0-0-evaluates-as-false-in-boolean-context>.

Rustom Mody

da leggere,
23 giu 2016, 01:00:2123/06/16
a
I would not support "tightening up"
But calling a wart a wart seems like a good idea to me
IOW making the docs a little more honest:
Along these lines:

There are two bool types in Python
A first class bool that is useful for amusement, confusion and one-upping noobs

A second class bool -- also called truthy and falsey -- that is used all the time

Andreas Röhler

da leggere,
23 giu 2016, 02:30:3623/06/16
a
Indeed, why should the result of 4 - 4 have a different truth-value than
4 - 3 ?
This implementation seems to be a legacy from languages without boolean
types.

Marko Rauhamaa

da leggere,
23 giu 2016, 02:46:2723/06/16
a
Andreas Röhler <andreas...@online.de>:

> Indeed, why should the result of 4 - 4 have a different truth-value
> than 4 - 3 ? This implementation seems to be a legacy from languages
> without boolean types.

In Lisp, only nil (= the empty list) is accepted as false, everything
else is considered true.

In Scheme, only #f (= False) is accepted as false, everything else is
considered true even though there is also a dedicated #t for True.


Marko

Steven D'Aprano

da leggere,
23 giu 2016, 03:05:4823/06/16
a
On Thursday 23 June 2016 16:34, Andreas Röhler wrote:

> Indeed, why should the result of 4 - 4 have a different truth-value than
> 4 - 3 ?

Because 4-4 is zero, which is "nothing", while 4-3 is one, which is
"something".

You might as well ask why False and True have different truth values.
Ironically, in a manner of speaking you *did* ask that, since 4-3 == True and
4-4 == False.


--
Steve

Christian Gollwitzer

da leggere,
23 giu 2016, 03:11:4823/06/16
a
Am 23.06.16 um 05:12 schrieb Larry Hudson:
https://xkcd.com/1172/

Christian

Steven D'Aprano

da leggere,
23 giu 2016, 03:20:3023/06/16
a
On Thursday 23 June 2016 14:47, Lawrence D’Oliveiro wrote:

> On Thursday, June 23, 2016 at 3:12:52 PM UTC+12, Larry Hudson wrote:
>> On 06/22/2016 12:42 AM, Lawrence D’Oliveiro wrote:
>>> * boolean operators don’t have to operate on boolean values. The
>>> language spec
>>> <https://docs.python.org/3/reference/expressions.html#boolean-operations>
>>> says:
>>>
>>> “...the following values are interpreted as false: False, None, numeric
>>> zero of all types, and empty strings and containers (including strings,
>>> tuples, lists, dictionaries, sets and frozensets). All other values are
>>> interpreted as true.”
>>>
>>> I feel that’s a needlessly complicated rule.

As I described in my earlier email, it isn't complicated, at least not the way
builtins are modelled.


>>> It would have been simpler if
>>> boolean operators (and conditional expressions like in if-statements and
>>> while-statements) only allowed values of boolean types. But that’s one of
>>> the few warts in the design of Python...
>>
>> Wart?? I *strongly* disagree. I find it one of the strengths of Python,
>> it enhances Python's expressiveness.
>
> Tightening it up would rule out a whole class of common errors,

Hardly common. The only two exceptions I've seen are:

- people surprised by midnight being false, but that is fixed in 3.5;
- people surprised that empty or exhausted iterables don't evaluate as false

and the first of those is pretty rare.

But even if you were right, and I disagree that you are, "fixing" this would
break backwards compatibility and cause vast amounts of working code to stop
working. That is much worse than the "problem".


> from
> misunderstanding (or forgetting) the rule about what exactly gets interpreted
> as true and what as false <https://bugs.python.org/issue13936>
> <http://stackoverflow.com/questions/28116931/datetime-time0-0-evaluates-as-
false-in-boolean-context>.

Or... we could fix time objects, as was done.


--
Steve

Antoon Pardon

da leggere,
23 giu 2016, 03:59:5823/06/16
a
Op 23-06-16 om 05:59 schreef Steven D'Aprano:
> On Thu, 23 Jun 2016 01:12 pm, Larry Hudson wrote:
>
>> On 06/22/2016 12:42 AM, Lawrence D’Oliveiro wrote:
>> [snip]
>>> I feel that’s a needlessly complicated rule. It would have been simpler
>>> if boolean operators (and conditional expressions like in if-statements
>>> and while-statements) only allowed values of boolean types. But that’s
>>> one of the few warts in the design of Python...
>>>
>> Wart?? I *strongly* disagree. I find it one of the strengths of Python,
>> it enhances Python's
>> expressiveness. Of course, everyone is entitled to their own
>> opinion...and this is mine.
> Allowing any value as a truth value is just applying the principle of
> duck-typing to booleans.

What does that mean? As far as I understood, duck typing was that you
could define any class with the same attributes and methods as an other,
often a built in, at which point you could substitute instance of this
new class anywhere you originally expected instance of the old class.

My experience is that this doesn't work with booleans. When I need
real booleans, encountering whatever else that can act like a boolean,
is more often than not an indication something went wrong but the
detection of it going wrong is delayed, because almost everything
can act like a boolean. It is why I have sometime found the need
to write:

if flag is True:

Because flag needed to be True, not truthy.

--
Antoon Pardon


Marko Rauhamaa

da leggere,
23 giu 2016, 04:17:0223/06/16
a
Antoon Pardon <antoon...@rece.vub.ac.be>:

> It is why I have sometime found the need to write:
>
> if flag is True:
>
> Because flag needed to be True, not truthy.

Then, you have found the correct idiom for your rare need. You might
even want to consider:

if flag is UP:
...
elif flag is DOWN:
...
else:
assert flag is HALFMAST
...


I don't particularly like Python's falsey/truthy semantics, but I can
live with it. The biggest problem I have with it is the absence of an
emptiness predicate. I'd like to be able to write:

if not leftover.empty():
...

or even:

if not empty(leftover):
...

rather than having to say:

if not leftover:
...

or:

if len(leftover) > 0: # no, I'd never write this
...


Marko

Antoon Pardon

da leggere,
23 giu 2016, 04:18:4623/06/16
a
Op 23-06-16 om 09:05 schreef Steven D'Aprano:
> On Thursday 23 June 2016 16:34, Andreas Röhler wrote:
>
>> Indeed, why should the result of 4 - 4 have a different truth-value than
>> 4 - 3 ?
> Because 4-4 is zero, which is "nothing", while 4-3 is one, which is
> "something".

No zero is not nothing. If zere is nothing and an empty list is nothing,
I would expect zero to be an empty list or that they could be used interchangebly.

For instance in a project of mine polling for information and
receiving an empty list is different from receiving None. An empty
list means there is currently no information available. None means
The information streams came to an end.

I rarely need tests where any truthy value will branch in one
direction and any falsy value in the other. So IMO it is more
hassle than it is worth.

--
Antoon.


Andreas Röhler

da leggere,
23 giu 2016, 04:18:4923/06/16
a


On 23.06.2016 09:05, Steven D'Aprano wrote:
> On Thursday 23 June 2016 16:34, Andreas Röhler wrote:
>
>> Indeed, why should the result of 4 - 4 have a different truth-value than
>> 4 - 3 ?
> Because 4-4 is zero, which is "nothing",

Hmm, water freezes at zero degree celsius, because there is no temperature?

Andreas Röhler

da leggere,
23 giu 2016, 04:28:1423/06/16
a


On 23.06.2016 10:17, Antoon Pardon wrote:
> Op 23-06-16 om 09:05 schreef Steven D'Aprano:
>> On Thursday 23 June 2016 16:34, Andreas Röhler wrote:
>>
>>> Indeed, why should the result of 4 - 4 have a different truth-value than
>>> 4 - 3 ?
>> Because 4-4 is zero, which is "nothing", while 4-3 is one, which is
>> "something".
> No zero is not nothing. If zere is nothing and an empty list is nothing,
> I would expect zero to be an empty list or that they could be used interchangebly.
>
>

There is a fundamental diff between zero and emptiness.

Zero is just a relation in the realm of integers. It tells being in the
midst between positiv and negativ infinity.
Number one tells being one unit towards positiv infinity in relation to
negativ infinity. And so on.

Whilst emptiness tells about non-existence.

Steven D'Aprano

da leggere,
23 giu 2016, 04:48:4223/06/16
a
On Thursday 23 June 2016 18:17, Antoon Pardon wrote:

> No zero is not nothing.

I think you have just disagreed with about four thousand years of
mathematicians and accountants.

In fact, mathematicians were so hung up about zero being nothing, that it took
about three thousand years before they accepted zero as a number (thanks to
Indian mathematicians, via Arab mathematicians).

> If zere is nothing and an empty list is nothing,
> I would expect zero to be an empty list or that they could be used
> interchangebly.

You must have real trouble with statically typed languages then. Some of them
won't even let you add 0.0 + 1 (since 0.0 is a float and 1 is an int).

> For instance in a project of mine polling for information and
> receiving an empty list is different from receiving None.

Okay. How is this relevant to the question of bools? If Python had "real bools"
(in, say, the Pascal sense) you would still need to distinguish None from an
empty list:

if info is None:
print("done")
elif info: # duck-typing version
# "real bools" version uses "info != []" instead
print("processing...")
else:
print("nothing to process")


In fact, in this case chances are you probably don't even care to distinguish
between empty and non-empty lists. What (I imagine) you probably care about is
None versus any list:

if info is None:
print("done")
else:
for item in info:
print("processing...")


> I rarely need tests where any truthy value will branch in one
> direction and any falsy value in the other.

That's reasonable. Few people do, except in the general case that they write
some code that accepts any arbitrary truthy value. But more often, you expect
that you are inspecting an object of some specific type, say, a sequence (list,
tuple, deque, etc):

if seq:
process()
else:
handle_empty_case()


or a mapping (dict, UserDict, etc):

if mapping:
process()
else:
handle_empty_case()


or a Widget:

if widget:
process()
else:
handle_empty_case()


where you ask the object in question whether or not it should be considered
empty ("nothing") or not ("something"), rather than having to call a type-
specific piece of code for each one:

if len(seq) == 0: ...

if mapping.isempty(): ...

if widget.isnullwidget(): ...



It's just duck-typing. Bools have certain behaviour in certain contexts, and
*all* objects get the opportunity to quack like a bool in that context.



--
Steve

Lawrence D’Oliveiro

da leggere,
23 giu 2016, 04:53:2823/06/16
a
On Thursday, June 23, 2016 at 8:17:02 PM UTC+12, Marko Rauhamaa wrote:
> if len(leftover) > 0: # no, I'd never write this
> ...

I regularly write “len(leftover) != 0”. Why not?

Antoon Pardon

da leggere,
23 giu 2016, 05:02:0623/06/16
a
Op 23-06-16 om 10:16 schreef Marko Rauhamaa:
> I don't particularly like Python's falsey/truthy semantics, but I can
> live with it. The biggest problem I have with it is the absence of an
> emptiness predicate. I'd like to be able to write:
>
> if not leftover.empty():
> ...
>
> or even:
>
> if not empty(leftover):
> ...
>
> rather than having to say:
>
> if not leftover:
> ...
>
> or:
>
> if len(leftover) > 0: # no, I'd never write this
> ...

Well if I have to test for emptyness, I always write

if len(seq) > 0:

Because this will throw an exception when len can't
apply to seq and so this will catch possible bugs
sooner than writing:

if not seq.

--
Antoon Pardon


Marko Rauhamaa

da leggere,
23 giu 2016, 05:11:0523/06/16
a
Lawrence D’Oliveiro <lawren...@gmail.com>:
The __len__ method is not guaranteed to execute in O(1). See:

<URL: https://docs.python.org/3/reference/datamodel.html?highlig
ht=__len__#object.__len__>


Marko

Steven D'Aprano

da leggere,
23 giu 2016, 05:17:3823/06/16
a
On Thursday 23 June 2016 18:32, Andreas Röhler wrote:

> There is a fundamental diff between zero and emptiness.

In English, "emptiness" implies a container (real or figurative). The container
is not "something or nothing", it is the *contents* being referred to.

"This shopping bag is empty" doesn't mean the shopping bag is nothing. It means
that the set of items in the bad is the null set, i.e. there are ZERO items in
the bag.

"My fridge is empty" doesn't mean that the fridge is nothing. It means that the
set of items in the fridge is the null set, i.e. there are ZERO items in the
fridge.

"That guy's head is empty" doesn't mean his head is nothing, it means that the
set of thoughts in his head is the null set, i.e. he has ZERO thoughts. (This,
of course, should be read figuratively, not literally.)


> Zero is just a relation in the realm of integers. It tells being in the
> midst between positiv and negativ infinity.

No, zero is not "a relation". It is an integer, and a very special one.

- zero is neither positive nor negative;
- zero is the additive identity: n+0 == n
- zero is multiplicative nullity; n*0 == 0
- division by zero is undefined.

It is an artifact of the way we draw the number line (a *picture*) that zero is
halfway between positive and negative:

<----------------------+------------------------>
-4 -3 -2 -1 0 1 2 3 4

We could have draw it like this, with zero at the extreme left hand end:


-3 /
-2 /
-1 /
0 +
1 \
2 \
3 \

although that would make graphing look a bit weird.

(That's what we do with the extended Reals: we bend the number line around in a
circle, with 0 at one pole and ±infinity at the other.)

But don't confuse the concrete representation of numbers on a line with the
abstract numbers themselves.

In practical sense, there is a difference between having zero sheep and having
one sheep, two sheep, three sheep, ... and of course nobody has even actually
had negative one sheep.


> Number one tells being one unit towards positiv infinity in relation to
> negativ infinity. And so on.
>
> Whilst emptiness tells about non-existence.

We can derive arithmetic from set theory. Zero is very special: it is defined
as the empty set:

0: {}

The successor of zero (namely, one) is the set of all empty sets:

1: {{}}

Two is the set of zero and one:

2 = {{}, {{}}}

and so forth.



--
Steve

Antoon Pardon

da leggere,
23 giu 2016, 05:24:4723/06/16
a
Op 23-06-16 om 10:48 schreef Steven D'Aprano:
> On Thursday 23 June 2016 18:17, Antoon Pardon wrote:
>
>> No zero is not nothing.
> I think you have just disagreed with about four thousand years of
> mathematicians and accountants.

I don't care. In modern mathematics, zero is usaly defined as the
empty set. The empty set contains nothing, but it isn't nothing
itself. Otherwise the empty set would be the same as the set
containing the empty set, since they both would contain the same,
being nothing.

So modern mathematics seems to agree with me and that is enough
for me.

>> If zere is nothing and an empty list is nothing,
>> I would expect zero to be an empty list or that they could be used
>> interchangebly.
> You must have real trouble with statically typed languages then. Some of them
> won't even let you add 0.0 + 1 (since 0.0 is a float and 1 is an int).

Your conclusion is a non sequitur.


>> For instance in a project of mine polling for information and
>> receiving an empty list is different from receiving None.
> Okay. How is this relevant to the question of bools? If Python had "real bools"
> (in, say, the Pascal sense) you would still need to distinguish None from an
> empty list:

It illustrates the distinction python makes into truthy and falsy, is often
enough inadequate.

A language with real bools would force you to write out the actual expression
you want and wouldn't tempt you to write something you think will work out
fine.

The zen of python states that explicit is better than implicit, but the
"boolean" semantics of python seem to encourage people to rely on a
lot of implicit things that are going on.

--
Antoon Pardon.

Antoon Pardon

da leggere,
23 giu 2016, 05:31:2823/06/16
a
Op 23-06-16 om 11:10 schreef Marko Rauhamaa:
As far as I can see, neither is the __bool__ method.

--
Antoon.

Steven D'Aprano

da leggere,
23 giu 2016, 05:39:3623/06/16
a
On Thursday 23 June 2016 17:58, Antoon Pardon wrote:

> Op 23-06-16 om 05:59 schreef Steven D'Aprano:
>> On Thu, 23 Jun 2016 01:12 pm, Larry Hudson wrote:
>>
>>> On 06/22/2016 12:42 AM, Lawrence D’Oliveiro wrote:
>>> [snip]
>>>> I feel that’s a needlessly complicated rule. It would have been simpler
>>>> if boolean operators (and conditional expressions like in if-statements
>>>> and while-statements) only allowed values of boolean types. But that’s
>>>> one of the few warts in the design of Python...
>>>>
>>> Wart?? I *strongly* disagree. I find it one of the strengths of Python,
>>> it enhances Python's
>>> expressiveness. Of course, everyone is entitled to their own
>>> opinion...and this is mine.
>> Allowing any value as a truth value is just applying the principle of
>> duck-typing to booleans.
>
> What does that mean? As far as I understood, duck typing was that you
> could define any class with the same attributes and methods as an other,
> often a built in, at which point you could substitute instance of this
> new class anywhere you originally expected instance of the old class.

But you only need to implement the behaviour you need, not the entire Duck
interface. If you only need quack(), you don't need to implement swim(), or
provide an actual Duck, any object capable of quacking will do.

To decide on a branch, you don't need an actual bool, anything capable of
acting like a bool will do. As a language design, ALL objects are capable of
acting like a bool. Python has a specific protocol in place for deciding
whether an object quacks like a bool:

if the object defines __len__:
if it returns 0, then the object is false;
else the object is true
elif the object defines __nonzero__ (__bool__ in Python 3)
if it returns a true value, then the object is true
else the object is false
else
# neither __len__ nor __nonzero__ is defined
the object is true


> My experience is that this doesn't work with booleans. When I need
> real booleans, encountering whatever else that can act like a boolean,
> is more often than not an indication something went wrong but the
> detection of it going wrong is delayed, because almost everything
> can act like a boolean. It is why I have sometime found the need
> to write:
>
> if flag is True:
>
> Because flag needed to be True, not truthy.

I find this hard to believe. Why do you care if somebody passes you 1 or "T" as
the flag instead of True? And if they do pass something other than True, you
don't get an exception, you simply take the false branch.

Somehow I doubt that you write three-state logic everywhere:

if flag is True: ...
elif flag is False: ...
else: ...


By the way, it is a particular error of folks using so-called "real bools" to
compare something you already know is a bool against True. I used to see it all
the time in my Pascal days, where people would define a boolean flag then write
"if flag == True". Given:

assert isinstance(flag, bool)

then writing

flag is True

returns a bool. So how do you test a bool? By comparing it to True:

flag is True is True

But that also returns a bool, so you must enter an infinite regress:

flag is True is True is True is True... # help me, where do I stop???

The right answer, of course, is to stop *right at the beginning*. Stopping at
Step 2 is silly and pointless. Since you know flag is a True or False value,
then you just write:

flag

And the same applies to true and false values.




--
Steve

Lawrence D’Oliveiro

da leggere,
23 giu 2016, 05:44:5223/06/16
a
On Thursday, June 23, 2016 at 9:11:05 PM UTC+12, Marko Rauhamaa wrote:
> Lawrence D’Oliveiro:
>
>> On Thursday, June 23, 2016 at 8:17:02 PM UTC+12, Marko Rauhamaa wrote:
>>> if len(leftover) > 0: # no, I'd never write this
>>> ...
>>
>> I regularly write “len(leftover) != 0”. Why not?
>
> The __len__ method is not guaranteed to execute in O(1).

So what is?

Marko Rauhamaa

da leggere,
23 giu 2016, 05:46:1923/06/16
a
Steven D'Aprano <steve+comp....@pearwood.info>:

> On Thursday 23 June 2016 18:32, Andreas Röhler wrote:
>
>> There is a fundamental diff between zero and emptiness.
>
> In English, "emptiness" implies a container (real or figurative). The
> container is not "something or nothing", it is the *contents* being
> referred to.
>
> "This shopping bag is empty" doesn't mean the shopping bag is nothing.
> It means that the set of items in the bad is the null set, i.e. there
> are ZERO items in the bag.

I once read this puzzle in a book:

There was a shipwreck in the middle of an ocean. The ship and the
cargo were lost, but five sailors managed to swim to the beach of a
nearby island. After quick scouting, the sailors realized they were
on a tiny desert island with lots of coconut trees loaded with
coconuts.

The sailors set out to collect all coconuts they could find. After
several hours, they had finished the job and made a sizeable pile of
coconuts on the beach. They were exhausted and it was getting dark so
they agreed to divide the pile evenly between each other on the
following morning. They camped on the beach for the night.

One of the sailors couldn't sleep. Would the others give him his
share? What if they overpowered him and left him without coconuts? He
sneaked to the pile of coconuts, split the big pile evenly into five
smaller piles. One was left over, he threw it to a monkey that was
watching nearby. He took his fifth, carried the coconuts to a secret
location, and put the rest of the coconuts in a single pile so others
wouldn't notice the loss. He went back to the camp and fell sound
asleep.

Another sailer woke up. What if he wouldn't get his share of the
coconuts? He went to the big pile, divided it evenly into five
smaller piles (one coconut was left over -- he threw it to the
monkey), hid his share, put the big pile back together, and went to
sleep.

Before dawn, each of the sailors had gone through the same exercise.
When they woke up, they went to the pile. Everyone noticed the pile
had shrunk during the night but nobody mentioned it. They divided the
pile evenly between the five. One coconut was left over and they
threw it to the monkey.

How many coconuts were there in the pile originally?


The book went on to find the answer(s), but gave also this interesting
side solution:

The pile originally had -4 coconuts. The first sailor threw one to
the monkey, leaving -5 coconuts in the pile. He took his share (-1
coconut) out and put the remaining -4 coconuts back in the big pile.

And so on.


Ridiculous? It was this line of thinking that led Paul Dirac to predict
the existence of antimatter.


Marko

Andreas Röhler

da leggere,
23 giu 2016, 05:52:5923/06/16
a


On 23.06.2016 11:17, Steven D'Aprano wrote:
> [ ... ]
> We can derive arithmetic from set theory.

IMO not, resp. not really. But that would make a another item, pretty
off-topic from Python.

Should you know a place where to continue, would like to follow up.

Thanks BTW.

Marko Rauhamaa

da leggere,
23 giu 2016, 05:53:1723/06/16
a
Antoon Pardon <antoon...@rece.vub.ac.be>:

> Op 23-06-16 om 11:10 schreef Marko Rauhamaa:
>> The __len__ method is not guaranteed to execute in O(1). See:
>>
>> <URL: https://docs.python.org/3/reference/datamodel.html?highlig
>> ht=__len__#object.__len__>
>
> As far as I can see, neither is the __bool__ method.

Correct, but in the absence of an __empty__ method, __bool__ gives the
class the best opportunity to check for emptiness quickly.

This is not only a theoretical concern. It's quite common for data
structures not to maintain an element count because it's extra baggage
that's not always needed and any application could keep a track of.
However, an emptiness check is often trivial.


Marko

Marko Rauhamaa

da leggere,
23 giu 2016, 05:57:3523/06/16
a
Lawrence D’Oliveiro <lawren...@gmail.com>:

> On Thursday, June 23, 2016 at 9:11:05 PM UTC+12, Marko Rauhamaa wrote:
>> The __len__ method is not guaranteed to execute in O(1).
>
> So what is?

The __bool__ method is the appropriate place to implement an efficient
emptiness check. It might not be O(1) but it will be the most efficient
way to check for emptiness, or the class is badly implemented.


Marko

Andreas Röhler

da leggere,
23 giu 2016, 06:15:2123/06/16
a


On 23.06.2016 11:46, Marko Rauhamaa wrote:
>
> Ridiculous? It was this line of thinking that led Paul Dirac to predict
> the existence of antimatter.
>
>
> Marko

Yeah. Maybe we could construct examples already using antagonistic
charges of electrons?

Antoon Pardon

da leggere,
23 giu 2016, 06:22:4023/06/16
a
Op 23-06-16 om 11:39 schreef Steven D'Aprano:
But an object acting like a bool, doesn't mean this bool behaviour makes the
disctinction you actually need. Python tempts people to rely on those truthy
values, because it saves typing is pythonic and it works for the moment and
then something unexpected gets passed through and you find yourself chasing
a very illusive bug.

>> My experience is that this doesn't work with booleans. When I need
>> real booleans, encountering whatever else that can act like a boolean,
>> is more often than not an indication something went wrong but the
>> detection of it going wrong is delayed, because almost everything
>> can act like a boolean. It is why I have sometime found the need
>> to write:
>>
>> if flag is True:
>>
>> Because flag needed to be True, not truthy.
> I find this hard to believe. Why do you care if somebody passes you 1 or "T" as
> the flag instead of True? And if they do pass something other than True, you
> don't get an exception, you simply take the false branch.
>
> Somehow I doubt that you write three-state logic everywhere:

Since I wrote above the I *sometimes* found this need. You may
safely assume I don't write it everywhere.

>
> if flag is True: ...
> elif flag is False: ...
> else: ...
>
>
> By the way, it is a particular error of folks using so-called "real bools" to
> compare something you already know is a bool against True. I used to see it all
> the time in my Pascal days, where people would define a boolean flag then write
> "if flag == True". Given:
>
> assert isinstance(flag, bool)

But of course if one would show such a line in code on this
list, it would illicit a lot of comments on how unpythonic this
this is and that you really shouldn't, and that you should realy
rely on an exception being thrown when what you are provided
doesn't work.

You come here with a remark depending on not using duck typing
when you start your contribution with defending duck typing.

--
Antoon.

Antoon Pardon

da leggere,
23 giu 2016, 06:55:4923/06/16
a
Op 23-06-16 om 11:53 schreef Marko Rauhamaa:
Maybe something like this:

def empty(sq):
try:
iter(sq).next()
except StopIteration:
return False
except:
raise TypeError
else:
return True

Marko Rauhamaa

da leggere,
23 giu 2016, 07:00:0423/06/16
a
Antoon Pardon <antoon...@rece.vub.ac.be>:

> Op 23-06-16 om 11:53 schreef Marko Rauhamaa:
> Maybe something like this:
>
> def empty(sq):
> try:
> iter(sq).next()
> except StopIteration:
> return False
> except:
> raise TypeError
> else:
> return True

That may or may not be as effective as a boolean check. The point is,
Python has already declared that __bool__ is the canonical emptiness
checker. You could even say that it's the principal purpose of the
__bool__ method.


Marko

Antoon Pardon

da leggere,
23 giu 2016, 07:16:2323/06/16
a
Op 23-06-16 om 12:59 schreef Marko Rauhamaa:
I think it is wrong to say __bool__ is the canonical emptiness checker.
It can be used for anything where you somehow think it is reasonable
to make a distinction between truthy and falsy. Even when talking
about emptyness doesn't make sense.

The function above at least raises an exception in a lot of cases
where the class provides booly behaviour yet emptyness wouldn't make
sense.

Would it be worth while? That you have to decide for yourself.

--
Antoon.


Chris Angelico

da leggere,
23 giu 2016, 07:45:1923/06/16
a
On Thu, Jun 23, 2016 at 7:23 PM, Antoon Pardon
<antoon...@rece.vub.ac.be> wrote:
> I don't care. In modern mathematics, zero is usaly defined as the
> empty set. The empty set contains nothing, but it isn't nothing
> itself. Otherwise the empty set would be the same as the set
> containing the empty set, since they both would contain the same,
> being nothing.

Zero is *the cardinality of* the empty set. The set containing the
empty set has a cardinality of 1.

ChrisA

Jussi Piitulainen

da leggere,
23 giu 2016, 08:06:0123/06/16
a
It also *changes* many things where emptiness *would* make sense. In
particular, it can first *make* a thing empty and then happily declare
it not empty. Not good.

Is "sq" mnemonic for something?

Antoon Pardon

da leggere,
23 giu 2016, 08:09:2623/06/16
a
Op 23-06-16 om 13:45 schreef Chris Angelico:
In modern set theory where the integers are defined as specific kind
of sets, zero *is* the empty set.

--
Antoon.

Chris Angelico

da leggere,
23 giu 2016, 08:14:1023/06/16
a
On Thu, Jun 23, 2016 at 10:05 PM, Jussi Piitulainen
<jussi.pi...@helsinki.fi> wrote:
> Is "sq" mnemonic for something?

Presumably "sequence", which fits the other assumption that you noted:
that calling 'iter' on it will produce a non-destructive iterator.

I hope that code is never used on older Pythons that don't have
exception chaining, given that it has a bare except in it. Actually, I
hope that code is never used at all.

ChrisA

Andreas Röhler

da leggere,
23 giu 2016, 08:18:2823/06/16
a
Modes are like waves. If one wave arrives being "modern", lets watch out
for the next.

There not just one set-theory, math is neither revealed nor received on
some mount - even if the notion of truth has some theological
connotations ;)

Steven D'Aprano

da leggere,
23 giu 2016, 08:37:5423/06/16
a
On Thu, 23 Jun 2016 08:21 pm, Antoon Pardon wrote:

> Op 23-06-16 om 11:39 schreef Steven D'Aprano:
[...]
>> To decide on a branch, you don't need an actual bool, anything capable of
>> acting like a bool will do. As a language design, ALL objects are capable
>> of acting like a bool. Python has a specific protocol in place for
>> deciding whether an object quacks like a bool:
>
> But an object acting like a bool, doesn't mean this bool behaviour makes
> the disctinction you actually need.

Um... okay?

I'm not really sure I understand the point you think your making. Lists and
tuples can be exchanged in many duck-typing situations, but if you need
something with an in-place sort method, you can't use a tuple. That's a
given. If you need some feature that isn't offered by truthiness, you can't
use truthiness to detect that feature. It seems hardly worth mentioning.


> Python tempts people to rely on those
> truthy values, because it saves typing is pythonic and it works for the
> moment and then something unexpected gets passed through and you find
> yourself chasing a very illusive bug.

You keep saying that, but I've never seen it happen. I've seen cases where
people have been surprised by the unexpected truthiness of an object ("I
expected an exhausted iterator to be false, but it was true"), but that's
not what you seem to be describing.

To be honest, I'm not sure what you are describing. Your explanation is
maddeningly vague. Since bools offer a *very small* API (beyond what they
also offer as a subclass of int), I cannot imagine what unexpected thing
you might get passed in that leads to "a very illusive bug".

The bottom line is, bools offer only a single major API[1]: are they truthy,
or falsey? What else can do you with them? Nothing. They support
conditional branches, and boolean operators "or" and "and". That's all.
They don't have methods to call, or attributes to set. You can use a bool
to take the if branch, or the else branch, and that's effectively all.

Since *all* objects support that same bool API, what can you *possibly* be
passed in place of a bool that fails to work?

I acknowledge, cheerfully, that there might be a mismatch between what you
expect and what the object actually does. "I expect empty containers to be
falsey, and non-empty ones to be truthy; but this RedBlackTree object is
always false even if it has many items; and this SortedDict is always true
even when it is empty."

That's a nuisance and a pain when it happens, but it's arguably a bug in the
object or at least a misfeature, and besides that's the risk when you
duck-type. You're trusting the object that you get to behave like the
object you expect, or it will break things.

(An object with a misbehaving __bool__ is no better or worse than an object
with a misbehaving sort() method, or __add__ method.)

So I'm not really sure what you are trying to describe. I guess it might be
something like this:

def spam(alist):
if alist:
process(alist)
else:
print("empty list")


If you pass 1 instead of an actual list, then you don't get an error until
somewhere inside process(). Potentially far, far away. So you want to
write:

def spam(alist):
if len(alist):
process(alist) # requires an actual list
else:
print("empty list")


and now calling spam(1) will raise immediately. Great.

But that's not really anything to do with *bools* specifically. If you call
spam() with a dict, or a set, or a tuple, or a RedBlackTree, any other
object with a length, you're no better off. If you absolutely need a list,
and nothing else, then you have to type-check.

In practice, I don't see how truthy/falsey objects lead to more or worse
bugs than any other form of dynamic typing.

To me, your position is equivalent to saying that dynamic typing and
duck-typing is really great, except for len(). len() should absolutely only
work on lists, and nothing else, so any time you want to get the length of
an object, you must work with real lists, not listy sequences:

if len(list(mystring)) > 20: ...

print(len(list(mydict.keys())), "items")


etc. Substitute "bool" for "len" and you might understand how I feel about
your position.


[...]
>> Somehow I doubt that you write three-state logic everywhere:
>
> Since I wrote above the I *sometimes* found this need. You may
> safely assume I don't write it everywhere.

Fair enough.




[1] I exclude minor things like repr(True), and the fact that they are
subclassed from int.


--
Steven

Random832

da leggere,
23 giu 2016, 09:18:2423/06/16
a
On Thu, Jun 23, 2016, at 02:34, Andreas Röhler wrote:
> Indeed, why should the result of 4 - 4 have a different truth-value
> than 4 - 3 ? This implementation seems to be a legacy from languages
> without boolean types.

A set which included Python until version 2.3.

Antoon Pardon

da leggere,
23 giu 2016, 09:25:3123/06/16
a
Op 23-06-16 om 14:37 schreef Steven D'Aprano:

> So I'm not really sure what you are trying to describe. I guess it might be
> something like this:
>
> def spam(alist):
> if alist:
> process(alist)
> else:
> print("empty list")
>
>
> If you pass 1 instead of an actual list, then you don't get an error until
> somewhere inside process(). Potentially far, far away. So you want to
> write:
>
> def spam(alist):
> if len(alist):
> process(alist) # requires an actual list
> else:
> print("empty list")
>
>
> and now calling spam(1) will raise immediately. Great.
>
> But that's not really anything to do with *bools* specifically. If you call
> spam() with a dict, or a set, or a tuple, or a RedBlackTree, any other
> object with a length, you're no better off. If you absolutely need a list,
> and nothing else, then you have to type-check.

Yes it has to do with the booly nature of python objects. The fact that your
examples still allows for bugs, doesn't contradict it already cathes a lot
of bugs. So yes I'm better of even if I am not completly save. Encouraging
the user to write explicit test, will detect bugs sooner and will make
it more probable the code behaves as expected even when the tests are done
one an unexpected kind of object.

> In practice, I don't see how truthy/falsey objects lead to more or worse
> bugs than any other form of dynamic typing.

Sure, this from a language that states that explicit is better than implicit.
The truthy/falsy objects encourage people to be implicit and thus allowing
a lot of things to pass that were originally not though off.

> To me, your position is equivalent to saying that dynamic typing and
> duck-typing is really great, except for len(). len() should absolutely only
> work on lists, and nothing else, so any time you want to get the length of
> an object, you must work with real lists, not listy sequences:
>
> if len(list(mystring)) > 20: ...
>
> print(len(list(mydict.keys())), "items")
>
>
> etc. Substitute "bool" for "len" and you might understand how I feel about
> your position.

IMO, bool is like you would give any object a lengthy nature and so having any
object also behave like a tuple with the object as it's only item. Then bool and
len would be similar.

--
Antoon.

Random832

da leggere,
23 giu 2016, 09:26:5323/06/16
a
On Thu, Jun 23, 2016, at 08:37, Steven D'Aprano wrote:
> You keep saying that, but I've never seen it happen. I've seen cases
> where people have been surprised by the unexpected truthiness of an
> object ("I expected an exhausted iterator to be false, but it was
> true"), but that's not what you seem to be describing.

I suspect that he's referring to cases like
http://bugs.python.org/issue4945 where a set of flags that are expected
to be bool under normal circumstances are interchangeably tested with
==, is, boolean checks, and the inversion of any of those.

If you test with "== True", then you treat 2 as non-truthy. If you test
with "is True", then you treat 1 as non-truthy. And the reverse of
either may treat 0 as truthy. If you mix and match any truth-test (e.g.
"== True") with anything that is not its opposite ("!= True", not e.g.
"== False") you may end up with situations where neither branch was
taken and your result is an unexpected state.

I don't actually agree with him that the object being passed in can be
blamed for this class of error.

It also occurs to me you could conceivably run into problems if you use
a passed-in mutable object as a flag to be tested multiple times.

> The bottom line is, bools offer only a single major API[1]: are they
> truthy, or falsey? What else can do you with them? Nothing. They
> support conditional branches, and boolean operators "or" and "and".
> That's all. They don't have methods to call, or attributes to set. You
> can use a bool to take the if branch, or the else branch, and that's
> effectively all.

Don't forget, they're integers valued 0 and 1. So you can multiply it by
a number to get 0 or that number. I recently did so (in a code golf
challenge, not serious code). You can sum an iterable of them to get a
count of true items.

Chris Angelico

da leggere,
23 giu 2016, 11:49:4623/06/16
a
On Thu, Jun 23, 2016 at 10:37 PM, Steven D'Aprano <st...@pearwood.info> wrote:
> I acknowledge, cheerfully, that there might be a mismatch between what you
> expect and what the object actually does. "I expect empty containers to be
> falsey, and non-empty ones to be truthy; but this RedBlackTree object is
> always false even if it has many items; and this SortedDict is always true
> even when it is empty."
>
> That's a nuisance and a pain when it happens, but it's arguably a bug in the
> object or at least a misfeature...

As evidenced by the change to time truthiness, yes, that's the
object's fault. If your RedBlackTree object were always *true*, I'd
call it a missing feature ("please add a __bool__ that distinguishes
empty trees from trees with content"), but always *false* would be a
bug. A SortedDict implies by its name that it should be extremely
dict-like, so that would be a strong argument for its truthiness to
follow a dict's. Either way, the misbehaviour gets pointed back at the
object in question.

ChrisA

Steven D'Aprano

da leggere,
23 giu 2016, 12:43:1523/06/16
a
On Thu, 23 Jun 2016 11:26 pm, Random832 wrote:

> On Thu, Jun 23, 2016, at 08:37, Steven D'Aprano wrote:
>> You keep saying that, but I've never seen it happen. I've seen cases
>> where people have been surprised by the unexpected truthiness of an
>> object ("I expected an exhausted iterator to be false, but it was
>> true"), but that's not what you seem to be describing.
>
> I suspect that he's referring to cases like
> http://bugs.python.org/issue4945 where a set of flags that are expected
> to be bool under normal circumstances are interchangeably tested with
> ==, is, boolean checks, and the inversion of any of those.
>
> If you test with "== True", then you treat 2 as non-truthy. If you test
> with "is True", then you treat 1 as non-truthy. And the reverse of
> either may treat 0 as truthy. If you mix and match any truth-test (e.g.
> "== True") with anything that is not its opposite ("!= True", not e.g.
> "== False") you may end up with situations where neither branch was
> taken and your result is an unexpected state.

Yeah, we can write crap code in Python if you try :-)

> I don't actually agree with him that the object being passed in can be
> blamed for this class of error.

Nor do I. I think that's a clear case where the solution is to stop writing
awful code.

We've all gone through a period were the nicest thing one might say about
our coding is "you don't really understand what you are doing". Some of my
earliest code was nearly as bad.


> It also occurs to me you could conceivably run into problems if you use
> a passed-in mutable object as a flag to be tested multiple times.

Indeed, but I expect that's more of a theoretical risk than a practical
risk. And, who knows, somebody might find a use for it, to win a bet, for a
code golf competition, or just because they like writing "clever" code:

flag = []
if condition:
flag.append(None)
else:
flag.pop()

Could be useful. But beware of overly clever code.


>> The bottom line is, bools offer only a single major API[1]: are they
>> truthy, or falsey? What else can do you with them? Nothing. They
>> support conditional branches, and boolean operators "or" and "and".
>> That's all. They don't have methods to call, or attributes to set. You
>> can use a bool to take the if branch, or the else branch, and that's
>> effectively all.
>
> Don't forget, they're integers valued 0 and 1. So you can multiply it by
> a number to get 0 or that number. I recently did so (in a code golf
> challenge, not serious code). You can sum an iterable of them to get a
> count of true items.

I would never forget they're also ints. I think I even mentioned that in the
footnote.




--
Steven

Lawrence D’Oliveiro

da leggere,
25 giu 2016, 01:38:5425/06/16
a
On Thursday, June 23, 2016 at 9:57:35 PM UTC+12, Marko Rauhamaa wrote:
> Lawrence D’Oliveiro:
>
>> On Thursday, June 23, 2016 at 9:11:05 PM UTC+12, Marko Rauhamaa wrote:
>>> The __len__ method is not guaranteed to execute in O(1).
>>
>> So what is?
>
> The __bool__ method is the appropriate place to implement an efficient
> emptiness check. It might not be O(1) but it will be the most efficient
> way to check for emptiness, or the class is badly implemented.

Saying “or the class is badly implemented” sounds like circular reasoning...

Jussi Piitulainen

da leggere,
25 giu 2016, 02:46:2425/06/16
a
What are you thinking? If there's a better way to implement __bool__,
why shouldn't that better way have been used?

Marko Rauhamaa

da leggere,
25 giu 2016, 04:56:5125/06/16
a
Steven D'Aprano <st...@pearwood.info>:

> So we have falsey values:
>
> - None
> - zeroes (0, 0.0, 0j, etc)
> - empty dict {}
> - empty sets and frozensets
> - empty strings '' and b'' (in Python 2: u'' and '')
> - empty lists, tuples and other sequences
>
> and truthy values:
>
> - object
> - non-zero numbers
> - non-empty dicts
> - non-empty sets and frozensets
> - non-empty strings
> - non-empty sequences

It might be more descriptive to call those polar opposites "naughty" and
"nice." Or maybe "hollow" and "puffy."


Marko

Gregory Ewing

da leggere,
25 giu 2016, 19:02:1025/06/16
a
Marko Rauhamaa wrote:

> The pile originally had -4 coconuts. The first sailor threw one to
> the monkey, leaving -5 coconuts in the pile. He took his share (-1
> coconut) out and put the remaining -4 coconuts back in the big pile.

Sounds a bit like Hawking radiation. A coconut-anticoconut
pair is created, and before they can recombine, the monkey
grabs the coconut, leaving the sailor with the anticoconut.

Unfortunately, it's pointless fot the sailor to eat the
anticocounut, as it would ony make him hungrier, and the
coconut is now inside the monkey's event horizon, never to
be seen again.

--
Greg

Rustom Mody

da leggere,
29 giu 2016, 06:22:0029/06/16
a
Moved from thread "Assignment Versus Equality" where this is less relevant
============


On Wednesday, June 29, 2016 at 8:06:10 AM UTC+5:30, Steven D'Aprano wrote:
> On Tue, 28 Jun 2016 12:10 am, Rustom Mody wrote:
>
> > Analogy: Python's bool as 1½-class because bool came into python a good
> > decade after python and breaking old code is a bigger issue than fixing
> > control constructs to be bool-strict
>
> That analogy fails because Python bools being implemented as ints is not a
> bug to be fixed, but a useful feature.
>
> There are downsides, of course, but there are also benefits. It comes down
> to a matter of personal preference whether you think that bools should be
> abstract True/False values or concrete 1/0 values. Neither decision is
> clearly wrong, it's a matter of what you value.
>
> Whereas some decisions are just dumb:
>
> https://www.jwz.org/blog/2010/10/every-day-i-learn-something-new-and-stupid/

When we were kids we used to have 'pillow-fights' -- such fun!

So if we are in a link-pillow-fight here is a link
https://mail.python.org/pipermail/python-ideas/2016-June/040780.html
in which python-dev Nick Coghlan answers the question:

> Q: ...supporting arithmetical operations (1+True==2) was a primary
> intention, in which case my question is "why?".
>
> Nick: The inheritance from int meant the default behaviour was to support
> type-promoting integer arithmetic operations in addition to bitwise
> arithmetic.
>
> That changes the question from "Why support that?" to "Why do the extra
> design, documentation and implementation work needed to prevent that?".
>
> The fact that "1 + True == 2" is surprising hasn't proven to be enough to
> motivate anyone to define the precise subset of operations they want to
> prevent, and then make the case for those restrictions as Python's native
> behaviour.


Well enough of link-ing.

There are many aspects of bool's ½-assed status as a legitimate bool-type
of which 1+True==2 is a silly but not very significant/expensive consequence.

More significant...

Steven D'Aprano wrote:

> So we have falsey values:
>
> - None
> - zeroes (0, 0.0, 0j, etc)
> - empty dict {}
> - empty sets and frozensets
> - empty strings '' and b'' (in Python 2: u'' and '')
> - empty lists, tuples and other sequences
>
> and truthy values:
>
> - object
> - non-zero numbers
> - non-empty dicts
> - non-empty sets and frozensets
> - non-empty strings
> - non-empty sequences
>
> This is an improvement over other languages like Javascript, Ruby, etc where
> the division between truthy and falsey appears to be fairly arbitrary.

Likewise and more strongly

Chris wrote :
> If your RedBlackTree object were always *true*, I'd
> call it a missing feature ("please add a __bool__ that distinguishes
> empty trees from trees with content"), but always *false* would be a
> bug. A SortedDict implies by its name that it should be extremely
> dict-like, so that would be a strong argument for its truthiness to
> follow a dict's. Either way, the misbehaviour gets pointed back at the
> object in question.

And Marko wrote:
> I don't particularly like Python's falsey/truthy semantics,
> but I can live with it. The biggest problem I have with it is the
> absence of an emptiness predicate. I'd like to be able to write:

<elsewhere>

> The point is, Python has already declared that __bool__ is the
> canonical emptiness checker. You could even say that it's the
> principal purpose of the __bool__ method.

In short,
- Steven hints that empty/non-empty is some sort of *generic* property of data structures
- Chris strengthens that to include types outside of builtins -- Red-Black trees
- Marko (thankfully adding the I dont like) connects emptiness to the dunder
__bool__

So here's some questions for the bool-fans

Please show me how we would define __bool__ for

1. Graphs -- the kind mathematicians define with "Let G =(V,E) be a graph..."

2. Automata which in a way are special kinds of graphs

3. Regular Expressions which mathematically are related to automata
And pragmatically are (more) present in python than the first two

It may (or may not) be helpful to pretend that python which already has
a regexp module/type also has explicit regexp syntax a la Perl.

Chris Angelico

da leggere,
29 giu 2016, 07:07:0129/06/16
a
On Wed, Jun 29, 2016 at 8:21 PM, Rustom Mody <rusto...@gmail.com> wrote:
>
> Please show me how we would define __bool__ for
>
> 1. Graphs -- the kind mathematicians define with "Let G =(V,E) be a graph..."
>
> 2. Automata which in a way are special kinds of graphs
>
> 3. Regular Expressions which mathematically are related to automata
> And pragmatically are (more) present in python than the first two
>
> It may (or may not) be helpful to pretend that python which already has
> a regexp module/type also has explicit regexp syntax a la Perl.

Probably the easiest way, for each of these objects, is to not define
__bool__ at all, or to define it thus:

def __bool__(self):
return True

If an object isn't a container, but is just a "thing", then it is by
definition true. The contrast isn't between [1] and [], but rather
between object() and None. It's perfectly reasonable for an object to
be always true - that's what the default object type does. You could
perhaps argue that a graph can be empty, but unless you're frequently
wanting to distinguish between empty graphs and non-empty graphs, I'd
stick with the default and make them always true. Note, for instance:

>>> bool(re.compile(""))
True

I think that's about as empty as a regex can be, and it's still true.
And regex match objects are always true, too - the match functions
will all return None if there's no match. Not all objects need to be
able to be falsey.

ChrisA

Steven D'Aprano

da leggere,
29 giu 2016, 09:08:1629/06/16
a
On Wed, 29 Jun 2016 08:21 pm, Rustom Mody wrote:

> So if we are in a link-pillow-fight here is a link
> https://mail.python.org/pipermail/python-ideas/2016-June/040780.html
> in which python-dev Nick Coghlan answers the question:
>
>> Q: ...supporting arithmetical operations (1+True==2) was a primary
>> intention, in which case my question is "why?".
>>
>> Nick: The inheritance from int meant the default behaviour was to support
>> type-promoting integer arithmetic operations in addition to bitwise
>> arithmetic.
>>
>> That changes the question from "Why support that?" to "Why do the extra
>> design, documentation and implementation work needed to prevent that?".
>>
>> The fact that "1 + True == 2" is surprising hasn't proven to be enough to
>> motivate anyone to define the precise subset of operations they want to
>> prevent, and then make the case for those restrictions as Python's native
>> behaviour.


Nick is a very senior core developer, and we would be foolish to ignore his
opinion, but that doesn't make his comments gospel.

To Nick, having 1+True return 2 is an accident of implementation, where it
is too much work to prevent it for the minimal gain it would give. And
historically, that was Guido's attitude back when Python gained a bool
type.

(Initially Python gained to pseudo-constants, True and False, set equal to 1
and 0; then in the following release it gained a built-in type bool that
subclassed int, with exactly two instances, True and False.)

But it is my argument that with (roughly) ten years of experience with us,
we can say that 1+True == 2 is not just an unfortunate accident of
implementation that we are forced to live with because nobody wants to do
the work to correct it. Rather, it is a useful and desirable feature. If I
were designing a new language from scratch, I would probably follow
Python's lead and use an int subclass for bools.

As I said before, this isn't to dispute or deny the fact that bools-as-ints
have unfortunate consequences. But they have useful consequences too, and
in my opinion they outweigh the bad ones.

If you disagree, okay, you disagree. I like broccoli and hate streaky bacon,
others feel the opposite way. I'm lucky that Python, due to historical
accident, ended up working the way I prefer. When you design your own
language, you can make it work the way you prefer.


[...]
> More significant...
>
> Steven D'Aprano wrote:
>
>> So we have falsey values:

Note that the question of truthy/falsey duck-typed bools is independent of
whether bools are abstract flags or concrete ints. A language could:

- have a dedicated, abstract bool type, like Pascal does;

- completely do without a dedicated bool type, and just have truthy/falsey
values, like Python 1.5 did;

- allow all values to be treated as truthy/falsey values, but have a
concrete (int-subclass) bool type as the canonical true/false, like Python
2 & 3 does;

- allow all values to be treated as truthy/falsey values, but have an
abstract bool type as the canonical true/false, like Javascript does.

So the question of truthy/falsey values is orthogonal to the question of
whether bool should inherit from int.


> In short,
> - Steven hints that empty/non-empty is some sort of *generic* property of
> data structures - Chris strengthens that to include types outside of
> builtins -- Red-Black trees - Marko (thankfully adding the I dont like)
> connects emptiness to the dunder __bool__

It's not just a hint. Python has a convention that empty collections should
be treated as falsey; likewise empty sequences; likewise "empty" numbers.
And non-empty ones should be treated as truthy. This is built into the way
the interpreter decides whether something is truthy or falsey.

Given:

if spam: ...
else: ...


Python decides which branch to take as follows:

- if spam has a __len__ method, and spam.__len__() returns 0, then spam is
falsey and the `else` branch is taken;

- if spam.__len__() returns a non-zero number, then spam is truthy and the
`if` branch is taken;

- otherwise, if spam has a __nonzero__ method (__bool__ in Python 3), if it
returns a falsey value, then spam is falsey;

- but if it returns a truthy value, then spam is truthy;

- and if spam has neither a __len__ nor a __nonzero__ / __bool__ method,
then by default it is truthy.



> So here's some questions for the bool-fans
>
> Please show me how we would define __bool__ for
>
> 1. Graphs -- the kind mathematicians define with "Let G =(V,E) be a
> graph..."

I would make the empty graph (zero nodes) falsey, and non-empty graphs (one
or more nodes) truthy.


> 2. Automata which in a way are special kinds of graphs

As above.


> 3. Regular Expressions which mathematically are related to automata
> And pragmatically are (more) present in python than the first two

Can you even have an empty regular expression? What does it match? Possibly
nothing at all.

Ideally, I would have the empty regular expression be falsey, and all others
truthy, but I wouldn't be too upset if all regexes were True.




--
Steven
“Cheer up,” they said, “things could be worse.” So I cheered up, and sure
enough, things got worse.

Rustom Mody

da leggere,
29 giu 2016, 09:30:5029/06/16
a
Salutations!

Chris fell into the trap -- if I take his "" as
> I think that's about as empty as a regex can be,

You have not fallen in... Admirable!
What you need is a negative lookahead empty re (?!)


>>> re.findall("", "")
['']
>>> re.findall("(?!)", "")
[]
>>> re.findall("(?!)", "a")
[]
>>> re.findall("", "a")
['', '']
>>>

The other answers -- graphs and automata -- are questionable and/or wrong

You may wish to think about them again?

Grant Edwards

da leggere,
29 giu 2016, 11:01:1129/06/16
a
On 2016-06-29, Steven D'Aprano <st...@pearwood.info> wrote:

> To Nick, having 1+True return 2 is an accident of implementation,

My recollection is that it was not an accident of impliementation. It
was an intentional descision to provide compatibility with many years
worth of programs that were written before there was either a boolean
type or built-in True/False integer values.

Those programs often did this at the top:

True = 1
False = 0

Having True and False evaluate as 1 and 0 in an integer expression
context guaranteed that those programs would to continue to work with
minimal changes.

--
Grant Edwards grant.b.edwards Yow! Life is a POPULARITY
at CONTEST! I'm REFRESHINGLY
gmail.com CANDID!!

Jon Ribbens

da leggere,
29 giu 2016, 11:05:3829/06/16
a
On 2016-06-29, Grant Edwards <grant.b...@gmail.com> wrote:
> On 2016-06-29, Steven D'Aprano <st...@pearwood.info> wrote:
>> To Nick, having 1+True return 2 is an accident of implementation,
>
> My recollection is that it was not an accident of impliementation. It
> was an intentional descision to provide compatibility with many years
> worth of programs that were written before there was either a boolean
> type or built-in True/False integer values.
>
> Those programs often did this at the top:
>
> True = 1
> False = 0
>
> Having True and False evaluate as 1 and 0 in an integer expression
> context guaranteed that those programs would to continue to work with
> minimal changes.

I thought it was more for things like this:

"%d widget%s" % (widgets, (widgets != 1) * "s")

i.e. using boolean expressions as numeric expressions, rather than
explicitly setting the identifiers True and False to be numbers.

Steven D'Aprano

da leggere,
29 giu 2016, 19:40:4129/06/16
a
On Wed, 29 Jun 2016 11:30 pm, Rustom Mody wrote:

> The other answers -- graphs and automata -- are questionable and/or wrong
>
> You may wish to think about them again?

You may wish to justify your assertion.

Steven D'Aprano

da leggere,
29 giu 2016, 19:45:0029/06/16
a
On Thu, 30 Jun 2016 01:00 am, Grant Edwards wrote:

> On 2016-06-29, Steven D'Aprano <st...@pearwood.info> wrote:
>
>> To Nick, having 1+True return 2 is an accident of implementation,
>
> My recollection is that it was not an accident of impliementation. It
> was an intentional descision to provide compatibility with many years
> worth of programs that were written before there was either a boolean
> type or built-in True/False integer values.

You're right ... I was thinking accident of history and wrote accident of
implementation :-(

Rustom Mody

da leggere,
30 giu 2016, 12:01:5030/06/16
a
On Thursday, June 30, 2016 at 5:10:41 AM UTC+5:30, Steven D'Aprano wrote:
> On Wed, 29 Jun 2016 11:30 pm, Rustom Mody wrote:
>
> > The other answers -- graphs and automata -- are questionable and/or wrong
> >
> > You may wish to think about them again?
>
> You may wish to justify your assertion.

> Rusi wrote
> > Please show me how we would define __bool__ for
> >
> > 1. Graphs -- the kind mathematicians define with "Let G =(V,E) be a
> > graph..."

> I would make the empty graph (zero nodes) falsey, and non-empty graphs (one
> or more nodes) truthy.


> 2. Automata which in a way are special kinds of graphs

As above.

From https://en.wikipedia.org/wiki/Finite-state_machine#Mathematical_model

A deterministic finite state machine (acceptor) is a quintuple
(Σ, S, δ, s₀, F), where:

Σ is the input alphabet (a finite, non-empty set of symbols).
S is a finite, non-empty set of states.
δ is the state-transition function: δ : S × Σ → S
s₀ is an initial state, an element of S.
F is the set of final states, a (possibly empty) subset of S.


Put in more succinct form:

If we take Σ (alphabet) and S (state-set) as given (ie independent) types
we can specify the dependence of s₀ δ and F as the following type_signature:

dfa(Σ, S) = s₀ : S
δ : S × Σ → S
F : ℘ S

Since s₀ : S is part of the dfa spec, S cant be empty

Can Σ (alphabet) be empty??
I'm not clear on that one...

Steven D'Aprano

da leggere,
30 giu 2016, 13:22:5030/06/16
a
On Fri, 1 Jul 2016 02:01 am, Rustom Mody wrote:

> On Thursday, June 30, 2016 at 5:10:41 AM UTC+5:30, Steven D'Aprano wrote:
>> On Wed, 29 Jun 2016 11:30 pm, Rustom Mody wrote:
>>
>> > The other answers -- graphs and automata -- are questionable and/or
>> > wrong
>> >
>> > You may wish to think about them again?
>>
>> You may wish to justify your assertion.

[snip]

Okay, if you think that automata cannot be empty, I'll accept that. In that
case, then I'll change my answer and say that __bool__ for automata should
simply return True. All automata should be truthy.

Rustom Mody

da leggere,
16 lug 2016, 01:48:4816/07/16
a
On Thursday, June 30, 2016 at 10:52:50 PM UTC+5:30, Steven D'Aprano wrote:
> Okay, if you think that automata cannot be empty, I'll accept that. In that
> case, then I'll change my answer and say that __bool__ for automata should
> simply return True. All automata should be truthy.
>

I am not sure with what tone of voice you are saying that

If ... “return True” is about as good -- ie useful -- as (say)

def __bool__(self):
from random import random
return int(2*random())

then I think we agree

But then there is a well-established behavior pattern in python
captured by the contexts that raise AttributeError/NameError/TypeError etc
viz For things that are undefined we are told politely they are undefined

IOW Why say something is useless and define it rather than just leave undefined
something that is ill-defined.

If on the other hand you are giving that “return True”as a serious useful definition?

If both you and Chris tripped up on a right definition of an “empty” automaton
and regex respectively, I believe it demonstrates that getting boolishness
for an arbitrary type right is at least non-trivial. [FWIW My belief: In
general its nonsensical]

Rustom Mody

da leggere,
16 lug 2016, 01:59:0216/07/16
a

From other thread:

On Saturday, July 16, 2016 at 9:50:13 AM UTC+5:30, Ethan Furman wrote:
> On 07/15/2016 09:04 PM, Rustom Mody wrote:
>
> > Just that suggesting that python's bool notion is straightforward is an
> > unnecessary lie – especially to newbies.
>
> Python's boolean concept is as simple as it gets -- what is not straightforward about it?

And to expand on my

On Saturday, July 16, 2016 at 11:18:48 AM UTC+5:30, Rustom Mody wrote:
> FWIW My belief: In general its nonsensical

C's 0 is false; rest-of-universe is true is a mess
Python increases the mess by making the false-y candidates also non-singleton

This seems to work for container-like objects like lists,strings,sets, etc
with None and 0 being somewhat elliptical analogues

But when we allow __bool__ to be available for any and every thing and give
it some implicit random definition, this is just plain nonsense.

[What is the bool-nature -- aka Buddha-nature -- of graphs question remains yet answered]

Steven D'Aprano

da leggere,
16 lug 2016, 05:14:5816/07/16
a
On Sat, 16 Jul 2016 03:58 pm, Rustom Mody wrote:

>
> From other thread:
>
> On Saturday, July 16, 2016 at 9:50:13 AM UTC+5:30, Ethan Furman wrote:
>> On 07/15/2016 09:04 PM, Rustom Mody wrote:
>>
>> > Just that suggesting that python's bool notion is straightforward is an
>> > unnecessary lie – especially to newbies.
>>
>> Python's boolean concept is as simple as it gets -- what is not
>> straightforward about it?
>
> And to expand on my
>
> On Saturday, July 16, 2016 at 11:18:48 AM UTC+5:30, Rustom Mody wrote:
>> FWIW My belief: In general its nonsensical
>
> C's 0 is false; rest-of-universe is true is a mess

Really? In what way?

As far as I know, C requires bools to be ints, not arbitrary values, and the
compiler will enforce that. What mess do you get from C allowing 2 as well
as 1 to be treated as true?


> Python increases the mess by making the false-y candidates also
> non-singleton

So you say, but you haven't demonstrated this.


> This seems to work for container-like objects like lists,strings,sets, etc
> with None and 0 being somewhat elliptical analogues

Right. This is a good, concrete, practical example that duck-typed truthy
and falsey values DOES work: it works for numbers, it works for strings, it
works for containers.


> But when we allow __bool__ to be available for any and every thing and
> give it some implicit random definition, this is just plain nonsense.
>
> [What is the bool-nature -- aka Buddha-nature -- of graphs question
> [remains yet answered]

No, I already answered that in the earlier thread. Graphs are collections or
sequences of nodes. An empty graph (one with zero nodes) should be falsey;
all other graphs (one or more nodes) should be truthy.

I say "should", not "must". Practicality beats purity: if your application
has a specific need for (let's say) a graph with exactly two cycles to be
considered falsey, and all others to be truthy, then you are free to define
your graph type that way. As an internal application-only class, that's
probably okay, but as a generic graph type in a library, it's probably a
bad idea.

Steven D'Aprano

da leggere,
16 lug 2016, 06:17:0116/07/16
a
On Sat, 16 Jul 2016 03:48 pm, Rustom Mody wrote:

> On Thursday, June 30, 2016 at 10:52:50 PM UTC+5:30, Steven D'Aprano wrote:
>> Okay, if you think that automata cannot be empty, I'll accept that. In
>> that case, then I'll change my answer and say that __bool__ for automata
>> should simply return True. All automata should be truthy.
>>
>
> I am not sure with what tone of voice you are saying that

A standard, non-sarcastic tone of voice.


> If ... “return True” is about as good -- ie useful -- as (say)
>
> def __bool__(self):
> from random import random
> return int(2*random())
>
> then I think we agree

No, I don't agree with that. "Emptiness" or "zeroness" or "falsity" doesn't
necessarily make sense for every single kind of object. If we were
modelling (say) Employees, then I would probably model all Employees as
truthy. That's easy to do: all objects are truthy by default, so I don't
have to do a thing.

If there is some concept of an "empty/null/do-nothing" automata, then I
would consider making such null automata falsey. But I'm no sure I would
care enough to bother. For example, functions are all truthy, even
do-nothing functions.


> But then there is a well-established behavior pattern in python
> captured by the contexts that raise AttributeError/NameError/TypeError etc
> viz For things that are undefined we are told politely they are undefined
>
> IOW Why say something is useless and define it rather than just leave
> undefined something that is ill-defined.

You are forgetting that you're not necessarily encountering automata in a
context where you are expecting an automata and nothing else:

x = Turing_Machine(foo)
if x:
x.run()
else:
x.blibbet()


You may encounter one in code that is expecting arbitrary objects, without
caring whether they are floats or HTTPServers or re.MatchObjects or
automata or Employees or something else:

for obj in bunch_of_objects:
if obj:
turn_left()
else:
turn_right()


There's an argument in favour of Pascal-style "true booleans" that require
you to use True and False *only* in boolean contexts; and there's an
argument in favour of Python's truthiness where any object can duck-type in
a bool context; but what doesn't make sense is to have *some* objects be
usable as true/false, forcing you to write code like this everywhere you
have to deal with arbitrary truthy objects:


for obj in bunch_of_objects:
try:
# Okay for collections, sequences, ints, floats, None,
# FooManagers, HttpServers, Dogs, Horses, Pizzashops, etc.
flag = bool(obj)
except TypeError:
# But not okay for Automata, Employees, Cats, PrintFormatters, etc.
flag = True # default to true, say
if flag:
turn_left()
else:
turn_right()


That's just awful language design. You should have either two booleans only,
or all objects should be booleans.



> If on the other hand you are giving that “return True”as a serious useful
> definition?

Sure. An automata is an object, and by default, all objects are "something"
and hence truthy. That's the "no-brainer" answer, it requires no
justification at all. If you think the answer should be something else,
*that* is what needs justification. Why shouldn't it be truthy?


> If both you and Chris tripped up on a right definition of an “empty”
> automaton and regex respectively, I believe it demonstrates that getting
> boolishness for an arbitrary type right is at least non-trivial. [FWIW My
> belief: In general its nonsensical]

Firstly, I disagree that I tripped up on anything. You haven't given any
reason to think that Automata objects shouldn't be truthy, and even if you
do, isn't that just a matter of opinion?

But in general, deciding on whether an arbitrary object should be truthy or
falsey is not hard, and most of the time you don't have to do a thing to
get the right behaviour.

- Does the object represent a collection or sequence? If so, then the right
behaviour is to delegate to `len(obj) != 0`.

- Does the object represent a number? If so, then the right behaviour is to
delegate to `obj != 0`.

- Does the object represent (in some sense) nothing rather than something?
That is, is it a reification of "there's nothing here"? E.g. something like
None in Python, null/nil pointers, Void, or Undefined. Then it should be
falsey.

- Otherwise, it represents something rather than nothing, and unless you
have pressing reason to do otherwise, it should be truthy.

Chris Angelico

da leggere,
16 lug 2016, 06:46:3416/07/16
a
On Sat, Jul 16, 2016 at 8:16 PM, Steven D'Aprano <st...@pearwood.info> wrote:
>> If both you and Chris tripped up on a right definition of an “empty”
>> automaton and regex respectively, I believe it demonstrates that getting
>> boolishness for an arbitrary type right is at least non-trivial. [FWIW My
>> belief: In general its nonsensical]
>
> Firstly, I disagree that I tripped up on anything. You haven't given any
> reason to think that Automata objects shouldn't be truthy, and even if you
> do, isn't that just a matter of opinion?

I also disagree that I "tripped up", but there is room for differing
decisions in API design, and this is one of them. I can't say
perfectly, from my armchair (which I'm not in anyway - way too
cumbersome for a desktop computer), which objects are capable of being
"empty" and which are not. The implementer of the automaton class or
the regex class has to decide what counts as "empty". As Steven says,
the default is that they're all truthy, and onus is on the implementer
to demonstrate that this object is functionally equivalent to 0 or an
empty collection. (And it's possible for ANYONE to get that wrong - cf
timedelta.)

ChrisA

Steven D'Aprano

da leggere,
16 lug 2016, 07:02:2616/07/16
a
On Sat, 16 Jul 2016 08:46 pm, Chris Angelico wrote:

> As Steven says,
> the default is that they're all truthy, and onus is on the implementer
> to demonstrate that this object is functionally equivalent to 0 or an
> empty collection. (And it's possible for ANYONE to get that wrong - cf
> timedelta.)

I think you're thinking of time values, not timedelta values. Until
recently, midnight was considered falsey just because it happened to be
implemented as 0 seconds:

[steve@ando ~]$ python3.3 -c "import datetime;print(bool(datetime.time(0)))"
False
[steve@ando ~]$ python3.6 -c "import datetime;print(bool(datetime.time(0)))"
True

That was a real bug, letting the concrete implementation show through into
the abstract API by accident, but it's corrected now.

timedelta values, being a difference between two times, have a qualitative
difference between delta = 0 and every other value. A difference of zero is
no difference at all, and it makes sense to make that falsey.

Rustom Mody

da leggere,
16 lug 2016, 08:16:1316/07/16
a
Earlier you said:

> > 1. Graphs -- the kind mathematicians define with "Let G =(V,E) be a
> > graph..."
>
> I would make the empty graph (zero nodes) falsey, and non-empty graphs (one
> or more nodes) truthy.
>
>
> > 2. Automata which in a way are special kinds of graphs
>
> As above.


Now you say:

> > If on the other hand you are giving that “return True”as a serious useful
> > definition?
>
> Sure. An automata is an object, and by default, all objects are "something"
> and hence truthy. That's the "no-brainer" answer, it requires no
> justification at all. If you think the answer should be something else,
> *that* is what needs justification. Why shouldn't it be truthy?


How do we put these two together?

Maybe thusly?
https://en.wikibooks.org/wiki/Sufism/Nasrudin#Of_any_two_options_choose_the_third

Rustom Mody

da leggere,
16 lug 2016, 08:34:2516/07/16
a
On Saturday, July 16, 2016 at 4:16:34 PM UTC+5:30, Chris Angelico wrote:
Just to re-iterate what we are talking about (and before you continue
to score self-goals):

You folks — Chris and Steven — likely know a lot more python than I do – no one
questioning that.

You also have a bizarre notion that python's property: “Everything has
auto-bool-nature” IS STRAIGHTFORWARD.

My point of those examples is to show that with such an outlook you will invariably trip up.

Python in fact has a well established rheostat for this:
Simple → Complex → Complicated

If we agree to this bool business being complicated then we are being honest
If we agree to it being complex — well euphemisms are necessary in civilized society I guess
If however you insist its simple, you will trip up.
And the fact that that may be nothing to do with trick questions posed by me is
seen in the other thread where Peter saw a subtle distinction in boolishness
that we all missed.

So yes “Anyone can get that wrong” is a self-goal
You are making my point and then saying you disagree.
With what/whom? Yourself??

Gerald Britton

da leggere,
16 lug 2016, 09:58:4916/07/16
a
>Earlier you said:

>* > 1. Graphs -- the kind mathematicians define with "Let G =(V,E) be a
*>* > graph..."
*> >* I would make the empty graph (zero nodes) falsey, and non-empty
graphs (one
*>* or more nodes) truthy.
*> > >* > 2. Automata which in a way are special kinds of graphs
*> >* As above.
*

>Now you say:

>* > If on the other hand you are giving that “return True”as a serious useful
*>* > definition?
*> >* Sure. An automata is an object, and by default, all objects are
"something"
*>* and hence truthy. That's the "no-brainer" answer, it requires no
*>* justification at all. If you think the answer should be something else,
*>* *that* is what needs justification. Why shouldn't it be truthy?
*

>How do we put these two together>


easy peasy: lists, tuples, dicts etc are also objects. They define
their truthiness by the presence of members. An empty list has a
boolean value of false.

for a custom object, you can accept the default boolean value of true
or override __bool__ so that it returns what you want. So for a graph
G, I'd say if |V| = |E| = 0, G has a boolean value of false.

Maybe thusly?https://en.wikibooks.org/wiki/Sufism/Nasrudin#Of_any_two_options_choose_the_third

------------------------------


- Previous message (by thread): Operator Precedence/Boolean Logic
<https://mail.python.org/pipermail/python-list/2016-July/711778.html>
- Next message (by thread): EuroPython 2016: Recruiting Offers
<https://mail.python.org/pipermail/python-list/2016-July/711769.html>
- *Messages sorted by:* [ date ]
<https://mail.python.org/pipermail/python-list/2016-July/date.html#711777>
[ thread ]
<https://mail.python.org/pipermail/python-list/2016-July/thread.html#711777>
[ subject ]
<https://mail.python.org/pipermail/python-list/2016-July/subject.html#711777>
[ author ]
<https://mail.python.org/pipermail/python-list/2016-July/author.html#711777>

------------------------------
More information about the Python-list mailing list
<https://mail.python.org/mailman/listinfo/python-list>

--
Gerald Britton, MCSE-DP, MVP
LinkedIn Profile: http://ca.linkedin.com/in/geraldbritton

Chris Angelico

da leggere,
16 lug 2016, 10:26:3616/07/16
a
On Sat, Jul 16, 2016 at 9:02 PM, Steven D'Aprano <st...@pearwood.info> wrote:
> On Sat, 16 Jul 2016 08:46 pm, Chris Angelico wrote:
>
>> As Steven says,
>> the default is that they're all truthy, and onus is on the implementer
>> to demonstrate that this object is functionally equivalent to 0 or an
>> empty collection. (And it's possible for ANYONE to get that wrong - cf
>> timedelta.)
>
> I think you're thinking of time values, not timedelta values. Until
> recently, midnight was considered falsey just because it happened to be
> implemented as 0 seconds:
>
> [steve@ando ~]$ python3.3 -c "import datetime;print(bool(datetime.time(0)))"
> False
> [steve@ando ~]$ python3.6 -c "import datetime;print(bool(datetime.time(0)))"
> True
>
> That was a real bug, letting the concrete implementation show through into
> the abstract API by accident, but it's corrected now.
>
> timedelta values, being a difference between two times, have a qualitative
> difference between delta = 0 and every other value. A difference of zero is
> no difference at all, and it makes sense to make that falsey.

Umm, yes. That's the one. Time, not timedelta. My bad. Point still
stands, though - the concept of "midnight" does not truly equate to
"empty" or "zero", and that bug stood for a long time.

ChrisA

Steven D'Aprano

da leggere,
16 lug 2016, 12:27:2316/07/16
a
On Sat, 16 Jul 2016 10:33 pm, Rustom Mody wrote:

> You also have a bizarre notion that python's property: “Everything has
> auto-bool-nature” IS STRAIGHTFORWARD.

That's a very strong claim.

You're not just pointing out that there may be a few old corner cases here
and there where Python's treatment of bools fails to be straightforward, or
is a little harder than it appears at first glance. You're making the claim
that it is BIZARRE (grossly unconventional or unusual, beyond belief,
foolish, laughable, ludicrous, nonsensical, outrageous, ridiculous, crazy)
to think that it might be straightfoward. In other words, that it is
obviously, clearly not-straightforward.

If you really mean your words, and don't wish to step back and make a less
extreme claim, then you ought to be easily able to show that Python's use
of bools hardly ever works. It's clearly a terrible idea, almost every use
of it is a failure, even Blind Freddy can see that it is hard to use and
not straightforward.

The truthiness API is straightforward. Any value or object is usable in a
boolean context, and there is a well-defined protocol for deciding whether
arbitrary objects are considered true or false:

* If the class defined a __nonzero__ (or __bool__ in Python 3) method, then
the truthiness of the object is given by the result of calling that method.

* If there is no __nonzero__ (or __bool__) method, but the class defines
__len__, which returns zero, then the object is deemed falsey, otherwise it
is deemed to be truthy.

* If the class lacks both dunder methods, then the object is deemed truthy.

This should not be hard to understand. So what part of this system is not
straightfoward?


(1) Is it that programming the required dunder methods is not necessarily
trivial for every imaginable object? Nobody said that had to be.


(2) Is it that it may be tricky for the designer of the class to map the
class values/objects into the true/false dichotomy? Python gives a simple
and, yes, straightforward metaphor to use: if an object represents nothing
(an empty container, null, void) then it should be falsey, otherwise it
should be truthy.

But that doesn't mean that every imaginable class trivially maps into that
dichotomy. Suppose we create a tri-state logic class, with three states
Yes, No and Maybe. Obviously Yes should map to True, and No to False. What
should Maybe map to? We may spend many sleepless hours weighing up the pros
and cons of mapping Maybe to True versus Maybe to False. Or we might flip a
coin.

And yes, Rustom, I'm very familiar with the philosophical objections to the
something/nothing distinction. "Is zero truly nothing, or is it some thing
distinct from the absence of any number?" I'm not interested in that
argument. Let the philosophers count angels, but as far as Python code
goes, I'm an intuitionist: if I have zero sheep, that's the same as not
having any sheep, or having no sheep.

I'm more sympathetic to the view that an empty list is different from
absence of a list, therefore it's something, not nothing. Fine, if that's
the way you want to reason, go right ahead and do so when you write your
own language. But in Python, practicality wins, and empty sequences and
collections are treated as "nothing". (It's a metaphor, not a deep
philosophical axiom.)

(3) Is it that sometimes people write code involving boolean contexts that
may not be trivially understood and obviously bug free? Sure they do. So
what? Do you expect perfection of code for every feature?

(4) Or something else? If so, what is your basis for claiming that this is
not straightforward? What part, or parts, is not straightforward?

Steven D'Aprano

da leggere,
16 lug 2016, 12:36:3016/07/16
a
On Sat, 16 Jul 2016 10:15 pm, Rustom Mody wrote:

> Earlier you said:
>
>> > 1. Graphs -- the kind mathematicians define with "Let G =(V,E) be a
>> > graph..."
>>
>> I would make the empty graph (zero nodes) falsey, and non-empty graphs
>> (one or more nodes) truthy.
>>
>>
>> > 2. Automata which in a way are special kinds of graphs
>>
>> As above.

If automata are graphs, and there is a zero-node graph that represents an
automation, then it should be falsey. If there is no such "empty
automation", then there shouldn't be. Was that unclear? If I failed to make
that obvious enough for you to understand, then I apologise.

It may be that you feel that there's no such thing as an empty automation.
Okay, that seems reasonable to me too. One can map functions to
flow-charts, which are a special kind of graph too. But a flow chart with
no elements is no flow chart at all: even the identity function, or the
do-nothing procedure, will be represented by a flow chart with at least one
node. So there are no falsey functions. Maybe there are no falsey automata
either.



> Now you say:
>
>> > If on the other hand you are giving that “return True”as a serious
>> > useful definition?
>>
>> Sure. An automata is an object, and by default, all objects are
>> "something" and hence truthy. That's the "no-brainer" answer, it requires
>> no justification at all. If you think the answer should be something
>> else, *that* is what needs justification. Why shouldn't it be truthy?
>
>
> How do we put these two together?

Um, in the obvious, straightforward way?

What part of my statements is giving you trouble? Should I use smaller
words? Bigger words? Draw a picture?

Automata were *your* idea. I have no concept of what *your* idea of automata
are, except that *you* claim that they are a kind of graph. If you want to
specify the semantics of automata that you consider important in detail,
then perhaps we can decide which ones should be falsey (if any). Otherwise
I'm reduce to talking in generalities, as the question is under-specified.

If there are automata equivalent to the empty graph (graph with no nodes),
then they should be falsey. All others (those equivalent to graphs with one
or more nodes) should be truthy. If you disagree, well, Rustom, it's YOUR
class, you tell me under what conditions you think an automation object
should be considered truthy or falsey.

Mu is not an option. You have to pick one or the other.

MRAB

da leggere,
16 lug 2016, 12:59:0216/07/16
a
On 2016-07-16 17:27, Steven D'Aprano wrote:
> On Sat, 16 Jul 2016 10:33 pm, Rustom Mody wrote:
[snip]

> And yes, Rustom, I'm very familiar with the philosophical objections to the
> something/nothing distinction. "Is zero truly nothing, or is it some thing
> distinct from the absence of any number?" I'm not interested in that
> argument. Let the philosophers count angels, but as far as Python code
> goes, I'm an intuitionist: if I have zero sheep, that's the same as not
> having any sheep, or having no sheep.
>
[snip]

And if you're going to argue that zero is something, then you could also
argue that false is something...

Chris Angelico

da leggere,
16 lug 2016, 13:06:5716/07/16
a
On Sun, Jul 17, 2016 at 2:27 AM, Steven D'Aprano <st...@pearwood.info> wrote:
> If you really mean your words, and don't wish to step back and make a less
> extreme claim, then you ought to be easily able to show that Python's use
> of bools hardly ever works. It's clearly a terrible idea, almost every use
> of it is a failure, even Blind Freddy can see that it is hard to use and
> not straightforward.

Anecdotal, yet important, factoid: When I teach Python to people
who've come from other languages, I explain it as: "In Python,
anything that represents emptiness is false. Everything else is
true.". So far, not a single student has failed to understand this,
and quite a few have thanked me for the simplicity (as if it's
credited to me, rather than just being a reflection of Python's
reality).

> The truthiness API is straightforward. Any value or object is usable in a
> boolean context, and there is a well-defined protocol for deciding whether
> arbitrary objects are considered true or false:
>
> * If the class defined a __nonzero__ (or __bool__ in Python 3) method, then
> the truthiness of the object is given by the result of calling that method.
>
> * If there is no __nonzero__ (or __bool__) method, but the class defines
> __len__, which returns zero, then the object is deemed falsey, otherwise it
> is deemed to be truthy.
>
> * If the class lacks both dunder methods, then the object is deemed truthy.

This isn't how truthiness is generally understood, though. Do you
explain to someone that (1).__bool__() returns True, or do you simply
say that 1, being a non-zero number, is true?

> But that doesn't mean that every imaginable class trivially maps into that
> dichotomy. Suppose we create a tri-state logic class, with three states
> Yes, No and Maybe. Obviously Yes should map to True, and No to False. What
> should Maybe map to? We may spend many sleepless hours weighing up the pros
> and cons of mapping Maybe to True versus Maybe to False. Or we might flip a
> coin.

Maybe can also raise an exception in __bool__ if it likes. Or, to
emphasize the tri-state nature of your logic class, *all* your
instances could raise, with a message saying that "if x:" should be
"if x >= tri.Maybe:" or "if x is tried.and.True" depending on how you
want to handle Maybe.

Ultimately, though, computers don't work with Maybes. They work with
concrete yes/no answers: should I run this code or not? (In
assembly/machine language, probably "should I take this jump or not"
covers it all.) Somewhere along the way, you have to turn that Maybe
in to either True or False, and that should be *before* you're asking
the question "if x:". Perhaps "Maybe" really means "Inherit" (as in
the DeScribe style sheet system; you have a tree of styles, and a
style could say "Bold: True" or "Bold: False", but if it doesn't, it's
shown as "Bold: Maybe" but really means "Bold: Same as parent"), in
which case you resolve it with "while x == tri.Maybe: x =
self.parent.x" before doing the lookups. Or perhaps Maybe means "the
user didn't enter a value", in which case you go with some global
default. Or perhaps it means "the data is too borderline to call this
one", in which case you flip a coin. Actual physical coin, mind, no
simulations here!

> And yes, Rustom, I'm very familiar with the philosophical objections to the
> something/nothing distinction. "Is zero truly nothing, or is it some thing
> distinct from the absence of any number?" I'm not interested in that
> argument. Let the philosophers count angels, but as far as Python code
> goes, I'm an intuitionist: if I have zero sheep, that's the same as not
> having any sheep, or having no sheep.
>
> I'm more sympathetic to the view that an empty list is different from
> absence of a list, therefore it's something, not nothing. Fine, if that's
> the way you want to reason, go right ahead and do so when you write your
> own language. But in Python, practicality wins, and empty sequences and
> collections are treated as "nothing". (It's a metaphor, not a deep
> philosophical axiom.)

Pike took the opposite view - an empty array is still true. Did you
put up a new shopping list? Yes, there's a list there, even though
it's currently empty. Both make sense, and both languages have very
simple definitions of "this is true, that is false". (And both permit
user-defined types to choose whether they're truthy or falsey, so of
course someone somewhere has made a pathological case, guaranteed.)
Python says that having zero sheep is the same as not having any
sheep; Pike says that a box of doughnuts is still a box even when
you've eaten all the doughnuts.

Most importantly, neither of them is "bizarre". (In most practical
usage, it actually works out pretty much the same way.) Rustom, I
await evidence from you that (a) new Python programmers are massively
confused because of the boolification rules, or (b) transitioning
programmers (new to Python but with experience in some other language)
are confused, or (c) that this is more of a bug magnet than comparable
features, while providing less useful functionality. Go! Prove to us.

ChrisA

Rustom Mody

da leggere,
16 lug 2016, 23:43:2916/07/16
a
Heh! A flurry of opinions!
No time right now… other than to say thank you (MRAB) for this little gem:
Likewise Chris’ example of the comparison of Pike and Python alternative
semantics

Chris Angelico

da leggere,
17 lug 2016, 00:05:5717/07/16
a
So if you accept that there are different semantics that all have
validity, can you also accept that Python's model is not "bizarre"?

ChrisA

Rustom Mody

da leggere,
17 lug 2016, 02:45:4017/07/16
a
On Sunday, July 17, 2016 at 9:35:57 AM UTC+5:30, Chris Angelico wrote:
I am sure Chris you can distinguish between:

- Python’s (bool) model is bizarre
- The model “Everything has auto-bool-nature” is bizarre
- The notion « “Everything has auto-bool-nature” is straightforward » is bizarre


My earlier statement (with emphasis in original):
> You also have a bizarre notion that python's property: “Everything has
> auto-bool-nature” IS STRAIGHTFORWARD.

If you like you can take me to task for not being sufficiently punctilious
about quote-marks as I am now.
[And remember your objections to my (mis)use of unicode <wink>]

Rustom Mody

da leggere,
17 lug 2016, 03:00:1117/07/16
a
To add to that:

This is my first post in this thread:
https://mail.python.org/pipermail/python-list/2016-June/710678.html

I dont think I need to change much what is there other than to say this:
A snarky tone is unconducive to a serious discussion.
So I could restate that without the snark… something which I believe I’ve
already done in recent posts

Chris Angelico

da leggere,
17 lug 2016, 03:33:1917/07/16
a
On Sun, Jul 17, 2016 at 4:44 PM, Rustom Mody <rusto...@gmail.com> wrote:
> I am sure Chris you can distinguish between:
>
> - Python’s (bool) model is bizarre
> - The model “Everything has auto-bool-nature” is bizarre
> - The notion « “Everything has auto-bool-nature” is straightforward » is bizarre
>
>
> My earlier statement (with emphasis in original):
>> You also have a bizarre notion that python's property: “Everything has
>> auto-bool-nature” IS STRAIGHTFORWARD.

I can distinguish them, yes. But Python's boolification model is
fundamentally the same as the model "Everything has auto-bool-nature".
So those two aren't really all that different, save that one of them
is language-agnostic.

I understand your third statement, but I posit that these last points
have proven it false. There are clearly a number of viable semantic
systems:

1) REXX and, I think, Pascal: there are two specific values that may
be used in conditionals, and anything else is an error
2) Everything is legal in a conditional, and has a truth value
2a) Pike: 0 is false, every other object is true, unless it defines a
magic method
2b) Python: Empty values and collections are false, everything else is
true, unless it defines a magic method
2c) JavaScript: 0, null, undefined, nan, "", false are false,
everything else is true, including all objects (no magic method
option)
3) Machine code: There are no conditionals - just CPU flags that you
can jump or not jump on.

All of them work. So you could *disagree* with the statement that
Python's model is straight-forward, but you cannot say that this
statement is *bizarre*.

ChrisA

Lawrence D’Oliveiro

da leggere,
17 lug 2016, 03:44:5217/07/16
a
On Sunday, July 17, 2016 at 7:33:19 PM UTC+12, Chris Angelico wrote:
> 1) REXX and, I think, Pascal: there are two specific values that may
> be used in conditionals, and anything else is an error

Worth comparing how two different languages deal with strict enforcement of booleans:
* Modula-2 does it right: BOOL is a separate type which is required for conditionals, but
+ the ORD and VAL functions offer typesafe conversions to and from integers, and
+ BOOL can be used as an array index type, just like any other enumerated type.
* Java does it wrong: not only does it not provide easy conversions, but it doesn’t allow enumerations to be used as array index types.

Python would do well to learn from the Modula-2 style.

Steven D'Aprano

da leggere,
17 lug 2016, 06:05:0617/07/16
a
On Sun, 17 Jul 2016 05:44 pm, Lawrence D’Oliveiro wrote:

> On Sunday, July 17, 2016 at 7:33:19 PM UTC+12, Chris Angelico wrote:
>> 1) REXX and, I think, Pascal: there are two specific values that may
>> be used in conditionals, and anything else is an error
>
> Worth comparing how two different languages deal with strict enforcement
> of booleans:

> * Modula-2 does it right: BOOL is a separate type which is
> required for conditionals, but
> + the ORD and VAL functions offer typesafe conversions to and from
> integers, and
> + BOOL can be used as an array index type, just like any
> other enumerated type.

That's also the Pascal model, which is no surprise, since Modula-2 and
Pascal are both invented by the same person, Nicholas(?) Wirth.

I'll certainly agree that the Pascal/Modula-2 model for bools is a good
model. On balance, I think that I'd argue:

- in statically typed languages, I'd look for the Pascal model;
- in dynamically typed languages, I'd look for something that
matches Python's truthiness rules;
- or at least some other consistent, useful and simple metaphor
for truthiness;
- a mere collection of objects which happen to be arbitrarily
treated as truthy or falsey (like Ruby and Javascript?),
lacking any consistent metaphor, is in some ways the worst
of both worlds.

Steven D'Aprano

da leggere,
17 lug 2016, 07:02:3617/07/16
a
On Sun, 17 Jul 2016 04:44 pm, Rustom Mody wrote:

> My earlier statement (with emphasis in original):
>> You also have a bizarre notion that python's property: “Everything has
>> auto-bool-nature” IS STRAIGHTFORWARD.

I'm still waiting to hear in what way it is not straightforward. You keep
insisting that it isn't, but haven't told us in what way it is not.

Rustom Mody

da leggere,
17 lug 2016, 11:00:1217/07/16
a
On Sunday, July 17, 2016 at 4:32:36 PM UTC+5:30, Steven D'Aprano wrote:
> On Sun, 17 Jul 2016 04:44 pm, Rustom Mody wrote:
>
> > My earlier statement (with emphasis in original):
> >> You also have a bizarre notion that python's property: “Everything has
> >> auto-bool-nature” IS STRAIGHTFORWARD.
>
> I'm still waiting to hear in what way it is not straightforward. You keep
> insisting that it isn't, but haven't told us in what way it is not.

The re/automaton/graph examples were towards this only and I think we are
running in circles on this. [Note the persons involved and even the specific
types involved are in a sense not relevant]

There is however one point that I briefly alluded that can be expanded on, viz.
Python’s bool behavior is inconsistent with rest of python’s standard behavior.

>>> class C:
... pass
...
>>> c=C()
>>> c+c
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'instance' and 'instance'
>>> c.a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: C instance has no attribute 'a'
>>> a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined

IOW the details — AttributeError/NameError/TypeError — may differ but in general
python has a well-established (and IMHO kind) behavior, if programmer fails
to define something python helpfully says that and makes no random guesses.

The extremal behavior at the other end of the spectum is probably html:
Whatever html you throw at whatever browser it will be rendered in some way
or other. [Some people like this — standards are for wimps]

For bools python is closer to html than to its normal peremptory default:

>>> if c:
... print "Yes"
... else:
... print "No"
...
Yes

Steven D'Aprano

da leggere,
17 lug 2016, 11:58:5317/07/16
a
On Mon, 18 Jul 2016 01:00 am, Rustom Mody wrote:

>> I'm still waiting to hear in what way it is not straightforward. You keep
>> insisting that it isn't, but haven't told us in what way it is not.
>
> The re/automaton/graph examples were towards this only and I think we are
> running in circles on this. [Note the persons involved and even the
> specific types involved are in a sense not relevant]

Ah, so its a secret, is it? ;-)


> There is however one point that I briefly alluded that can be expanded on,
> viz. Python’s bool behavior is inconsistent with rest of python’s standard
> behavior.

"Inconsistent" is too strong. Treatment of bools is certainly different from
(say) arithmetic. Python doesn't assume that every object can duck-type as
a number -- there's no standard protocol for coercing HTTPServer objects
into floats, for example.

But bools are not the only "universal" type. Strings are too. All objects
can be coerced to strings, using either str() or repr(). If you define only
one of __str__ or __repr__, Python will use the other. If you define
neither, you will inherit from object. If you are using a classic class in
Python 2, you will inherit the built-in conversion.

Likewise equality: == is expected to work with *every* class, without
exception, so if you fail to define an __eq__ method, Python will use its
own default behaviour (which is to compare object identity).

There are a small, but very important, set of functions which are expected
to work on all objects, and coercion to bool is one of them.


> IOW the details — AttributeError/NameError/TypeError — may differ but in
> general python has a well-established (and IMHO kind) behavior, if
> programmer fails to define something python helpfully says that and makes
> no random guesses.

There is *no random guessing* involved. I've already gone through the steps
of the bool protocol two, three, maybe four times. Why do you misrepresent
this as "random guesses"? There's no element of chance, the protocol is
completely deterministic and documented. There's a preferred API,
__nonzero__ in Python 2 and __bool__ in Python 3, if that isn't defined
there's a fallback using __len__, if that's not defined then the usual
rules of inheritance apply and you inherit from your superclasses.

Steven D'Aprano

da leggere,
17 lug 2016, 12:01:4117/07/16
a
On Mon, 18 Jul 2016 01:58 am, Steven D'Aprano wrote:

> All objects
> can be coerced to strings, using either str() or repr(). If you define
> only one of __str__ or __repr__, Python will use the other.

Er, sorry, that was incoherent. I hit Send too quick, without editing.

What I meant to say was, if you *fail* to define both __str__ and __repr__,
Python will use whichever you define in place of the missing one.

And of course, if you define neither, then you will inherit from object.
0 nuovi messaggi