1

このスタイルのようなコードを常に心配していたので、なぜこの質問をするのか

def callsomething(x):
    if x in (3,4,5,6):
        #do something

関数 callsomething が頻繁に呼び出された場合、(3,4,5,6) はスペースと時間を浪費しすぎましたか? C のような言語では、定数のようにデータ セグメントに入れられるかもしれませんが、Python ではそうではありません。それがどのように機能するかを知っているので、私はこのようなコードを書く傾向がありました

checktypes = (3,4,5,6)#cache it
def callsomething(x):
    global checktypes
    if x in checktypes:
        #do something

しかし、テストの後、この方法でプログラムが遅くなることがわかりました。より複雑なケースでは、コードは次のようになります。

types = (3,4,5,6)
def callsomething(x):
    global types
    for t in types:
        t += x
        #do something

これよりまだ遅い

def callsomething(x):
    for t in (3+x,4+x,5+x,6+x):
        #do something

この場合、プログラムは (3+x,4+x,5+x,6+x) を作成する必要がありますが、それでも最初のバージョンよりは高速ですが、頭が大きくなりすぎることはありません。

Python でのグローバル var アクセスがプログラムの速度を低下させることは知っていますが、構造体の作成と比べてどうですか?

4

2 に答える 2

8

心配する必要はありません。これは定数として保存されます (これが、予想よりも高速である理由を説明しています)。

>>> def callsomething(x):
...     if x in (3,4,5,6): pass
... 
>>> import dis
>>> dis.dis(callsomething)
  2           0 LOAD_FAST                0 (x)
              3 LOAD_CONST               5 ((3, 4, 5, 6))
              6 COMPARE_OP               6 (in)
              9 POP_JUMP_IF_FALSE       15
             12 JUMP_FORWARD             0 (to 15)
        >>   15 LOAD_CONST               0 (None)
             18 RETURN_VALUE        

で見上げる方xset速いはずですよね?でもうわぁ…

>>> def callsomething(x):
...     if x in {3,4,5,6}: pass
... 
>>> dis.dis(callsomething)
  2           0 LOAD_FAST                0 (x)
              3 LOAD_CONST               1 (3)
              6 LOAD_CONST               2 (4)
              9 LOAD_CONST               3 (5)
             12 LOAD_CONST               4 (6)
             15 BUILD_SET                4
             18 COMPARE_OP               6 (in)
             21 POP_JUMP_IF_FALSE       27
             24 JUMP_FORWARD             0 (to 27)
        >>   27 LOAD_CONST               0 (None)
             30 RETURN_VALUE      

set は変更可能であるため、Python は最近までこの最適化を行っていませんでした。Python3.3 では、これをフリーズセットにしても安全であることがわかります。

Python 3.3.0 (default, Sep 29 2012, 17:17:45) 
[GCC 4.7.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> def callsomething(x):
...     if x in {3,4,5,6}: pass
... 
>>> import dis
>>> dis.dis(callsomething)
  2           0 LOAD_FAST                0 (x) 
              3 LOAD_CONST               5 (frozenset({3, 4, 5, 6})) 
              6 COMPARE_OP               6 (in) 
              9 POP_JUMP_IF_FALSE       15 
             12 JUMP_FORWARD             0 (to 15) 
        >>   15 LOAD_CONST               0 (None) 
             18 RETURN_VALUE         
>>> 
于 2013-06-12T03:46:36.973 に答える
1

タプル以外のものの定数を取得できるように本当にハックしたい場合は、次のようなひどいことをすることができます

def foo(x, dont_use_this=frozenset([1,2,3])):
    if x in dont_use_this:
        # do something
    return x

しかし、そうしないでください。

于 2013-06-12T04:07:43.403 に答える