关于python中修改函数参数的问题?

def func(nums) ... ... ... 如果此函数没有返回值,请问我怎样修改nums的值?才能够在主程序中调用nums时nums发生改变…
关注者
13
被浏览
22,788

3 个回答

也欢迎关注我的知乎账号 @石溪 ,将持续发布机器学习数学基础及Python数据分析编程应用等方面的精彩内容。

参数的传递是通过自动将对象赋值给本地变量名来实现的。 在函数运行时,函数头部的参数名是一个新的、本地的变量名,这个变量名是在函数的本地作用域内存在。参数的传递本质上就是python赋值的另一个实例而已。

那么,这个问题分为可变对象和不可变对象两种情况进行讨论:

在原处改变函数的可变对象参数的值会对调用者有影响。 函数能够就地改变传入的可变对象,因此其结果会影响调用者,这其实和前面介绍过的对象赋值原理是一样的;

而不可变对象的引用重新赋值会指向新的对象,因此不会改变调用者。

先看一个不可变对象的例子

def f(a):
    a = 99
    print(a)
b = 88
f(b)
    print(b)
88 

在函数中修改a对于调用函数的地方没有任何影响,因为他在函数内部直接把本地变量a重置为了一个完全不同的新对象,所以他不会影响最初的变量b

而当参数传递像列表和字典这样的可修改对象的时候,我们还需要注意,对这样的可变对象的原处修改可能在函数退出后依然有效,并由此影响到调用者。

def change(a,b):
    a = 2
    b[0] = 'spam'
x = 1
l = [1,2]
change(x,l)
print(x,l)
1 ['spam', 2]

再次对比可以看出,调用者的不可变变量x没有受到影响,而可变变量L在函数内部进行本地修改,并影响到了自身

可以看出,对于参数a,仅仅把本地变量a修改为引用一个完全不同的对象,并没有改变调用者作用域中的名称x的绑定。而参数b被传给了一个可变对象(在调用者作用域中叫做L的列表),因为第二个赋值是一个在原处发生的对象改变,对函数中b[0]进行赋值的结果会在函数返回后影响L的值,他修改了b所引用的对象的一部分,因为引用共享对象的缘故,L也被同时改变。

再强调一次,其实参数传递后的本地修改过程和简单对象赋值后的对象修改,实质上是一回事 ,换句话说就等于下面这个例子所描述的程序过程

L = [1,2]
b = L
b[0] = 'spam'
print(L)
['spam', 2]

那如何避免对可变参数的修改呢?

实际上,可变参数的原处修改行为并不是一个bug,它只是参数传递在python中工作的方式。在python中,默认通过引用进行函数的参数传递,是因为这通常是我们所想要的:这意味着不需要创建多个拷贝就可以在我们的程序中传递很大的对象。如果不想要函数内部在原处的修改影响传递给它的对象, 那么,我们可以简单的创建一个明确的可变对象的拷贝

def change(a,b):
    a = 2
    b[0] = 'spam'
x = 1
l = [1,2]
change(x,l[:])
print(x,l)
1 [1, 2]

或者在函数内部进行拷贝,这样可以不改变传入的对象,函数调用看上去没有变化

def change(a,b):
    b = b[:]
    a = 2
    b[0] = 'spam'
x = 1
l = [1,2]
change(x,l)
print(x,l)
1 [1, 2]

关于Python编程和数据分析更全面的内容,欢迎关注我在CSDN上的专栏《python数据分析编程基础》。

当然还有《机器学习中的数学-全集(python版)》系列专栏,欢迎大家阅读,配合食用,效果更佳~

有订阅的问题可咨询微信:zhangyumeng0422

你试试在外面加一个装饰器,不知道这样是否符合你要求

def change(func):
    def wrapper(nums):
        nums = [1, 2]
        func(nums)
        return nums
    return wrapper