Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

[False,True] and [True,True] --> [True, True]?????

3 views
Skip to first unread message

bdb112

unread,
Apr 20, 2009, 3:03:28 AM4/20/09
to
Is there any obvious reason why
[False,True] and [True,True]
gives [True, True]

Python 2.5.2 (r252:60911, Feb 21 2008, 13:11:45) [MSC v.1310 32 bit
(Intel)]

Andre Engels

unread,
Apr 20, 2009, 3:10:48 AM4/20/09
to bdb112, pytho...@python.org
On Mon, Apr 20, 2009 at 9:03 AM, bdb112 <boyd.bl...@gmail.com> wrote:
> Is there any obvious reason why
> [False,True] and [True,True]
> gives [True, True]

Well, whether the reason is obvious, I do not know, but the way and
seems to be implemented is:

X and Y =
* X if the boolean value of X is false
* Y if the boolean value of X is true

In this case, bool([False,True]) = true, so the second element is taken.


--
André Engels, andre...@gmail.com

AggieDan04

unread,
Apr 20, 2009, 3:14:44 AM4/20/09
to

X and Y == (Y if X else X)
X or Y == (X if X else Y)

[False, True] is true, so the and operator returns the second argument.

Gabriel Genellina

unread,
Apr 20, 2009, 3:17:11 AM4/20/09
to pytho...@python.org
En Mon, 20 Apr 2009 04:03:28 -0300, bdb112 <boyd.bl...@gmail.com>
escribió:

> Is there any obvious reason why
> [False,True] and [True,True]
> gives [True, True]

Yes: short-circuit evaluation.
[False,True] and [True,True] is *not* an element-by-element operation,
it's a simple expression involving two objects (two lists).
A and B means: check the boolean value of A; if it's false, return A.
Else, return B.
A non-empty list has a boolean value of true, so the second list is
returned.

If you want an element-wise operation:
A = [False,True]
B = [True,True]
result = [a and b for a,b in zip(A,B)]
--
Gabriel Genellina

bdb112

unread,
Apr 20, 2009, 4:16:04 AM4/20/09
to
THanks Gabriel,
Now I know about the zip function.

Your explanation of Boolean ops on lists was clear.
It leads to some intriguing results:

bool([False])
--> True

I wonder if python 3 changes any of this?

Peter Otten

unread,
Apr 20, 2009, 4:33:04 AM4/20/09
to
bdb112 wrote:

> Your explanation of Boolean ops on lists was clear.
> It leads to some intriguing results:
>
> bool([False])
> --> True
>
> I wonder if python 3 changes any of this?

No. Tests like

if items:
...

to verify that items is a non-empty list are a widespread idiom in Python.
They rely on the behaviour you observe.

Peter

Gerhard Häring

unread,
Apr 20, 2009, 4:54:40 AM4/20/09
to pytho...@python.org

Are they widespread? I haven't noticed, yet.

I prefer to write it explicitly:

if len(lst) > 0:
...

if item is None:
...

etc.

-- Gerhard

Chris Rebert

unread,
Apr 20, 2009, 4:58:55 AM4/20/09
to Gerhard Häring, pytho...@python.org
> Are they widespread? I haven't noticed, yet.
>
> I prefer to write it explicitly:
>
> if len(lst) > 0:

Nope, that's not idiomatic. The simpler `if lst:` version is indeed widespread.

>    ...
>
> if item is None:

That's pretty common and accepted; comparison to None is something of
a special case.

Cheers,
Chris
--
I have a blog:
http://blog.rebertia.com

Peter Otten

unread,
Apr 20, 2009, 5:17:22 AM4/20/09
to
Gerhard Häring wrote:

> Peter Otten wrote:
>> bdb112 wrote:
>>
>>> Your explanation of Boolean ops on lists was clear.
>>> It leads to some intriguing results:
>>>
>>> bool([False])
>>> --> True
>>>
>>> I wonder if python 3 changes any of this?
>>
>> No. Tests like
>>
>> if items:
>> ...
>>
>> to verify that items is a non-empty list are a widespread idiom in
>> Python. They rely on the behaviour you observe.
>
> Are they widespread? I haven't noticed, yet.

That is my impression.



> I prefer to write it explicitly:
>
> if len(lst) > 0:
> ...

Using google codesearch I get

matches search expression
ca. 1000 lang:python "if items:"
216 lang:python "if len(items) > 0:"

This could of course mean that "people who like 'items' as a list name also
like the 'if items:...' idiom" or "'items' is a popular name for boolean
values" or "the search result is spammed by a gazillion zope versions"...

Peter

Steven D'Aprano

