[TIP] Interesting getattr pattern [was: Re: [issue5728] Support telling TestResult objects a test run has finished]

Olemis Lang olemis at gmail.com
Tue Apr 14 09:56:53 PDT 2009


On Mon, Apr 13, 2009 at 9:10 AM, Olemis Lang <olemis at gmail.com> wrote:
>
> According to my experience, function calls are expensive, especially
> in this case where startTestRun method can be called *MANY* times.
>

I tried to measure the three candidate alternatives. I employed a
simpler example (didnt remember the whole code :-/ , and this was done
yesterday ) :

{{{
#!python

class A():
    def method(self):
        pass

class B():
    pass

REPEAT = 100000

def func1(x):
    for _ in xrange(REPEAT):
        try:
            method = x.method
        except AttributeError:
            pass
        else:
            method()

def func2(x):
    for _ in xrange(REPEAT):
        method = getattr(x, 'method', None)
        if method is not None:
            method()

def func3(x):
    for _ in xrange(REPEAT):
        method = getattr(x, 'method', lambda : None)
        method()
}}}

Here you have the results :

{{{
>>> from cProfile import run
>>> run('func1(A())')
         100003 function calls in 0.395 CPU seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.238    0.238    0.395    0.395 <stdin>:1(func1)
   100000    0.157    0.000    0.157    0.000 <stdin>:2(method)
        1    0.000    0.000    0.395    0.395 <string>:1(<module>)
        1    0.000    0.000    0.000    0.000 {method 'disable' of
'_lsprof.Profiler' objects}

>>> run('func1(B())')
         3 function calls in 0.446 CPU seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.446    0.446    0.446    0.446 <stdin>:1(func1)
        1    0.000    0.000    0.446    0.446 <string>:1(<module>)
        1    0.000    0.000    0.000    0.000 {method 'disable' of
'_lsprof.Profiler' objects}

>>> run('func2(A())')
         200003 function calls in 0.720 CPU seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.404    0.404    0.720    0.720 <stdin>:1(func2)
   100000    0.155    0.000    0.155    0.000 <stdin>:2(method)
        1    0.000    0.000    0.720    0.720 <string>:1(<module>)
   100000    0.161    0.000    0.161    0.000 {getattr}
        1    0.000    0.000    0.000    0.000 {method 'disable' of
'_lsprof.Profiler' objects}

>>> run('func2(B())')
         100003 function calls in 0.711 CPU seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.256    0.256    0.711    0.711 <stdin>:1(func2)
        1    0.000    0.000    0.711    0.711 <string>:1(<module>)
   100000    0.455    0.000    0.455    0.000 {getattr}
        1    0.000    0.000    0.000    0.000 {method 'disable' of
'_lsprof.Profiler' objects}

>>> run('func3(A())')
         200003 function calls in 0.852 CPU seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.550    0.550    0.852    0.852 <stdin>:1(func3)
   100000    0.149    0.000    0.149    0.000 <stdin>:2(method)
        1    0.000    0.000    0.852    0.852 <string>:1(<module>)
   100000    0.154    0.000    0.154    0.000 {getattr}
        1    0.000    0.000    0.000    0.000 {method 'disable' of
'_lsprof.Profiler' objects}

>>> run('func3(B())')
         200003 function calls in 1.022 CPU seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.442    0.442    1.022    1.022 <stdin>:1(func3)
   100000    0.148    0.000    0.148    0.000 <stdin>:3(<lambda>)
        1    0.000    0.000    1.022    1.022 <string>:1(<module>)
   100000    0.432    0.000    0.432    0.000 {getattr}
        1    0.000    0.000    0.000    0.000 {method 'disable' of
'_lsprof.Profiler' objects}

}}}

Possible conclusions :

- func1 seems to be the fastest
- func2 seems to be quite cool
- func3 seems to be the slowest

... from there on it's up to you anyway.



-- 
Regards,

Olemis.

Blog ES: http://simelo-es.blogspot.com/
Blog EN: http://simelo-en.blogspot.com/

Featured article:



More information about the testing-in-python mailing list