2016-10-15 4 views
0

私はPythonを学んでおり、どのようにスタックがPythonで動作するかを考えようとしています。私はいくつかの疑問を持っています。私はスタックの仕事を知っていて、私はそれについて多くの記事とチュートリアルを読んできました。私は彼らがすべて良いですが、まだ私はいくつかの疑問があるstackoverflow上の多くのスレッドを読んだ。呼び出し引数スタックはPythonでどのように機能しますか?

これまでのところ、私はスタックストアを読み、関数の値を返しました。 LIFOプリンシパルによって動作します。

スタックの最初の値だけが返され、一番上に格納されます。

だから私の質問はある - 4つの変数があるとします

sum = a + d 
sum = b + c 

a = 9 
d = 4 
b = 2 
c = 13 

、彼らが返されます:彼らは、例えば、値を呼び出す機能した順序でスタックに格納されている

a = 9 
b = 2 
c = 13 
d = 4 

は、上から下まで。今や私の混乱は - いずれかの操作がdcを使用する必要がある場合、スタックの途中にある限り、スタック戻り値はどのようにしてdcになるでしょうか?最初にスタックしてからdを返しますか?

これは混乱です。

+2

スタック変数にアクセスするときに 'push'や' pop'ingはありません。 – tkausl

+0

私は混乱しています、あなたはデータ構造として "スタック"を意味しますか、またはメモリとして "スタック"を意味しますか?最初のものが該当する場合 - 上からの値が必要ない場合は使用しないでください。後者の場合、変数は積み重ねられた関数の "仮想"ヒープ内にありますので、それは大丈夫です – RafazZ

+2

なぜタグ付けしましたかこれは[スタックオーバーフロー]ですか? –

答えて

0

pythonがどのように動作するのか興味があれば、標準のCPythonライブラリdisがあります。 はここにあなたのテストコードのために出力されます:

>>> import dis 
>>> def test(): 
...  a = 9 
...  b = 2 
...  c = 13 
...  d = 14 
...  sum1 = a + d 
...  sum2 = b + c 
... 
>>> dis.dis(test) 
    2   0 LOAD_CONST    1 (9) 
       3 STORE_FAST    0 (a) 

    3   6 LOAD_CONST    2 (2) 
       9 STORE_FAST    1 (b) 

    4   12 LOAD_CONST    3 (13) 
      15 STORE_FAST    2 (c) 

    5   18 LOAD_CONST    4 (14) 
      21 STORE_FAST    3 (d) 

    6   24 LOAD_FAST    0 (a) 
      27 LOAD_FAST    3 (d) 
      30 BINARY_ADD   
      31 STORE_FAST    4 (sum1) 

    7   34 LOAD_FAST    1 (b) 
      37 LOAD_FAST    2 (c) 
      40 BINARY_ADD   
      41 STORE_FAST    5 (sum2) 
      44 LOAD_CONST    0 (None) 
      47 RETURN_VALUE   

、それはあなたが見ることができるようにスタックとは何の関係もありません。 それはあなたがコンピューティングの一般的なスタックの概念に興味があるなら、あなたには、いくつかの低レベル(Cのような2.5世代言語)に切り替える必要があります

>>> def test2(a,b,c,d): 
...  sum1 = a + d 
...  sum2 = b + c 
... 
>>> dis.dis(test2) 
    2   0 LOAD_FAST    0 (a) 
       3 LOAD_FAST    3 (d) 
       6 BINARY_ADD   
       7 STORE_FAST    4 (sum1) 

    3   10 LOAD_FAST    1 (b) 
      13 LOAD_FAST    2 (c) 
      16 BINARY_ADD   
      17 STORE_FAST    5 (sum2) 
      20 LOAD_CONST    0 (None) 
      23 RETURN_VALUE   

のように、調整後のコードでさえも行う、あるいはません。アセンブリ言語にさらに深く関わっています。さまざまな呼び出し規約について読ん

スタックはLIFOとして動作しますが、あなたは正確にデータ構造が積層されているかについて注意する必要があります(例えばx86 calling conventions

+0

参照による呼び出し値? LOAD_FASTコール0(a)のように0メモリアドレスですか? –

+0

これはPythonスタックフレーム内の変数のインデックスです。 _stack_フレームと呼ばれていますが、x86/ARMの汎用レジスタ(eax、ebx/r0、r1、r2など)のように考える必要があります。 フレームはCPython仮想マシンのスタック内に割り当てられます(したがって_stack frame_)が、データはLIFOの順序でアクセスされません。 CPython – agg3l

+0

の[bytecodes reference](https://docs.python.org/2/library/dis.html#bytecodes)は、Python変数(いくつかのconst値ではない)がスタックにプッシュされている場合、次に可能です参照によってアクセスされているとします。 – agg3l

0

だけでなく、他の良いスタート点であってもよいです。例えば、多くのプログラミング言語は、関数を呼び出すときに、スタックを使用してパラメータとローカル変数を格納します。しかし、スタックされているものは、呼び出しフレーム全体であり、フレーム内の個々の変数ではありません。

たとえば、私はローカル変数a、b、c、dを "スタックに"持っているかもしれませんが、それらはフレームの先頭から固定された既知のオフセットに格納されています。変数は任意の順序でアクセスすることができ、コンパイラが行っている最適化とは別に、動きません。

Pythonはもう少し複雑です。 CPythonでは、少なくとも、カバーの下にスタックフレームがありますが、実際には、ローカル変数は関数のローカル名前空間を構成する関数インスタンスオブジェクトの配列(以下のshadowrangerの注記を参照)に格納されています。すべての変数はいつでもdictを通してアクセスできます。

これらの場合、ローカル変数はLIFOではなく、名前空間dictでオフセットまたは名前を知っている限り、任意にアクセスできます。

+0

ローカル変数は実際には 'dict'に自動的には格納されません。 'locals()'(そしておそらくネストされたアクセスを閉じます)は要求に応じて 'dict'を作らなければなりません。もしあなたがそれを呼び出さなければ、ローカル変数は配列に格納されます。 'dis'を使うと違いが見えます。 localsは 'LOAD_FAST' /' STORE_FAST'でアクセスされます。この配列は数値でインデックス付けされた配列を参照します(配列のサイズはコンパイラによって決定され、名前に名前が割り当てられます)。ローカルアクセスのために 'dict'を使うのはあまりにも遅いでしょう。 – ShadowRanger

+0

@ShadowRanger - ありがとう!私はあなたのコメントを参照して更新しました。私はいつも地元の人たちを想定し、クラスインスタンスメソッドの検索はおおよそ同等でした。 – tdelaney

関連する問題