unread,
Apr 20, 2009, 5:26:34 AM4/20/09
to


Do you also count the length of a list explicitly?

n = 0
for item in lst:
n += 1
if n > 0:
...

No? Of course you don't. You understand that lists know how to calculate
their own length, and you just ask the list for its length. Great.

Well, lists also know whether or not they are empty, without needing to
concern yourself with the definition of "empty".

if lst:
# not empty
else:
# empty


All Python objects have an understanding of "empty" or "not empty", and
the only time I've seen it cause problems is with iterators, because you
can't tell if an iterator is empty until you actually try to access a
value.

> if item is None:
> ...

That's a completely different test. That's testing whether item is the
specific singleton None. It is very different from testing bool(item).

--
Steven

Peter Pearson

unread,
Apr 20, 2009, 11:53:41 AM4/20/09
to
On 20 Apr 2009 09:26:34 GMT, Steven D'Aprano wrote:
> On Mon, 20 Apr 2009 10:54:40 +0200, Gerhard Häring wrote:
[snip]

>> I prefer to write it explicitly:
>>
>> if len(lst) > 0:
>
> Do you also count the length of a list explicitly?
>
> n = 0
> for item in lst:
> n += 1
> if n > 0:
> ...
>
> No? Of course you don't. You understand that lists know how to calculate
> their own length, and you just ask the list for its length. Great.
>
> Well, lists also know whether or not they are empty, without needing to
> concern yourself with the definition of "empty".
>
> if lst:
> # not empty
> else:
> # empty
>
> All Python objects have an understanding of "empty" or "not empty", and
> the only time I've seen it cause problems is with iterators, because you
> can't tell if an iterator is empty until you actually try to access a
> value.

Like Gerhard, I prefer the construction that explicitly
says, "This is a list, and this is what I'll do if it's not
empty." To me, and I suspect to a great many programmers,
"if x:" does *not* mean "if x is not empty", it means "if
x is (in some sense) True, including the possibility that
x is an object from which a True or False value must be
extracted by means that might not be at all obvious." For
an object lesson in the perils of said extraction, see the
recent thread on [False,True] and [True,True] == [True,True].

People much smarter than me will no doubt rush to point out
that if I were alert, I would know from the context that x
is a list, and if I were thoroughly familiar with Python, I
would know that when x is a list, "if x:" means not empty.
True, but this is all the brain I got, so when I come back
in two months, pathetically disoriented, to peer at this
line of code through my senescent blear, I hope I'll see,
"This, Peter, is a list, and this is what I'll do . . ."

The "not empty" interpretation is a cute shortcut. But
somebody's gotta put up some resistance to cute shortcuts,
or we'll find ourselves back with Perl.

--
To email me, substitute nowhere->spamcop, invalid->net.

Paul Rubin

unread,
Apr 20, 2009, 12:27:37 PM4/20/09
to
Peter Pearson <ppea...@nowhere.invalid> writes:
> The "not empty" interpretation is a cute shortcut. But
> somebody's gotta put up some resistance to cute shortcuts,
> or we'll find ourselves back with Perl.

+ QOTW

"Martin v. Löwis"

unread,
Apr 20, 2009, 4:05:57 PM4/20/09
to Gerhard Häring
> Are they widespread? I haven't noticed, yet.
>
> I prefer to write it explicitly:
>
> if len(lst) > 0:

I prefer to test explicitly for the truth value of the
list. I don't want to test whether the length of the list
is greater than 0 (in fact, I don't care about the length
property of the list at all) - I want to know whether the
list is empty (or not empty). The Python syntax for this
test is

if lst:
# not empty

or

if not list:
#empty

The view "let me test for the precise value" leads to
formulations like

if foo is True:
return True
else:
return False

People should have more trust in boolean conversions.

Regards,
Martin

Aahz

unread,
Apr 20, 2009, 4:10:11 PM4/20/09
to
In article <mailman.4205.1240217...@python.org>,

=?ISO-8859-1?Q?Gerhard_H=E4ring?= <g...@ghaering.de> wrote:
>
>I prefer to write it explicitly:
>
>if len(lst) > 0:
> ...

At the very least, IMO you should write this as

if len(lst):
...

There's no reason to be explicit about the numeric comparison.
--
Aahz (aa...@pythoncraft.com) <*> http://www.pythoncraft.com/

"If you think it's expensive to hire a professional to do the job, wait
until you hire an amateur." --Red Adair

Grant Edwards

unread,
Apr 20, 2009, 4:13:15 PM4/20/09
to
On 2009-04-20, Martin v. L?wis <mar...@v.loewis.de> wrote:

> I don't want to test whether the length of the list

> is greater than 0 [...] - I want to know whether the


