web-dev-qa-db-ja.com

python関数への入力として渡される辞書は、ローカルではなくその関数のグローバルのように機能します

以下の動作に非常に混乱しています。ケース1、3、および4は期待どおりに動作しますが、ケース2は動作しません。辞書が関数によって返されない場合でも、ケース2で関数が辞書エントリの値をグローバルに変更できるのはなぜですか?関数を使用する主な理由は、関数内のすべてをコードの残りの部分から分離することですが、関数内で同じ変数名を使用することを選択した場合、これは不可能なようです。私は関数で明示的に定義されたものはすべてその関数に対してローカルであると理解していましたが、辞書が定義されて関数への入力として渡される場合はそうではないようです

Python 2.7.2+ (default, Oct  4 2011, 20:06:09) 
[GCC 4.6.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.

=============ケース1 ===============

>>> def testfun1(a):
...     a=2
... 
>>> a=0
>>> testfun1(a)
>>> a
0

=============ケース2 ================

>>> def testfun2(b):
...     b['test']=2
... 
>>> b={}
>>> testfun2(b)
>>> b
{'test': 2}

=============ケース3 ================

>>> def testfun3():
...     c=2
... 
>>> c=0
>>> testfun3()
>>> c
0

=============ケース4 ===============(この質問で説明: グローバル辞書は、変更するためにキーワードglobalを必要としませんそれら?

>>> def testfun4():
...     d['test']=10
... 
>>> d={}
>>> testfun4()
>>> d
{'test': 10}
34
user1748155

Pythonのパラメーターの受け渡しは、おそらく慣れている言語とは少し異なります 。 pythonには名前によるパスがあります。本質的に常にオブジェクト自体を渡しているため、オブジェクトの変更可能性によって、変更可能かどうかが決まります。リストと辞書は変更可能なオブジェクトですが、数値、文字列、およびタプルは変更できません。

辞書をコピーではなく関数に渡します。したがって、それを変更すると、元のコピーも変更されます。

これを回避するには、関数を呼び出す前に、または関数内から辞書をコピーする必要があります(dict関数に辞書を渡す必要があります)。

77
Casey Kuball

@ Casey Kuball の発言をサポートするために、Pythonのすべてのオブジェクトは参照渡しされます。各関数は、渡された実際のオブジェクトへの参照を受け取ります。これらのオブジェクトの変更は可変データ型かどうか。

本質的に、dictsetlistのような可変オブジェクトは参照によって渡されると言えます。 intstrTupleなどの不変オブジェクトは値で渡されます。

また、関数内で可変オブジェクトが上書きされ、関数に渡された実際のオブジェクトへの参照が失われる場合もあります。

>>> def testfun(b):
...     b = b or {}  # Creates a new object if b is false
...     b['test'] = 2
... 
>>> b = {}
>>> testfun(b)
>>> b
{}
1
Chuma Umenze

Globalキーワードは、割り当てにのみ必要です(おそらくdel、私は試したことがない)。オブジェクトの突然変異は完全に有効です。

1
Demian Brecht

dictオブジェクトを関数に渡し、関数内でそれを変更したため、もちろん関数が戻った後に変更されます。オブジェクトはコピーされないので、渡したのと同じオブジェクトを変更します。この質問は、オブジェクトを明示的に渡したときの命名、類似の名前、スコープなどとは関係ありません。

0
wRAR

関数に整数や文字列などの基本オブジェクトを渡す場合、関数内で変更しても、関数外の対応するオブジェクトには何も起こりません。なぜなら、基本オブジェクトでリードしているとき、python値によってそれ。

ただし、辞書またはリストを関数に渡すと、それらは参照で渡されます。つまり、その振る舞いが得られます。つまり、関数の外側のオブジェクトは変更されています。

edit:さらに、値渡しまたは参照渡しには違いがあります。値渡しでは、オブジェクトの「コピー」が順番に作成されます関数で使用されます。参照により、まったく同じオブジェクトが参照を介して渡され、関数内でのそのオブジェクトへの変更は外部から見えるようになります。定義により、pythonはその不変オブジェクトを値で渡し、その可変オブジェクトを参照で渡します。

0
sissi_luaty