1

2つの関数があるとします

def myfunction1(number):

    biglist = [1,2,3,4,5,6,7,8,9]

    print number*biglist


biglist = [1,2,3,4,5,6,7,8,9]

def myfunction2(number, biglist):

    print number*biglist

私はipythonの魔法の%timeitでそれらの時間を計測します:

In [5]: %timeit myfunction2(number, biglist)
1000000 loops, best of 3: 607 ns per loop

In [6]: %timeit myfunction1(number)
1000000 loops, best of 3: 841 ns per loop

これは、biglistmyfunction1 を呼び出すたびに変数が再宣言されるということですか? biglist最初の関数呼び出しの後、関数が呼び出されるたびにリストを再初期化する必要がないように、Python は何らかの方法で変数を関数と共に格納すると推測していました。

Pythonの内部の仕組みがわからないので、推測です。誰かが実際に何が起こっているのか説明できますか?

4

3 に答える 3

2

Python は、非常に複雑な分析を行わないと、あなたが提案したことを実行できません。代入ステートメントは、インタープリターで 2 回入力した場合、単なる代入ステートメントですx=3。その間に x に対して何を行ったかに関係なく、入力した直後に x が 3 になることを期待しています...これは実際には違いはありません

説明するために-その機能は簡単に

def myfunction1(number):
    biglist = [1,2,3,4,5,6,7,8,9]
    biglist = number*biglist
    print biglist

その場合、biglist を再割り当てします。

もちろん、これは biglist が呼び出しごとに異なる変数であるという事実を無視します - この func を 2 つのスレッドで同時に実行することができ、それらは無関係になります

于 2011-01-25T09:35:51.293 に答える
0

はい.. myfunction1 のスコープ内にあり、myfunction2 ではグローバル スコープ内にあり、プログラムが終了するまで終了しません。myfunction1 が完了すると、それに関連付けられている変数は到達不能としてマークされます。そして、すべての呼び出しは、そのスコープ内でのみ新しい vars を作成します。

――サイ

于 2011-01-25T09:33:25.420 に答える
0

Python は、myfunction1() へのエントリごとに新しいリストを作成し、それを「biglist」に割り当てる必要があります。

myfunction2() では、グローバル スコープの「biglist」への参照を渡しているため、コピーを行う必要はありません。

この 2 つには他にも微妙な違いがあります。その参照を渡すと、グローバル データが (おそらく望ましくない) 干渉を受けやすくなります。

>>> biglist = [ 1,2,3,4,5,6,7,8,9 ]
>>> def myfunction3(mylist):
...     mylist[2] = 99
...
>>> biglist
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> myfunction3(biglist)
>>> biglist
[1, 2, 99, 4, 5, 6, 7, 8, 9]

...一方、関数スコープで宣言すると、毎回新しく作成されることを意味します。たとえば、次のようになります。

>>> def myfunction4():
...     mylist = [ 1,2,3,4,5 ]
...     print mylist
...     mylist[2] = 99
...
>>> myfunction4()
[1, 2, 3, 4, 5]
>>> myfunction4()
[1, 2, 3, 4, 5]

関数が呼び出されるたびに、新鮮でクリーンな、純粋なリストのコピーを使用して操作できます。

では、どうすれば両方の長所を活かすことができるでしょうか? これを試して:

>>> def myfunction5():
...     mylist = biglist+[] # Make a private copy
...     mylist[4] = 99
...
>>> biglist
[1, 2, 99, 4, 5, 6, 7, 8, 9]
>>> myfunction5()
>>> biglist
[1, 2, 99, 4, 5, 6, 7, 8, 9]

global-scope リストが変更されていないことがわかります。このメソッドに基づく新しい関数は次のようになります。

def myfunction1a(number):
    mylist = biglist+[] # Copy-safe version
    print number*mylist

ベンチマークのタイミングを使用して比較するとどうなりますか? この場合、関数内の「biglist」を実際に変更していないことはわかっていますが、グローバル データを共有する必要がある場合、およびリストがゼロからのみ構築されるという事実に慣れるのに慣れるのは悪いパラダイムではありません。 1 回 (そしてコピー) すると、パフォーマンスが向上する場合があります。

于 2011-01-25T13:04:05.373 に答える