Python中为何函数用layers_dim无报错,用layerss_dim等提示未定义?
我定义了如下Python代码:
### CONSTANTS ### layer_dims = [12288, 20, 7, 5, 1] # 4-layer model def initialize_parameters_deep(**layer_dims): """ Arguments: layer_dims -- python array (list) containing the dimensions of each layer in our network Returns: parameters -- python dictionary containing your parameters "W1", "b1", ..., "WL", "bL": Wl -- weight matrix of shape (layer_dims[l], layer_dims[l-1]) bl -- bias vector of shape (layer_dims[l], 1) """ np.random.seed(1) parameters = {} L = len(layer_dims) # number of layers in the network for l in range(1, L): parameters['W' + str(l)] = np.random.randn(layer_dims[l], layer_dims[l-1]) / np.sqrt(layer_dims[l-1]) #*0.01 parameters['b' + str(l)] = np.zeros((layer_dims[l], 1)) assert(parameters['W' + str(l)].shape == (layer_dims[l], layer_dims[l-1])) assert(parameters['b' + str(l)].shape == (layer_dims[l], 1)) return parameters
我定义了常量layer_dims,但将函数参数改为layers_dim时运行无报错;改为layerss_dim、blablabla或layer_dimsss等名称时,会出现类似“layerss_dim is not defined”的错误。想请教为何会出现这种差异?
这背后的核心原因和Python的**可变关键字参数(**kwargs语法)**以及变量作用域有关,咱们一步步拆解:
先看你原始函数的参数写法:
**layer_dims
这种双星号开头的参数是Python的可变关键字参数,它的作用是把调用函数时传入的所有关键字参数打包成一个字典,参数名(这里是layer_dims)就是这个字典的名字。如果调用函数时不传任何关键字参数,这个字典就是空的——这也是你能正常运行的前提之一。为什么改成
layers_dim时不报错?
如果修改后的函数参数是**layers_dim(依然保留双星号),那本质上和原来的逻辑完全一致:调用时不传参的话,layers_dim就是一个空字典,函数里的len(layers_dim)得到0,循环range(1, 0)不会执行,最终返回空的parameters字典,不会触发报错。
如果是你不小心去掉了双星号,写成了普通参数layers_dim但运行没报错,那大概率是你函数内部的代码并没有使用这个形参,而是直接引用了全局变量layer_dims——Python会在局部作用域找不到变量时,自动去全局作用域查找,所以依然能正常运行。为什么改成
layerss_dim这类名字会报错?
报错提示“layerss_dim is not defined”通常有两种场景:
- 场景一:去掉了双星号,变成普通参数
如果把参数改成普通的layerss_dim(没有双星号),但调用函数时没有传入对应的实参(比如你写了initialize_parameters_deep()而不是initialize_parameters_deep(layer_dims)),Python就会提示缺少位置参数;如果你调用时写错了实参名(比如写了initialize_parameters_deep(layerss_dim)),但你根本没定义过名为layerss_dim的变量,自然会报“not defined”。 - 场景二:修改了参数名但没同步改函数内部的引用
如果你把函数参数改成layerss_dim,同时把函数内部所有layer_dims的引用都改成了layerss_dim,但调用时还是传入原来的全局变量layer_dims,这时候不会报错;但如果调用时没传参,或者传参错误,就会触发变量未定义的报错。
给你个小建议:如果你的函数是要接收layer_dims这个列表作为输入,应该用普通参数(不要双星号),并且调用时明确传入全局变量,比如:
def initialize_parameters_deep(layer_dims): # 函数内部逻辑不变 ... # 调用时传入全局的layer_dims parameters = initialize_parameters_deep(layer_dims)
这样逻辑更清晰,也不容易出现这类变量名混淆的问题。
内容的提问来源于stack exchange,提问作者Gerrit

