5

Python で関数を呼び出すのはコストがかかることを知っているので、この質問への答えは最適化の決定に関係があります。だから知りたい

  • 必要な関数呼び出しの通常の回数は?
  • 必要な関数呼び出しの最小数は?
  • 電話の数を増やすものは何ですか?
  • ユーザーが作成したクラスは組み込みクラスと比べてどうですか?
  • オブジェクトの削除 (ガベージ コレクションを含む) はどうですか?

私の google-fu は、この質問に対する答えを見つけることができませんでした。

編集:コメントを要約し、より多くの投票を未然に防ぐために、ここにいくつかの説明があります:

  • 通常の Python 関数の呼び出しと比較して、Python インスタンス作成の時間の複雑さに興味があります。
  • この質問のために、最新の CPython バージョンに限定しましょう。
4

2 に答える 2

7

Eli Bendersky による Python オブジェクトの作成を参照してください。

結論を長々と引用すると:

木を見て森を失うことのないように、この記事の最初の質問に戻りましょう。CPython を実行するとどうなりj = Joe()ますか?

  • Joe明示的なメタクラスがないので、typeその型です。したがって、のtp_callスロットでtypeあるtype_callが呼び出されます。
  • type_calltp_newまず、Joe のスロットを 呼び出します。
    • Joe には明示的な基本クラスがないため、その基本はobjectです。したがって、object_newと呼ばれます。
    • Joe は Python 定義のクラスであるため、カスタムtp_allocスロットはありません。したがって、 をobject_new呼び出しますPyType_GenericAlloc
    • PyType_GenericAllocJoe を格納するのに十分な大きさのメモリのチャンクを割り当てて初期化します。
  • type_call次に進みJoe.__init__、新しく作成されたオブジェクトを呼び出します。
    • Joeは を定義していないので__init__、そのベース__init__は と呼ばれobject_initます。
    • object_init何もしません。
  • 新しいオブジェクトは から返されtype_call、 name にバインドされjます。
于 2012-07-30T12:31:05.253 に答える
3

コメントで提案されているとおりに実行timeitし、これらのテストケースで使用しました:

def a():
    pass

class A(object):
    pass

class B(object):
    def __init__(self):
        pass

class NOPType(type):
    pass

class C(object):
    __metaclass__ = NOPType
    def __init__(self):
        pass

class D(object):
    def __new__(cls, *args, **kwargs):
        return super(D, cls).__new__(cls)

    def __init__(self):
        pass

class E(A):
    def __init__(self):
        super(E, self).__init__()

試験結果:

$ python -m timeit -s "import tst" "tst.a()"
10000000 ループ、ベストオブ 3: ループあたり 0.149 マイクロ秒
$ python -m timeit -s "import tst" "tst.A()"
10000000 ループ、ベストオブ 3: ループあたり 0.169 マイクロ秒
$ python -m timeit -s "import tst" "tst.B()"
1000000 ループ、ベストオブ 3: ループあたり 0.384 usec
$ python -m timeit -s "import tst" "tst.C()"
1000000 ループ、ベストオブ 3: ループごとに 0.397 usec
$ python -m timeit -s "import tst" "tst.D()"
1000000 ループ、ベストオブ 3: ループあたり 1.09 マイクロ秒
$ python -m timeit -s "import tst" "tst.E()"
1000000 ループ、ベストオブ 3: ループごとに 0.827 usec

関数呼び出しをベースラインとして使用すると、次の結果が得られます。

  • 基本的なインスタンス化には 1.1 倍の時間がかかります。
  • メソッドを追加する__init__と、係数が 2.6 に増加します
  • no-op メタクラスの追加は、2.7 で、ほんの少し高価です。
  • 代わりに basic を追加する__new__と、7.3 関数呼び出しと同等になります。
  • 単一のサブクラスを持つクラスは、5.6 関数呼び出しと同等です

super最後の 2 つの結果については、呼び出しをその戻り値に置き換えると、約 2 を引くことができます。

これにより、CPython 2.7 で、時間のかかる python クラスと python 関数を比較する方法の概算が得られるはずです。

于 2012-07-30T13:09:23.230 に答える