> list is empty (or not empty).

I fail to see the difference between "length greater than 0"
and "list is not empty". They are, by definition, the same
thing, aren't they?

--
Grant Edwards grante Yow! ... My pants just went
at on a wild rampage through a
visi.com Long Island Bowling Alley!!

"Martin v. Löwis"

unread,
Apr 20, 2009, 4:24:41 PM4/20/09
to
>> I don't want to test whether the length of the list
>> is greater than 0 [...] - I want to know whether the
>> list is empty (or not empty).
>
> I fail to see the difference between "length greater than 0"
> and "list is not empty". They are, by definition, the same
> thing, aren't they?

Yes, they test the same property, and so would

for x in foo: # foo is empty if it does not have any elements
# not empty
break
else:
# empty

People also write, as a test for empty lists,

if foo == []: # foo is empty when it is equal to the empty list
# empty

if foo != []:
# not empty

Yet another equivalent test would be

try:
foo[0] # foo is empty if it does not have a zeroeth element
except IndexError:
# empty
else:
# not empty

They are *not* the same thing, by definition, as they work
in different ways. They just yield the same result.

There are many equivalent ways to spell this property; some
are more direct than others. I find that referring to the
boolean-ness of a list is the most direct way to test whether
a list is empty - just as testing for the boolean-ness of
an integer is the most direct way to test whether it is 0.

Regards,
Martin

"Martin v. Löwis"

unread,
Apr 20, 2009, 4:27:34 PM4/20/09
to Aahz
>> I prefer to write it explicitly:
>>
>> if len(lst) > 0:
>> ...
>
> At the very least, IMO you should write this as
>
> if len(lst):
> ...
>
> There's no reason to be explicit about the numeric comparison.

I think in the mind-set that dislikes relying on boolean conversion
of lists, relying on boolean conversion of numbers is just as evil.
In this mindset (IIUC), you *have* to have an expression that is
either True or False in a boolean test (if and while).

Regards,
Martin

Gerhard Häring

unread,
Apr 20, 2009, 6:32:44 PM4/20/09
to pytho...@python.org
Martin v. Löwis wrote:
>> Are they widespread? I haven't noticed, yet.
>>
>> I prefer to write it explicitly:
>>
>> if len(lst) > 0:
>
> I prefer to test explicitly for the truth value of the
> list. I don't want to test whether the length of the list
> is greater than 0 (in fact, I don't care about the length
> property of the list at all) - I want to know whether the
> list is empty (or not empty). The Python syntax for this
> test is
>
> if lst:
> # not empty
>
> or
>
> if not list:
> #empty
> [...]

You're right - as most of the time ;-) This makes a lot of sense to me.

The reason I preferred len(), btw., was only that len() make it clear
that the argument is a sequence.

Maybe I was just too annoyed by lots of Python code I read that looked
like this:

def foo(x, y, z):
if x:
...
else:
...

with poorly named variables where I didn't know what the heck the
variables are (bool, list, instance, ...). I hate it when I have to look
for the actual method calls to figure out what's going in. Better
variable naming and small comments would often help.

-- Gerhard

Raymond Hettinger

unread,
Apr 20, 2009, 7:21:25 PM4/20/09
to
> > No. Tests like
>
> > if items:
> >    ...
>
> > to verify that items is a non-empty list are a widespread idiom in Python.
> > They rely on the behaviour you observe.
>
> Are they widespread? I haven't noticed, yet.

It's the preferred form (as recommended by PEP 8).


Raymond

Terry Reedy

unread,
Apr 20, 2009, 8:20:44 PM4/20/09
to pytho...@python.org
Gerhard Häring wrote:

> Martin v. Löwis wrote:
>>> Are they widespread? I haven't noticed, yet.
>>>
>>> I prefer to write it explicitly:
>>>
>>> if len(lst) > 0:
>> I prefer to test explicitly for the truth value of the
>> list. I don't want to test whether the length of the list
>> is greater than 0 (in fact, I don't care about the length
>> property of the list at all) - I want to know whether the
>> list is empty (or not empty). The Python syntax for this
>> test is
>>
>> if lst:
>> # not empty
>>
>> or
>>
>> if not list:
>> #empty
>> [...]
>
> You're right - as most of the time ;-) This makes a lot of sense to me.
>
> The reason I preferred len(), btw., was only that len() make it clear
> that the argument is a sequence.
>
> Maybe I was just too annoyed by lots of Python code I read that looked
> like this:
>
> def foo(x, y, z):
> if x:
> ...
> else:
> ...
>
> with poorly named variables where I didn't know what the heck the
> variables are (bool, list, instance, ...). I hate it when I have to look
> for the actual method calls to figure out what's going in. Better
> variable naming and small comments would often help.

