作为函数的输入传递的python字典在该函数中表现为全局而不是本地

use*_*155 38 python variables dictionary global local

我对以下行为感到非常困惑.案例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.
Run Code Online (Sandbox Code Playgroud)

=============案例1 ===============

>>> def testfun1(a):
...     a=2
... 
>>> a=0
>>> testfun1(a)
>>> a
0
Run Code Online (Sandbox Code Playgroud)

=============案例2 ===============

>>> def testfun2(b):
...     b['test']=2
... 
>>> b={}
>>> testfun2(b)
>>> b
{'test': 2}
Run Code Online (Sandbox Code Playgroud)

=============案例3 ===============

>>> def testfun3():
...     c=2
... 
>>> c=0
>>> testfun3()
>>> c
0
Run Code Online (Sandbox Code Playgroud)

=============案例4 ===============(由这个问题解释:全局词典不需要关键字全局来修改它们吗?)

>>> def testfun4():
...     d['test']=10
... 
>>> d={}
>>> testfun4()
>>> d
{'test': 10}
Run Code Online (Sandbox Code Playgroud)

Cas*_*all 84

Python的参数传递与您可能习惯的语言略有不同.python没有通过值显式传递和传递引用语义,而是通过名称传递.您基本上总是传递对象本身,并且对象的可变性决定了它是否可以被修改.列表和Dicts是可变对象.数字,字符串和元组不是.

您将字典传递给函数,而不是副本.因此,当您修改它时,您也在修改原始副本.

要避免这种情况,首先应该在调用函数之前复制字典,或者从函数内部复制字典(将字典传递给dict函数应该这样做).

  • 对于复制字典,应该使用复制模块的深度复制方法**copy.deepcopy(d)**,它返回d的深层副本.有关浅层和深层复制的更多信息,请参阅https://docs.python.org/2/library/copy.html (6认同)
  • @PavanGupta这一切都取决于你想要的副本的"深度".如果你的dict的值也是dicts,你想创建那些dicts的副本,还是指向它们.此规则/问题以递归方式应用. (6认同)

Chu*_*nze 10

为了支持@Casey Kuball所说的,Python 中的每个对象都是通过引用传递的。每个函数都会收到对您传递的实际对象的引用。修改这些对象取决于它们是否是可变数据类型。

本质上,可以说像字典、集合和列表这样的可变对象是通过引用传递的。不可变对象,如intstrtuple是按值传递。

您还应该注意,在某些情况下,可变对象在函数中被覆盖,从而丢失了对传递给函数的实际对象的引用。

>>> def testfun(b):
...     b = b or {}  # Creates a new object if b is false
...     b['test'] = 2
... 
>>> b = {}
>>> testfun(b)
>>> b
{}
Run Code Online (Sandbox Code Playgroud)


sis*_*aty 7

当您将整数或字符串等基本对象传递给函数时,如果您在函数内部更改它,则函数外部的相应对象不会发生任何变化,因为当您以基本对象开头时,Python 按值传递它。

但是,如果您将字典或列表传递给函数,它们将通过引用传递,这意味着您将具有这种行为:函数外部的对象被更改,如您所见。

编辑: 此外,按值传递和按引用传递之间存在区别:按值传递,会创建对象的“副本”以便在函数中使用;通过引用,通过引用传递完全相同的对象,并且函数内部对其进行的修改在外部可见。根据定义,python 按值传递其不可变对象,并按引用传递其可变对象。