简短的答案是,Python始终会传递值,但每个Python变量实际上都是指向某个对象的指针,因此有时看起来像是传递引用。
在Python中,每个对象都是可变的或不可更改的。例如,列表,字典,模块和熊猫数据帧是可变的,而整数,字符串和元组是不可变的。可变对象可以在内部进行更改(例如,将元素添加到列表中),但非可变对象则不能。
正如我在开始时所说的,您可以将每个Python变量都视为指向对象的指针。当您将变量传递给函数时,函数中的变量(指针)始终是传入的变量(指针)的副本。因此,如果将新内容分配给内部变量,则您所做的就是更改局部变量指向另一个对象。这不会改变(变异)变量指向的原始对象,也不会使外部变量指向新对象。此时,外部变量仍指向原始对象,但内部变量指向新对象。
如果要更改原始对象(仅适用于可变数据类型),则必须执行一些更改对象的操作,而无需为局部变量分配全新的值。这就是为什么letgo()
和letgo3()
离开外部项目不变,但letgo2()
会改变它。
正如@ursan指出的那样,如果letgo()
使用类似这样的东西,那么它将改变(变异)df
指向的原始对象,这将改变通过全局a
变量看到的值:
def letgo(df):
df.drop('b', axis=1, inplace=True)
a = pd.DataFrame({'a':[1,2], 'b':[3,4]})
letgo(a)
在某些情况下,您可以完全掏空原始变量,并用新数据重新填充它,而无需实际进行直接分配,例如,这将更改v
指向的原始对象,这将更改v
以后使用的数据:
def letgo3(x):
x[:] = np.array([[3,3],[3,3]])
v = np.empty((2, 2))
letgo3(v)
注意,我不是直接分配东西给x
;。我正在为的整个内部范围分配内容x
。
如果您绝对必须创建一个全新的对象并使其在外部可见(大熊猫有时就是这种情况),则有两种选择。“干净”选项只是返回新对象,例如,
def letgo(df):
df = df.drop('b',axis=1)
return df
a = pd.DataFrame({'a':[1,2], 'b':[3,4]})
a = letgo(a)
另一种选择是到达函数外部并直接更改全局变量。这将更a
改为指向一个新对象,a
此后引用的任何函数都将看到该新对象:
def letgo():
global a
a = a.drop('b',axis=1)
a = pd.DataFrame({'a':[1,2], 'b':[3,4]})
letgo()
直接更改全局变量通常不是一个好主意,因为任何读取您的代码的人都将很难找出a
更改的方式。(我通常将全局变量用于脚本中许多函数使用的共享参数,但我不允许它们更改那些全局变量。)