In my view, that is only excusable in throw-away private code or in
languages like early BASIC where only one letter is allowed, and even
then, 'x' should be a number, not a collection.

Steven D'Aprano

unread,
Apr 20, 2009, 10:44:40 PM4/20/09
to
On Mon, 20 Apr 2009 15:13:15 -0500, Grant Edwards wrote:


> I fail to see the difference between "length greater than 0" and "list
> is not empty". They are, by definition, the same thing, aren't they?

For built-in lists, but not necessarily for arbitrary list-like sequences.

There's also the performance issue. I might have a sequence-like
structure where calling len() takes O(N**2) time, (say, a graph) but
calling __nozero__ might be O(1). Why defeat the class designer's
optimizations?


--
Steven

Steven D'Aprano

unread,
Apr 20, 2009, 10:49:02 PM4/20/09
to
On Tue, 21 Apr 2009 00:32:44 +0200, Gerhard Häring wrote:

> The reason I preferred len(), btw., was only that len() make it clear
> that the argument is a sequence.
>
> Maybe I was just too annoyed by lots of Python code I read that looked
> like this:
>
> def foo(x, y, z):
> if x:
> ...
> else:
> ...
>
> with poorly named variables where I didn't know what the heck the
> variables are (bool, list, instance, ...).


Have you considered that perhaps you don't need to know what the type of
the variables are? Duck typing and all that.

Besides, if the problem is "poorly named variables", the solution *isn't*
to call arbitrary functions on them.

len(x)

x could be a set, a dict, an unsorted list, a sorted list, a tuple, a
deque, a heap, a binary tree, a graph, a stack, a queue, ...

--
Steven

Steven D'Aprano

unread,
Apr 20, 2009, 11:06:40 PM4/20/09
to
On Mon, 20 Apr 2009 15:53:41 +0000, Peter Pearson wrote:

> Like Gerhard, I prefer the construction that explicitly says, "This is a
> list, and this is what I'll do if it's not empty." To me, and I suspect
> to a great many programmers, "if x:" does *not* mean "if x is not
> empty", it means "if x is (in some sense) True, including the
> possibility that x is an object from which a True or False value must be
> extracted by means that might not be at all obvious."

That's *exactly* what it means. This is a feature, not a bug.

No matter what x is (excluding buggy classes), "if x" means "test whether
x is true in a boolean context".

If x happens to be a list, that means "x is empty". If x is a float, it
means "x is positive or negative zero". If x is a phlange, it means the
doofer is unset or it has more than three frobs.

You shouldn't care exactly why x is true or false, only that it is. Why
should you have to manually count the frobs when the class can do it for
you?

> For an object
> lesson in the perils of said extraction, see the recent thread on
> [False,True] and [True,True] == [True,True].

That would be this thread :)

The OP's problem was not with boolean contexts, but with the mistaken
idea that the "and" operator does element by element comparison.

Pop quiz: what's the difference between:

if [False, False]:
print "something"

and

if len([False, False]) != 0:
print "something"

?

--
Steven

John Machin

unread,
Apr 20, 2009, 11:26:58 PM4/20/09
to

Consider this snippet:

while stack and some_condition(stack[-1]):
# do stuff including popping and breaking
else:
# raise an exception

Would you use an explicit len(stack) > 0 ?

Grant Edwards

unread,
Apr 21, 2009, 10:35:13 AM4/21/09
to
On 2009-04-21, Steven D'Aprano <ste...@REMOVE.THIS.cybersource.com.au> wrote:

> No matter what x is (excluding buggy classes), "if x" means
> "test whether x is true in a boolean context".
>
> If x happens to be a list, that means "x is empty". If x is a
> float, it means "x is positive or negative zero".

I think you've got your true/false cases flipped...

--
Grant Edwards grante Yow! I want my nose in
at lights!
visi.com

Peter Pearson

unread,
Apr 21, 2009, 11:51:00 AM4/21/09
to
On 21 Apr 2009 03:06:40 GMT, Steven D'Aprano wrote:
> On Mon, 20 Apr 2009 15:53:41 +0000, Peter Pearson wrote:
>
>> Like Gerhard, I prefer the construction that explicitly says, "This is a
>> list, and this is what I'll do if it's not empty." To me, and I suspect
>> to a great many programmers, "if x:" does *not* mean "if x is not
>> empty", it means "if x is (in some sense) True, including the
>> possibility that x is an object from which a True or False value must be
>> extracted by means that might not be at all obvious."
>
> That's *exactly* what it means. This is a feature, not a bug.
>
> No matter what x is (excluding buggy classes), "if x" means "test whether
> x is true in a boolean context".
>
> If x happens to be a list, that means "x is empty". If x is a float, it
> means "x is positive or negative zero". If x is a phlange, it means the
> doofer is unset or it has more than three frobs.
>
> You shouldn't care exactly why x is true or false, only that it is. Why
> should you have to manually count the frobs when the class can do it for
> you?

