[Tutor] List comprehension question

Richard D. Moores rdmoores at gmail.com
Tue Nov 9 23:09:31 CET 2010


On Tue, Nov 9, 2010 at 12:54, Steven D'Aprano <steve at pearwood.info> wrote:
> Richard D. Moores wrote:
>
>> See <http://tutoree7.pastebin.com/R82876Eg> for a speed test with n =
>> 100,000 and 100,000 loops
>
> As a general rule, you shouldn't try to roll your own speed tests. There are
> various subtleties that can throw your results right out. Timing small code
> snippets on modern multi-tasking computers is fraught with difficulties.

Yes, but I thought that if I ran the tests the way I did, several
times and then reversing the order of the functions, and seeing that
the results were very similar, I could be pretty sure of my findings.
Could you point out where taking even that amount of care could lead
me astray?

>
> Fortunately Python comes with that battery already included: the timeit
> module. You can use it from the shell like this:
>
> python -m timeit -s "setup code goes here" "test code goes here"
>
> At the Python interactive interpreter, the most useful pattern I've found
> is:
>
> from timeit import Timer
> t = Timer("proper_divisors(n)",
>    "from __main__ import proper_divisors; n = 100000")
> min(t.repeat(repeat=5, number=100000))
>
>
> Or if you're happy with Python's defaults, that last line can be just:
>
> min(t.repeat())

That's terrific, Stephen! I've used timeit before, but only for really
small snippets. With your encouragement I experimented and after some
trial and error, I came up with this method for using your template:

1. Don't try to dump all you (Steven) wrote in at once.
2. First, do the import.
>>> from timeit import Timer
3. Then dump in the function (steps 2 and 3 can be reversed, I think)
4. then
 >>>t = Timer("proper_divisors(n)",
          "from __main__ import proper_divisors; n = 100000")
5. Finally,
>>>min(t.repeat(repeat=5, number=100000))
6. Wait for the result.

(please tell me if I could cut down the number of steps by combining a
couple of them.)

I was pleased that for

def proper_divisors(n):
    pd = set((1,))
    for x in range(2, int(n**.5)+1):
        if n % x == 0:
            pd.update((x, n//x))
    return sum(list(pd))

I got 8.312734300029753

and for

def proper_divisors(n):
    pd = set((1,))
    for x in range(2, int(n**.5)+1):
        factor, mod = divmod(n,x)
        if mod == 0:
            pd.update((x,factor))
    return sum(list(pd))

got 14.859849506012608

That's about the same speed ratio (1.79) that I reported here earlier,
I believe. I quote: "It may be that I haven't done your suggestions
justice, but that
function is 76% slower than proper_divisors_sum2()"

Question: When I dump in more that one line of any code (properly
indented), after running it once, I've never known how to run it again
without a redump. The up arrow just gets me one line at a time. So,
how to do it?

Thanks,

Dick


More information about the Tutor mailing list