Numpy数组与Python列表作为函数参数的可变性及传递机制咨询
我熟悉VBA这类可在函数定义中显式指定参数按值(byVal)或按引用(byRef)传递的语言,但Python的参数传递逻辑让我困惑:看似默认类似按值传递,可变对象却又类似按引用传递,我不清楚这在NumPy数组和Python列表中的具体表现。
我的理解——可变/不可变等价于按引用/按值传递——是否错误?是否需要在函数首行对数组参数使用.deepcopy()来避免意外修改原对象?
代码示例与运行现象
以下代码展示了NumPy数组的相关传递现象(Python列表通过推导式修改元素时也有类似表现):
import numpy as np def inc_elements(my_array): for i in range(len(my_array)): my_array[i] = my_array[i] + 1.0 # same effect as: my_array[i] += 1.0 return my_array def inc_array(my_array): my_array = np.add(my_array, np.full_like(my_array, 1.0)) # same effect as: my_array = my_array + np.full_like(my_array, 1.0) # and: my_array = my_array + 1.0 # but NOT: my_array += 1.0 return my_array def del_element(my_array): my_array = np.delete(my_array, [0,]) return my_array functions = [inc_elements, inc_array, del_element] for func in functions: old_array = np.array([0., 1., 2.]) print(f'old_array = {old_array}, {type(old_array)}') new_array = func(old_array) print(f'after {func.__name__}:') print(f'new array = {new_array}, {type(new_array)}') print(f'old_array = {old_array}, {type(old_array)}\n') del old_array, new_array
运行结果:
old_array = [0. 1. 2.], <class 'numpy.ndarray'>
after inc_elements:
new array = [1. 2. 3.], <class 'numpy.ndarray'>
old_array = [1. 2. 3.], <class 'numpy.ndarray'>
old_array = [0. 1. 2.], <class 'numpy.ndarray'>
after inc_array:
new array = [1. 2. 3.], <class 'numpy.ndarray'>
old_array = [0. 1. 2.], <class 'numpy.ndarray'>
old_array = [0. 1. 2.], <class 'numpy.ndarray'>
after del_element:
new array = [1. 2.], <class 'numpy.ndarray'>
old_array = [0. 1. 2.], <class 'numpy.ndarray'>
具体疑问点
从运行结果可以看到:
- 逐个修改数组元素时,原数组会被修改;但使用
np.add、np.delete这类NumPy函数修改整个数组时,原数组不受影响。这一规律是否普遍适用? - 传递子数组或单个数组元素时,会有怎样的表现?
- 所有NumPy函数(如
np.sqrt)都遵循“不修改原数组,返回新数组”的规律吗? - NumPy数组的增强赋值运算符
a += b行为类似循环修改元素,与a = a + b不等价,这背后的原因是什么?
资料需求
恳请推荐能深入讲解数组和列表作为Python函数参数传递机制的教材或官方文档内容。
内容的提问来源于stack exchange,提问作者Murray Anderson

