2016-04-16 5 views
0

私はPython変数のスコープをかなりよく理解していたと思っていましたが、今日はこのコードを実行しました。奇妙なPythonのスコープの問題

from __future__ import print_function 

def main(): 
    v_Matrix =[[1, 2, 3], 
       [4, 5, 6], 
       [7, 8, 9]] 

    print(v_Matrix) 
    print() 

    f_Rotate(v_Matrix) 
    print(v_Matrix) 

    hh = 3 
    f_This(hh) 
    print(hh) 

def f_Swap(v_Matrix, r1, c1, r2, c2): 
    v_Matrix[r1][c1], v_Matrix[r2][c2] = v_Matrix[r2][c2], v_Matrix[r1][c1] 

def f_Transpose(v_Matrix): 
    for row in range(len(v_Matrix)): 
     for col in range(row): 
      f_Swap(v_Matrix, row, col, col, row) 

def f_FlipVertical(v_Matrix): 
    v_Size = len(v_Matrix) 
    for row in range(v_Size // 2): 
     for col in range(v_Size): 
      f_Swap(v_Matrix, row, col, v_Size - row - 1, col) 

def f_Rotate(v_Matrix): 
    f_Transpose(v_Matrix) 
    f_FlipVertical(v_Matrix) 

def f_This(hh): 
    hh = hh * 2 

if __name__ == '__main__': 
    main() 

実行すると、変数v_Matrixはグローバルのように動作するようです。ただし、テスト変数hhは、1つのスコープをmain()に、もう1つをf_Thisに設定して、期待どおりに動作します。

v_Matrixはグローバルではなく、さまざまな機能で変更されていますが、これらの機能間を行き来することはなく、main()にも戻ります。これらの機能でv_Matrixに適用された値の変更は、出力の間に表示されるmain()のスコープでアクセスできます。ただし、期待どおりに、は、機能の範囲内でのみ、のスコープ内で変更されません。

何がありますか?

+0

リストは変更可能であるためです。詳細については、https://docs.python.org/2/reference/datamodel.html#objects-values-and-typesをご覧ください。 – Selcuk

+0

Pythonは、オブジェクトのコピーを作成するのではなく、functionを呼び出すときに、変更可能なオブジェクトへのポインタをパラメータとして渡します。 Cスタイルのポインタと同様に、ポイントされているオブジェクトの内容を変更することはできますが、関数の呼び出し側が新しいオブジェクトを割り当てることでそのオブジェクトを指すことはできません。 –

+0

@Selcukあなたのリンクのスコープについてはあまり言及されていません。しかし、あなたのコメントは、変更可能なオブジェクト、特にリストが "外側"、 "内側"のコンテナなどのスコープとは異なる振る舞いをするという事実を私が指摘する助けとなりました。 。私はスコープを研究したときにその事実を逃したと思います。ありがとう。 – JayJay123

答えて

1

listは、変更可能なデータ構造です。つまり、id()を同じに保ちながら値を変更することができます。 という名前のという名前の変数を渡している場合は、同じコードを持つ同じオブジェクトであるidを持つようになります。あなたがどこにいてもそれを変えれば、それは良いもののために突然変異してしまいます

したがって、解決策は、は、の周りを通過しません。むしろとし、とするとデータ変換(突然変異ではない)することができます。つまり、もう1つまたはそれ以上を作成し、ジェネレータを使用して最終的な必須リストのみを評価します。

+0

答えと情報ありがとう。 – JayJay123

2

Pythonのすべてがオブジェクトであり、オブジェクトは変更可能でも不変でも同じ方法で関数に渡されます。ただし、変更可能なオブジェクトへの変更は、その機能の外に見ることができます。

例:

def f(c,d): 
    print('Inside f()') 
    print(' id(a) =',id(a),'value =',a) 
    print(' id(b) =',id(b),'value =',b) 
    print(' id(c) =',id(c),'value =',c) 
    print(' id(d) =',id(d),'value =',d) 
    c = 4  # local name c is assigned a new object. 
    d[0] = 5 # local name d's object is mutated 
    print(' id(a) =',id(a),'value =',a) 
    print(' id(b) =',id(b),'value =',b) # b and d objects are same, so b changed 
    print(' id(c) =',id(c),'value =',c) # id changed, not same as a 
    print(' id(d) =',id(d),'value =',d) # id did not change, still same as b 
    d = [6] # local name d is assigned a new object. 
    print(' id(d) =',id(d),'value =',d) # id changed, not same as b 
a = 3 # immutable 
b = [3] # mutable 
print('Before f()') 
print(' id(a) =',id(a),'value =',a) 
print(' id(b) =',id(b),'value =',b) 
f(a,b) 
print('After f()') 
print(' id(a) =',id(a),'value =',a) 
print(' id(b) =',id(b),'value =',b) 

注釈付き出力:

Before f() 
    id(a) = 507107264 value = 3 
    id(b) = 67001608 value = [3] 
Inside f() 
    id(a) = 507107264 value = 3 
    id(b) = 67001608 value = [3] 
    id(c) = 507107264 value = 3 # id(c) == id(a) 
    id(d) = 67001608 value = [3] # id(d) == id(b) 
    id(a) = 507107264 value = 3 
    id(b) = 67001608 value = [5] # id(d)==id(b), so b changed when d did 
    id(c) = 507107296 value = 4 # c was reassigned, id(c) != id(a) 
    id(d) = 67001608 value = [5] # id(d) == id(b)...object mutated 
    id(d) = 65761864 value = [6] # d was reassigned, id(d) != id(b) 
After f() 
    id(a) = 507107264 value = 3 # immutable a unaffected 
    id(b) = 67001608 value = [5] # sees mutation of list contents from d[0]=5 
+0

詳細な回答ありがとうございます。 – JayJay123