That whimsical example is surprisingly persuasive for me.


>> For an object
>> lesson in the perils of said extraction, see the recent thread on
>> [False,True] and [True,True] == [True,True].
>
> That would be this thread :)

Oh, dear. Indeed, it is exactly this increasing scarcity of
at-hand working memory that makes me resist non-obvious features
in programming languages. Perhaps it's time to take up golf.

Lawrence D'Oliveiro

unread,
Apr 22, 2009, 9:40:47 PM4/22/09
to
In message <25f4735b-52a2-4d53-9097-
e62365...@k19g2000prh.googlegroups.com>, bdb112 wrote:

> Is there any obvious reason why
> [False,True] and [True,True]
> gives [True, True]

This kind of confusion is why conditional constructs should not accept any
values other than True and False
<http://groups.google.co.nz/group/comp.lang.python/msg/396c69e9498d9ad4>.


Steven D'Aprano

unread,
Apr 22, 2009, 10:26:35 PM4/22/09
to
On Thu, 23 Apr 2009 13:40:47 +1200, Lawrence D'Oliveiro wrote:

> In message <25f4735b-52a2-4d53-9097-
> e62365...@k19g2000prh.googlegroups.com>, bdb112 wrote:
>
>> Is there any obvious reason why
>> [False,True] and [True,True]
>> gives [True, True]
>
> This kind of confusion is why conditional constructs should not accept
> any values other than True and False

You've already said this, more than a week ago, in the thread titled "Why
does Python show the whole array?". It wasn't correct then, and it isn't
correct now. Any programming feature is subject to errors from people who
try to guess what it does instead of reading the Fine Manual, and Python
has no obligation to make every language feature match the random
preconceptions of every user. Or even some subset of users.

If people guess wrongly what an operator does, then let them learn what
it actually *does* do instead of crippling the operator's functionality.

--
Steven

Leo

unread,
Apr 23, 2009, 5:18:25 AM4/23/09
to
Steven D'Aprano wrote:

Is that true?
Calling len() actually traverses the whole list?
>
>


Peter Otten

unread,
Apr 23, 2009, 6:26:23 AM4/23/09
to
Leo wrote:

