web-dev-qa-db-ja.com

timeit.Timer()を使用するときに関数のパラメーターを渡す方法

簡単なプログラムの概要です

# some pre-defined constants
A = 1
B = 2

# function that does something critical
def foo(num1, num2):
    # do something

# main program.... do something to A and B
for i in range(20):
    # do something to A and B
    # and update A and B during each iteration

import timeit
t = timeit.Timer(stmt="foo(num1,num2)")  
print t.timeit(5)

「グローバル名fooが定義されていません」というメッセージが表示され続けるだけです。ありがとう!

45
CppLearner

コードスニペットは自己完結型である必要があります。外部参照を作成することはできません。ステートメント文字列またはセットアップ文字列で値を定義する必要があります。

import timeit

setup = """
A = 1
B = 2

def foo(num1, num2):
    pass

def mainprog():
    global A,B
    for i in range(20):
        # do something to A and B
        foo(A, B)
"""

t = timeit.Timer(stmt="mainprog()" setup=setup)
print(t.timeit(5))

さらに良いことに、グローバル値を使用しないようにコードを書き直してください。

15
Hugh Bothwell

関数はtimeitで引数を使用できます。これらがクロージャーを使用して作成されている場合、別の関数でそれらをラップすることにより、この動作を追加できます。

def foo(num1, num2):
    def _foo():
        # do something to num1 and num2
        pass
    return _foo

A = 1
B = 2

import timeit
t = timeit.Timer(foo(A,B))  
print t.timeit(5)

短くするか、明示的なクロージャー宣言の代わりに functools.partial を使用できます

def foo(num1, num2):
    # do something to num1 and num2
    pass

A = 1
B = 2

import timeit, functools
t = timeit.Timer(functools.partial(foo, A, B)) 
print t.timeit(5)

モジュールのファイル名がtest.pyであるとします

# some pre-defined constants
A = 1
B = 2

# function that does something critical
def foo(n, m):
    pass

# main program.... do something to A and B
for i in range(20):
    pass

import timeit
t = timeit.Timer(stmt="test.foo(test.A, test.B)", setup="import test")  
print t.timeit(5)
15
Lucas S.

関数は、セットアップ文字列で定義する必要があります。これを行うための良い方法は、モジュール内にコードを設定することです。

t = timeit.Timer("foo(num1, num2)", "from myfile import foo")
t.timeit(5)

それ以外の場合は、すべてのセットアップをセットアップステートメント内の文字列として定義する必要があります。

setup = """
 # some pre-defined constants
A = 1
B = 2

# function that does something critical
def foo(num1, num2):
    # do something

# main program.... do something to A and B
for i in range(20):
    # do something to A and B
    # and update A and B during each iteration
"""

t = timeit.Timer("foo(num1, num2)", setup)
t.timeit(5)

私が見つけた素晴らしいものは、cProfileを使用するiPythonのショートカットです。

def foo(x, y):
    print x*y

%prun foo("foo", 100)

私は通常、追加の関数を作成します。

def f(x,y):
    return x*y

v1 = 10
v2 = 20

def f_test():
    f(v1,v2)

print(timeit.timeit("f_test()", setup="from __main__ import f_test"))
8

別のオプションは、関数をその引数に functools を介してバインドすることです(std :: bindと同様)。その後、timeitに引数を渡す必要はありません。functool.partialによって返される呼び出し可能オブジェクトがそれを処理します。

    def findMax(n):#n is an array
        m = 0
        c = 0
        for i in range(len(n)):
            c += 1
            if m < n[i]:
                m = n[i]
        return m, c


import timeit
import functools
a = [6, 2, 9, 3, 7, 4, 5]
t = timeit.Timer(functools.partial(findMax,a))
t.timeit(100)
3
Mahi Kumar

グローバルを呼び出さずにタイミングルーチンを区分化する方法の例を次に示します

_def foo(a, b):
    '''Do something to `a` and `b`'''
    return a + b

