关于python:两个关键字参数位置的交换引发错误

Interchange of Position of Two Keyword Arguments Throws Error

我有个奇怪的问题。我知道在python中,Kwargs遵循args,所以我检查了一下,这不是问题所在。问题是:

好的:

def __init__(self, sample_rate, label=u"", data=[] ):

类型错误:__init__()为关键字参数'data'获取了多个值:

def __init__(self, sample_rate, data=[], label=u""):

引发错误的调用行如下所示:

1
2
def __getslice__(self, start, stop):
    return Channel(self.sample_rate, self.label, data=list.__getslice__(self,start,stop))

完整代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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))

谢谢您!


在第二个版本(def __init__(self, sample_rate, data=[], label=u""):)中,第二个位置参数(当调用时,这意味着不计算self)是data,但在__getslice__中,您传递的第二个参数是label。因此,您应该将label作为第二个参数,或者将函数调用更改为:

1
return Channel(self.sample_rate, label=self.label, data=list.__getslice__(self,start,stop))


你用的是

1
Channel(self.sample_rate, self.label, data=list.__getslice__(self,start,stop))

注意,第二个参数没有关键字,所以解释器假定这是data参数(因为这是在函数中定义的顺序)。如果你加上label=,它就会解决问题。

但是,您的代码中有一个更重要的错误:不要将[]用作默认值。原因是此代码在函数定义时被评估。每次调用不带data参数的代码时,都会得到与默认值相同的列表。第一次之后它可能不会是空的!对于所有可变数据类型都是这样。正确的方法是使用None作为默认值,如果参数值为none,则在函数(每次运行的代码)内部初始化一个新的[]。(在默认参数值中,david goodger也很好地解释了这个gocha)


问题是,在调用代码中,有两个位置参数:

1
2
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只获取关键字参数。