No. Steven constructed the theoretical case where determining whether a
sequence (not Python's list) is empty is a cheap operation while getting
the actual length is costly.

The only "popular" data structure I know that implements its length like
this are strings in C.

Peter

Hrvoje Niksic

unread,
Apr 23, 2009, 7:31:45 AM4/23/09
to
Peter Otten <__pet...@web.de> writes:

> The only "popular" data structure I know that implements its length
> like this are strings in C.

Linked lists and trees also tend to do the same, with the exception of
those that explicitly store their length to optimize length queries.

Lawrence D'Oliveiro

unread,
Apr 23, 2009, 8:08:25 PM4/23/09
to
In message <pan.2009.04...@REMOVE.THIS.cybersource.com.au>, Steven
D'Aprano wrote:

> On Thu, 23 Apr 2009 13:40:47 +1200, Lawrence D'Oliveiro wrote:
>
>> In message <25f4735b-52a2-4d53-9097-
>> e62365...@k19g2000prh.googlegroups.com>, bdb112 wrote:
>>
>>> Is there any obvious reason why
>>> [False,True] and [True,True]
>>> gives [True, True]
>>

>> <http://groups.google.co.nz/group/comp.lang.python/msg/396c69e9498d9ad4>


>
> Any programming feature is subject to errors from people who
> try to guess what it does instead of reading the Fine Manual, and Python
> has no obligation to make every language feature match the random
> preconceptions of every user. Or even some subset of users.

<http://groups.google.co.nz/group/comp.lang.python/msg/b12e7b7cbcc82eb0>

Lie Ryan

unread,
Apr 24, 2009, 2:21:22 AM4/24/09
to
Steven D'Aprano wrote:
> On Mon, 20 Apr 2009 15:13:15 -0500, Grant Edwards wrote:
>
>
>> I fail to see the difference between "length greater than 0" and "list
>> is not empty". They are, by definition, the same thing, aren't they?
>
> For built-in lists, but not necessarily for arbitrary list-like sequences.

I think a list-like sequence that does not emulate this behavior (False
when empty, True otherwise) should be considered a buggy implementation
of the list interface.

Lie Ryan

unread,
Apr 24, 2009, 2:50:01 AM4/24/09
to
Gerhard Häring wrote:
> len() make it clear
> that the argument is a sequence.

Not necessarily. Classes that overrides __len__ may fool that assumption
(well, in python classes that overrides special functions may do
anything it is never intended to do).

I often think an "if item:" as "is item workable?". What the exact
definition of "workable" is just something I don't care, at least until
I need to debug the code. A container is workable if it contains
something; most of the time, an empty sequence does not have any value
(pun intended) and thus unworkable.

Steven D'Aprano

unread,
Apr 24, 2009, 4:23:53 AM4/24/09
to
On Fri, 24 Apr 2009 06:50:01 +0000, Lie Ryan wrote:

> Gerhard Häring wrote:
>> len() make it clear that the argument is a sequence.
>
> Not necessarily.

len() works on dicts and sets, and they're not sequences.


--
Steven

Steven D'Aprano

unread,
Apr 24, 2009, 4:28:19 AM4/24/09
to
On Thu, 23 Apr 2009 17:18:25 +0800, Leo wrote:

>> There's also the performance issue. I might have a sequence-like
>> structure where calling len() takes O(N**2) time, (say, a graph) but
>> calling __nozero__ might be O(1). Why defeat the class designer's
>> optimizations?
>
> Is that true?
> Calling len() actually traverses the whole list?

Not for built-in lists, but for sequences created by somebody else, who
knows what it does?

--
Steven

Paul Rubin

unread,
Apr 24, 2009, 6:22:50 AM4/24/09
to
Steven D'Aprano <st...@REMOVE-THIS-cybersource.com.au> writes:
> len() works on dicts and sets, and they're not sequences.

Of course dicts and sets are sequences. But there are also sequences
on which len doesn't work.

You could use: sum(1 for x in seq)
Of course iterating through seq may have undesired side effects.

Peter Otten

unread,
Apr 24, 2009, 7:16:05 AM4/24/09
to
Paul Rubin wrote:

> Steven D'Aprano <st...@REMOVE-THIS-cybersource.com.au> writes:
>> len() works on dicts and sets, and they're not sequences.
>
> Of course dicts and sets are sequences. But there are also sequences
> on which len doesn't work.

That was my intuition, too. But Python takes a different stance:

>>> from collections import *
>>> for obj in [(), [], {}, set()]:
... print(("%r: " % (obj,)) + ", ".join(a.__name__ for a in [Iterable,
Container, Sequence] if isinstance(obj, a)))
...
(): Iterable, Container, Sequence
[]: Iterable, Container, Sequence
{}: Iterable, Container
set(): Iterable, Container

Peter

Steven D'Aprano

unread,
Apr 24, 2009, 7:17:26 AM4/24/09
to
On Fri, 24 Apr 2009 03:22:50 -0700, Paul Rubin wrote:

> Steven D'Aprano <st...@REMOVE-THIS-cybersource.com.au> writes:
>> len() works on dicts and sets, and they're not sequences.
>
> Of course dicts and sets are sequences.

Dicts and sets are explicitly described as "other containers":

http://docs.python.org/library/stdtypes.html#sequence-types-str-unicode-
list-tuple-buffer-xrange

Note that addition is included in the table of sequence operations, but
neither dicts nor sets support it:

>>> {} + {}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'dict' and 'dict'

Nor do they support slicing.


> But there are also sequences on which len doesn't work.
>
> You could use: sum(1 for x in seq)
> Of course iterating through seq may have undesired side effects.

It's also not guaranteed to terminate.

Well, technically no user-defined function is guaranteed to terminate,
but you know what I mean :)


--
Steven

"Martin v. Löwis"

unread,
Apr 24, 2009, 2:21:42 PM4/24/09
to Peter Otten

>> Of course dicts and sets are sequences. But there are also sequences
>> on which len doesn't work.
>
> That was my intuition, too. But Python takes a different stance:

It's a sequence if it can be indexed by numbers in range(len(seq)).
Neither dicts nor sets can be indexed that way.

Regards,
Martin

jazbees

unread,
Apr 25, 2009, 11:18:22 AM4/25/09
to
I'm surprised to see that the use of min and max for element-wise
comparison with lists has not been mentioned. When fed lists of True/
False values, max will return True if there is at least one True in
the list, while min will return False if there is at least one False.
Going back to the OP's initial example, one could wrap a min check on
each list inside another min.

>>> A = [False, True]
>>> B = [True, True]
>>> min(A)
False
>>> min(B)
True
>>> min(min(A), min(B))
False

