2017-11-02 19 views
1

Pythonでは、何も返さずに関数内のいくつかの型のオブジェクトを変更することができます。一部のオブジェクトでは、そうではありません。我々は関数に辞書を渡し、関数内でそれを変更した場合関数呼び出しで変数をいつ変更できますか?

は例えば、元の辞書が変更されます

def add_key(d, key): 
    d[key] = True 

d = {} 
print d 
# {} 

add_key(d, 1) 
print d 
# {1: True} 

対照的に、我々はこのような整数を変えることができない。

def increment_int(i): 
    i += 1 

i = 1 
print i 
# 1 

increment_int(i) 
print i 
# still 1! 

最初は、このように変更可能なオブジェクトを関数内で変更できないというルールが考えられました。同様の例は、文字列では動作しません:

def append_string(s1, s2): 
    s1 += s2 

s = "hello" 
print s 
# "hello" 

append_string(s, " world") 
print s 
# "hello", not "hello world" :( 

特定の操作は、後で見ることができます関数内で変更可能なオブジェクトに適用されているようですので、他の人が文句を言わない間、私は、しかし困惑しています。例えば。

def swap_then_append(l1, l2): 
    l1, l2 = l2, l1 
    l1.append(1) 
    l2.append(2) 

l1 = [] 
l2 = [] 
print l1, l2 
# [] [] 

swap_then_append(l1, l2) 
print l1, l2 
# [2] [1] 
:一見奇妙な、予期しない動作で、

def swap_lists(l1, l2): 
    l1, l2 = l2, l1 

l1 = [1] 
l2 = [2] 
print l1, l2 
# [1] [2] 

swap_lists(l1, l2) 
print l1, l2 
# still [1] [2], even though lists are mutable! 

さらに別の例:

def append_list(l, val): 
    l.append(val) 

l = [] 
print l 
# [] 

append_list(l, 1) 
print l 
# [1] 

二つのリストの名前を交換しながら、にはない:リストに項目を追加すると仕事をします

ここで何が起こっているのか説明できますか?


編集:この質問のpossible duplicateが同定されています。その答えは部分的に私に何が起こっているのかを説明していますが、私はまだ、なぜ上記の関数swap_listsが実際にリストを入れ替えていないのか理解できません。今、私はそれについてさらに考えていますが、私はまだ実際にはincrement_intappend_stringが私が最初に期待したことをしない理由を理解していません。それ以外は、整数と文字列の不変性と関係します。

+0

可能性のある重複を指摘してくれてありがとう - その質問と回答を読むことは役に立ちましたが、私はまだ何が起こっているのか分かりません。私は可能な重複を認めて下の編集を追加しましたが、私はまだ非常に深い誰かから答えをいただければ幸いです! –

+3

変更可能なオブジェクトを変更することはできますが、割り当て(スワッピングを含む)によって新しいオブジェクトが名前にバインドされるため、その効果はその名前を含むスコープに対してローカルになります。 –

+2

Pythonの "変数"は、オブジェクトのラベルと同じように考えられます。オブジェクトにはラベルが付いていてもなくても存在します(オブジェクトは他のオブジェクトによって参照されていない場合は破棄されますが、それは脇にあります)。オブジェクトとなる点は、それに付随するラベルまたはラベルとは独立して存在する。例えば、 'l1 = l2 = [1,2,3]'は同じリストに2つのラベルを貼り付けます。これは、オブジェクトの変更や不変性とは関係ありません。 1つのラベルが1つのオブジェクトに割り当てられ、それを別のオブジェクトに割り当てると、そのラベルを交換するだけです。 – Iguananaut

答えて

3

二重ターゲットの説明では、何がうまくいっているのかを説明していますが、swap_then_appendでは何が起こるか説明します。

def swap_then_append(l1, l2): 
    print l1,l2 
    # [3],[4] 
    l1, l2 = l2, l1 
    print l1,l2 
    # [4] [3] 
    l1.append(1) 
    l2.append(2) 

l1 = [3] 
l2 = [4] 
print l1, l2 
# [3] [4] 

swap_then_append(l1, l2) 
print l1, l2 
# [3,2] [4,1] 

「スワッピング」はリストを参照するために使用される変数の名前を変更しますが、唯一の機能内。基本となるオブジェクトの変異は永続的ですが、変数の割り当てはスコープによって異なります。彼らは今、ただ順番に、l1l2メインスクリプトで定義されたシャドウ、関数のシグネチャで定義された元の変数l1l2をシャドーイングされる機能で新しいl1l2は、同様に、何かを呼ばれるかもしれません。突然変異は元のリストに適用されます。

関連する問題