2017-03-21 6 views
3

私は裸の関数の代わりにクラスとメソッドを扱うのが好きです。私は、実行速度、メモリ使用量、またはその他の面で特定のパフォーマンスに影響があるかどうか疑問に思っています。他のテストで関数の代わりにメソッドを使用すると、パフォーマンスに影響はありますか?

import timeit 

class Hello: 
    def hello(self): 
     x = 9 * 8 + 3**5 

def world(): 
    x = 9 * 8 + 3 ** 5 

print(timeit.timeit(world, number=10000000)) 
h = Hello() 
print(timeit.timeit(h.hello, number=10000000)) 
# 0.8460009839758439 
# 0.8781686117747095 

を私は他に比べて一つのケースで使用されているRAMを見ていない:

簡単なテストは両方とも同じようにうまく機能することを示しています。

関数の代わりにクラス/メソッドを使用すると、パフォーマンスが低下する特定のケースがありますか?

注:私はない美的な側面

+0

ラムダでラッピングし、もう一度テストしてみてください。 –

答えて

4

メソッド呼び出しのオーバーヘッドが本当にmethodオブジェクトにfunctionオブジェクトの単なる変換であり、コードのパフォーマンスに専念したいときに、属性アクセス(.)インスタンスから作成した関数の属性です。

とは別に、関数の呼び出しは似ていますが、メソッドのために1つの余分な引数(self)が暗黙に挿入されています。

meth = h.hello 
# use meth from now on 

(編集:Pythonで3.7

だから、いや、ここに持っている任意の懸念、オーバーヘッドが小さく、完全にローカル変数にメソッドを割り当てることによって解消することができますが、実際に存在しません基本的にはローカル名にh.helloを割り当てることの利点を否定することを紹介しnew op-codesは、メソッドのルックアップはちょうどあなたがボトルネックを探しているなら、あなたが他の場所で探している必要があり、非常に速く

:-)ました。 Pythonの動的な解釈は、この種の懸念をペタニックにしています。メモリ態様として


、方法は、本質的に起因し、そのメンバーの一人としての機能を含む方法の機能よりも少し大きくなければならない。それにもかかわらず

meth.__func__ # original function object 

、私が想像できませんアプリケーションがわずかなメモリオーバヘッドのためにチョークするシナリオです。 CPythonので

は、例えば、約64バイトがgetsizeofに係るバウンドメソッドオブジェクトに追加されている:

>>> getsizeof(Foo().foo) 
64 

これはfunctionオブジェクトが含ま__func__属性、カウントされない:

>>> getsizeof(Foo().foo.__func__) 
136 
1

メソッドobj.method(...)を呼び出すと、属性アクセス(obj.method部分)が発生します。これは、些細ではないため、非常にコストのかかる操作です。可能な属性アクセスシナリオの簡単な説明はdocumentation of the descriptor protocolにあります

属性アクセスのデフォルトの動作を設定、取得、または オブジェクトの辞書から属性を削除することです。例えば、a.xは、a.__dict__['x']で始まり、 type(a).__dict__['x']で始まり、メタクラスを除いて type(a)の基本クラスを続けて、 ルックアップチェーンを持ちます。

ただし、ルックアップ値が 記述子メソッドの1つを定義するオブジェクトである場合、Pythonはデフォルトの動作をオーバーライドし、 は代わりに記述子メソッドを呼び出すことがあります。これが 優先順位チェーンで発生する場合、どの記述子メソッドが定義されているか、どのように呼び出されたかによって異なります。

属性アクセスが完了した後でのみ、結果の呼び出し可能オブジェクトを呼び出すことは、空き関数を呼び出すことと少し異なります。ただし、ベンチマークでは、アトリビュートアクセスのオーバーヘッド、つまり一見無害な表記h.helloの操作は測定されません(ただし、例では非常に小さいはずです)。

関連する問題