In a recent work project, I made use of this behavior to condense the
code required to test whether any item in a list of strings could be
found in another string. Here's a variation on that concept that
checks to see if a string contains any vowels:

>>> hasvowels = lambda x:max([y in x for y in "aeiou"])
>>> hasvowels("parsnips")
True
>>> hasvowels("sfwdkj")
False

If using Python 2.5 or later, this could be combined with Python's
version of the ternary operator if your code is such that the source
list may be empty, which is what I ended up using for my project.

>>> foo = ["green", "orange"]
>>> bar = ["blue", "green", "red", "yellow"]
>>> found = lambda x,y:max([z in y for z in x] if x else [False])
>>> found(foo, bar)
True
>>> foo = []
>>> found(foo, bar)
False

Duncan Booth

unread,
Apr 25, 2009, 1:11:45 PM4/25/09
to
jazbees <jaz...@gmail.com> wrote:

>>>> hasvowels = lambda x:max([y in x for y in "aeiou"])
>>>> hasvowels("parsnips")
> True
>>>> hasvowels("sfwdkj")
> False
>

Do you object to using def to define functions?

Anyway, it is probably clearer to use the builtin 'any' for code like this:

>>> def hasvowels(s):
... return any(v in s for v in "aeiou")
...


>>> hasvowels("parsnips")
True
>>> hasvowels("sfwdkj")
False
>>>

>>>> foo = ["green", "orange"]


>>>> bar = ["blue", "green", "red", "yellow"]
>>>> found = lambda x,y:max([z in y for z in x] if x else [False])
>>>> found(foo, bar)
> True
>>>> foo = []
>>>> found(foo, bar)
> False

If you are doing a lot of this consider whether you might be better off
using sets:

>>> def found(x,y):
... return bool(set(x).intersection(y))
...

John Posner

unread,
Apr 26, 2009, 4:31:27 PM4/26/09
to jazbees, pytho...@python.org
jazbees wrote:

> I'm surprised to see that the use of min and max for element-wise
> comparison with lists has not been mentioned. When fed lists of True/
> False values, max will return True if there is at least one True in
> the list, while min will return False if there is at least one False.
> Going back to the OP's initial example, one could wrap a min check on
> each list inside another min.

I agree with Duncan Booth that any() is equivalent to -- and better than
-- max() for handling boolean values. But what boolean-oriented function
is equivalent to min()? How about this, which returns the negation of
the min() result:

def at_least_one_false(value_list):
"""
return True if at least one value in value_list is logically FALSE
"""
return any( [not val for val in value_list] )

This works, but the short-circuit feature of any() is undermined by the
process-the-whole-sequence behavior of the list comprehension. So, let's
delete the square brackets, converting the list comprehension into a
generator expression:

return any( not val for val in value_list )

According to timeit.Timer.timeit(), this change improves performance
from 14.59 seconds to 10.49 seconds, with a long value_list:

[True]*20 + [False] + [True]*30

But the generator expression produces worse performance with a shorter
value_list:

[True]*2 + [False] + [True]*3


Arnaud Delobelle

unread,
Apr 26, 2009, 4:37:15 PM4/26/09
to
John Posner <jjpo...@snet.net> writes:

> jazbees wrote:
>
>> I'm surprised to see that the use of min and max for element-wise
>> comparison with lists has not been mentioned. When fed lists of True/
>> False values, max will return True if there is at least one True in
>> the list, while min will return False if there is at least one False.
>> Going back to the OP's initial example, one could wrap a min check on
>> each list inside another min.
>
> I agree with Duncan Booth that any() is equivalent to -- and better
> than -- max() for handling boolean values. But what boolean-oriented
> function is equivalent to min()? How about this, which returns the
> negation of the min() result:
>
> def at_least_one_false(value_list):
> """
> return True if at least one value in value_list is logically FALSE
> """
> return any( [not val for val in value_list] )
>
> This works, but the short-circuit feature of any() is undermined by
> the process-the-whole-sequence behavior of the list comprehension. So,
> let's delete the square brackets, converting the list comprehension
> into a generator expression:
>
> return any( not val for val in value_list )

This is the same as:

return not all(value_list)

> According to timeit.Timer.timeit(), this change improves performance
> from 14.59 seconds to 10.49 seconds, with a long value_list:
>
> [True]*20 + [False] + [True]*30
>
> But the generator expression produces worse performance with a shorter
> value_list:
>
> [True]*2 + [False] + [True]*3

--
Arnaud

John Posner