def time_foo():
    '''Create timer object simply without using global variables'''
    import timeit

    _foo = foo
    a = 1
    b = 2

    # Get `Timer` oject, alternatively just get time with `timeit.timeit()`
    t = timeit.Timer('_foo(a, b)', globals=locals())

    return t
_

同じtimeit関数を使用して他の関数の時間を計る場合は、これを一般化することもできます。例はmain()ルーチンの例です:

_def foo1(a, b):
    '''Add `a` and `b`'''
    return a + b

def foo2(a, b):
    '''More math on `a` and `b`'''
    return (a**2 * b)**2

def time_foo(func, **kwargs):
    '''Create timer object simply without using global variables'''
    import timeit
    return timeit.timeit('func(**kwargs)', globals=locals())

def run():
    '''Modify inputs to foo and see affect on execution time'''

    a = 1
    b = 2
    for i in range(10):
        # Update `a` and `b`
        a += 1
        b += 2
        # Pass args to foo as **kwargs dict
        print('foo1 time: ', time_foo(foo1, **{'a':a, 'b':b}))
        print('foo2 time: ', time_foo(foo2, **{'a':a, 'b':b}))

    return None
_
2
ryanjdillon

より簡単な解決策があります(少なくともPython 3の場合))、現在のグローバル名前空間内でコードを実行させることができます:

t = timeit.Timer(stmt="foo(num1,num2)", globals=globals())

https://docs.python.org/3/library/timeit.html#examples グローバルは推奨されませんが、何かを確認する簡単なスクリプトを作成している場合、これは最も簡単な実装。

2
RustyToms

今日Python 3.7でタイミングをいじって、関数と変数をタイマーに渡そうとしました。これが私が思いついたものです。

import re

text = "This         is      a  test of the      emergency broadcast       system"

def regex(text):
    return re.sub(r"(\s)\1{1,}", r"\1", text)

def loop_while(text):
    if "  " in text:
        while "  " in text:
            text = text.replace("  ", " ")

    return text

if __name__ == "__main__":
    import timeit

    callable_functions = [item for item in locals().items() if callable(item[1])]

    for func_name, func in callable_functions:
        elapsed_time = timeit.timeit(f"{func_name}(text)", globals=globals(), number=100000)
        print(f"{func_name}: {elapsed_time} \n{func(text)}\n")

これは出力します:

正規表現:1.378352418
これは緊急放送システムのテストです

loop_while:0.15858950299999997
これは緊急放送システムのテストです

次に、新しいバージョンをテストするために必要なのは、新しい関数を追加することだけです。何かのようなもの:

def split_join(text):
    return " ".join(text.split())

これで出力されます:

正規表現:1.378352418
これは緊急放送システムのテストです

loop_while:0.15858950299999997
これは緊急放送システムのテストです

split_join:0.05700970800000005
これは緊急放送システムのテストです

0
GollyJer

これはうまくいくはずです:

import timeit

def f(x,y):
    return x*y

x = 5
y = 7

print(timeit.timeit(stmt='f(x,y)',
                    setup='from __main__ import f, x, y',
                    number=1000))
0
FooBar167

タイマーを実行する前にすべてのデータを取得する準備ができたstaticクラスを作成することをお勧めします。

別のメモとして、グローバルスペースはFAST_LOADを活用していないため、グローバルスペースではなく、関数でテスト実行する方が良いPythonコードは関数内でより速く実行されますか?

class Data(object):
    """Data Creation"""
    x = [i for i in range(0, 10000)]
    y = Tuple([i for i in range(0, 10000)])
    def __init__(self):
        pass

import timeit

def testIterator(x):
    for i in range(10000):
        z = i


print timeit.timeit("testIterator(Data.x)", setup="from __main__ import testIterator, Data", number=50)
print timeit.timeit("testIterator(Data.y)", setup="from __main__ import testIterator, Data", number=50)
0
user1767754