asking

Steven D'Aprano steve+comp.lang.python at pearwood.info
Wed Aug 22 09:56:00 EDT 2012


On Wed, 22 Aug 2012 02:42:16 -0700, alex23 wrote:

> On 08/22/2012 03:17 AM, mingqiang hu wrote:
>> I mean any of "a","b","c" in string "adfbdfc"  makes the statement
>> true,can I not use a function?
> 
> any(map(string.__contains__, substrings))

Nice.

However, be aware that in Python 2, map() is eager and produces a full 
list ahead of time. In Python 3, map() is lazy and only produces results 
as needed. Since any returns as soon as it sees a true value, Python 3 
can be significantly faster here under some circumstances. For example, 
consider:

string = "a"*10000000
substrings = "abcdefghijklmnopqrstuvwxyz"

map(string.__contains__, substrings) in Python 2 produces a list of 26 
values:

[True, False, False, False, False, ..., False]

up front, before passing that list to any() which stops as soon as it 
sees the first value. Generating those 25 False values was a waste of 
time.

In Python 3, map() produces a lazy iterator object that doesn't calculate 
the values until required. So map(string.__contains__, substrings) 
doesn't do anything straight away. It waits for any() to request a value, 
then returns True. any() then immediately returns, and the other 25 False 
values never get calculated.

In Python 2, you can use itertools.imap for a lazy version. In Python 3, 
you can use list(map( ... )) for an eager version.

Here is a version which is lazy in both Python 2 and 3. I expect it to be 
more or less equally as efficient, and I find it easier to read:

any(sub in string for sub in substrings)

There's also an all() function that works similarly to any(), except that 
it stops as soon as it sees a false value.


-- 
Steven



More information about the Python-list mailing list