unread,
Apr 26, 2009, 7:20:38 PM4/26/09
to Arnaud Delobelle, pytho...@python.org
Arnaud Delobelle wrote:
>> return any( not val for val in value_list )
>>
>
> This is the same as:
>
> return not all(value_list)
>
>
Yes, I should have remembered De Morgan's Theorem. Thanks!

-John

jazbees

unread,
Apr 26, 2009, 9:43:56 PM4/26/09
to
On Apr 25, 12:11 pm, Duncan Booth <duncan.bo...@invalid.invalid>
wrote:

> jazbees <jazb...@gmail.com> wrote:
> >>>> hasvowels = lambda x:max([y in x for y in "aeiou"])
> >>>> hasvowels("parsnips")
> > True
> >>>> hasvowels("sfwdkj")
> > False
>
> Do you object to using def to define functions?

Not at all. Do you object to my use of lambdas? I'm not aware of
anything that says it's bad form to define a function using a lambda
when the only thing that a function does is immediately return some
calculated value.

> Anyway, it is probably clearer to use the builtin 'any' for code like this:
>
> >>> def hasvowels(s):
>
> ...     return any(v in s for v in "aeiou")

I wasn't aware of either "any" or "all". Thanks for the info!
Unfortunately this recent project where I used "min" and "max" is
running on a system using Python 2.4, so "any" and "all" are not
available.

> If you are doing a lot of this consider whether you might be better off
> using sets:
>
> >>> def found(x,y):
>
> ...    return bool(set(x).intersection(y))

I haven't used sets very much, but I'll definitely keep this in mind.
Thanks!

John Machin

unread,
Apr 26, 2009, 10:52:14 PM4/26/09
to

Something else worth noting:

dos-prompt>\python24\python -mtimeit -s"hasvowels=lambda x:max([y in x


for y in 'aeiou'])" "hasvowels('parsnips')"

100000 loops, best of 3: 3.08 usec per loop

dos-prompt>\python24\python -mtimeit -s"hasvowels=lambda x:max([y in x
for y in 'aeiou'])" "hasvowels('qwrtypsdf')"
100000 loops, best of 3: 3.06 usec per loop

dos-prompt>\python24\python -mtimeit -s"import re; hasvowels=re.compile
('[aeiou]').search" "hasvowels('parsnips')"
1000000 loops, best of 3: 1.32 usec per loop

dos-prompt>\python24\python -mtimeit -s"import re; hasvowels=re.compile
('[aeiou]').search" "hasvowels('qwrtypsdf')"
1000000 loops, best of 3: 0.934 usec per loop

HTH,
John

Terry Reedy

unread,
Apr 27, 2009, 2:10:44 PM4/27/09
to pytho...@python.org
jazbees wrote:
> On Apr 25, 12:11 pm, Duncan Booth <duncan.bo...@invalid.invalid>
> wrote:
>> jazbees <jazb...@gmail.com> wrote:
>>>>>> hasvowels = lambda x:max([y in x for y in "aeiou"])
>>>>>> hasvowels("parsnips")
>>> True
>>>>>> hasvowels("sfwdkj")
>>> False
>> Do you object to using def to define functions?
>
> Not at all. Do you object to my use of lambdas? I'm not aware of
> anything that says it's bad form to define a function using a lambda
> when the only thing that a function does is immediately return some
> calculated value.

The difference between

hasvowels = lambda x:max([y in x for y in "aeiou"])

and

def hasvowels(x): return max([y in x for y in "aeiou"])

is that the first is 4 chars shorter, but the result has a generic
.__name__ attribute of '<lambda>' insteand of the specific 'hasvowels',
which is definitely more useful. Given this and the that the main
purpose of lambda is to avoid a local name binding, many consider its
use in 'name = lambda...' to be bad form.

tjr

jazbees

unread,
Apr 28, 2009, 10:35:02 PM4/28/09
to
On Apr 27, 1:10 pm, Terry Reedy <tjre...@udel.edu> wrote:
> The difference between
>
> hasvowels = lambda x:max([y in x for y in "aeiou"])
>
> and
>
> def hasvowels(x): return max([y in x for y in "aeiou"])
>
> is that the first is 4 chars shorter, but the result has a generic
> .__name__ attribute of '<lambda>' insteand of the specific 'hasvowels',
> which is definitely more useful.  Given this and the that the main
> purpose of lambda is to avoid a local name binding, many consider its
> use in 'name = lambda...' to be bad form.
>
> tjr

Point taken. Thanks for the explanation, Terry! Thanks also to John
for pointing out the execution speed difference when compared to
regular expressions. I try as much as possible to experiment with
different variations for certain code blocks, but I still don't have
enough of the language in my head to think of all the possible
alternatives. Those examples are great for oiling the mental
machine. Cheers!

Justin

0 new messages