python调用子函数时参数传递问题

场景:

python建立子函数,在主程序中进行调用。


问题描述

将全局变量传入子函数,子函数中对局部变量进行修改导致全局变量发生。

示例代码:

import numpy as np
def softmax(lx):
    lx -= np.max(lx, axis = 1, keepdims = True)
    print("lx:\n",lx)
    print("全局变量x地址与局部变量地址是否相同:", id_x==id(lx))
    lx = np.exp(lx) / np.sum(np.exp(lx), axis = 1, keepdims=True)
    return lx
x = np.array([[5,3,1,1],[0.5,0.3,0.1,0.1]])
print("运算前X:\n",x)
id_x = id(x)
y = softmax(x)
print("运算后X:\n",x)
print("y:\n",y)

代码结果:

运算前X:
 [[5.  3.  1.  1. ]
 [0.5 0.3 0.1 0.1]]
lx:
 [[ 0.  -2.  -4.  -4. ]
 [ 0.  -0.2 -0.4 -0.4]]
全局变量x地址与局部变量地址是否相同: True
运算后X:
 [[ 0.  -2.  -4.  -4. ]
 [ 0.  -0.2 -0.4 -0.4]]
y:
 [[0.85326667 0.11547709 0.01562812 0.01562812]
 [0.31651871 0.25914361 0.21216884 0.21216884]]

原因分析:

在 python 中,对象才有类型,变量是没有类型的(例如:a=5, 那么5就是对象,int型;a是变量,没有类型,是一个对象的引用(一个指针))。

对象的类型可以分为两类:
1.不可变类型:变量赋值 a=5 后再赋值 a=10,这里实际是新生成一个 int 值对象 10,再让 a 指向它,而 5 被丢弃,不是改变a的值,相当于新生成了a。
2.可变类型:变量赋值 la=[1,2,3,4] 后再赋值 la[2]=5 则是将 list la 的第三个元素值更改,本身la没有动,只是其内部的一部分值被修改了。

python 函数的参数传递:
1.不可变类型:类似 c++ 的值传递,如 整数、字符串、元组。如fun(a),传递的只是a的值,没有影响a对象本身。比如在 fun(a)内部修改 a 的值,只是修改另一个复制的对象,不会影响 a 本身。
2.可变类型:类似 c++ 的引用传递,如 列表,字典。如 fun(la),则是将 la 真正的传过去,修改后fun外部的la也会受影响


解决方案:

使用copy函数,将全局变量的值传递给局部变量。

import numpy as np
def softmax(llx):
    lx = llx.copy()
    lx -= np.max(lx, axis = 1, keepdims = True)
    print("lx:\n",lx)
    print("全局变量x地址与局部变量地址是否相同:", id_x==id(lx))
    lx = np.exp(lx) / np.sum(np.exp(lx), axis = 1, keepdims=True)
    return lx
x = np.array([[5,3,1,1],[0.5,0.3,0.1,0.1]])
print("运算前X:\n",x)
id_x = id(x)
y = softmax(x)
print("运算后X:\n",x)
print("y:\n",y)

代码结果:

运算前X:
 [[5.  3.  1.  1. ]
 [0.5 0.3 0.1 0.1]]
lx:
 [[ 0.  -2.  -4.  -4. ]
 [ 0.  -0.2 -0.4 -0.4]]
全局变量x地址与局部变量地址是否相同: False
运算后X:
 [[5.  3.  1.  1. ]
 [0.5 0.3 0.1 0.1]]
y:
 [[0.85326667 0.11547709 0.01562812 0.01562812]
 [0.31651871 0.25914361 0.21216884 0.21216884]]

参考文档

你可能感兴趣的:(python,python)