两个关键字参数位置互换时发生错误
我遇到了一个奇怪的问题。我知道在Python中,关键字参数(kwargs)是跟在位置参数(args)后面的,所以我检查了这一点,发现这不是问题所在。问题在于:
这个是正常的:
def __init__(self, sample_rate, label=u"", data=[] ):
但是出现了这个错误:__init__()
收到了多个 'data' 关键字参数的值:
def __init__(self, sample_rate, data=[], label=u""):
导致错误的调用行看起来是这样的:
def __getslice__(self, start, stop):
return Channel(self.sample_rate, self.label, data=list.__getslice__(self,start,stop))
完整的代码是:
class Channel(list):
sample_rate = 0
def __init__(self, sample_rate, data=[], label=u"" ):
list.__init__(self,data)
self.sample_rate = sample_rate
self.label = label
@property
def nyquist_rate(self):
return float(self.sample_rate) / 2.0
def __getslice__(self, start, stop):
return Channel(self.sample_rate, self.label, data=list.__getslice__(self,start,stop))
谢谢!
3 个回答
问题在于你的调用代码中,有两个位置参数:
return Channel(self.sample_rate, self.label, data=list.__getslice__(self,start,stop))
# sample_rate (pos) data (pos) data (kw)
在Python 2.x中,函数定义时位置参数和关键字参数没有区别。当你调用一个函数时,位置参数会从左到右依次填充函数的参数,然后再绑定所有的关键字参数。在你的例子中,data
同时被位置参数和关键字参数绑定了。在另一种情况下,它之所以能正常工作,是因为第二个位置参数被用于label
,而data
只接收了关键字参数。
你是这样调用代码的:
Channel(self.sample_rate, self.label, data=list.__getslice__(self,start,stop))
注意,第二个参数没有指定关键字,所以解释器会认为这是 data
参数(因为在函数定义时它们的顺序就是这样)。如果你加上 label=
,应该就能解决这个问题。
不过,你的代码里还有一个更重要的错误:不要把 [] 作为默认值。原因是这个代码在定义函数的时候就会被计算。每次你调用这个代码而没有提供 data
参数时,你会得到同一个列表作为默认值。而且第一次之后,这个列表可能就不再是空的了!这对所有可变数据类型都是这样的。正确的做法是,把 None
作为默认值,然后在函数内部(每次运行的代码)检查参数值是否为 None,如果是的话就初始化一个新的 []。
(这个问题也被 David Goodger 解释得很好,详细内容可以查看 默认参数值)
在第二个版本中(def __init__(self, sample_rate, data=[], label=u""):
),第二个位置参数(也就是在调用时,不算self
)是data
,但是在__getslice__
中,你传入的第二个参数是label
。所以你要么保持label
作为第二个参数,要么把函数调用改成这样:
return Channel(self.sample_rate, label=self.label, data=list.__getslice__(self,start,stop))