使用继承,实例化,* args,** kwargs在代码中混淆

时间:2012-06-24 11:55:07

标签: python class

class Pen(object):
    def __init__(self, mean_radius = None, length = None):
        self.usage = "Is used to apply ink trails to drawing surfaces"
        self.mean_radius = mean_radius
        self.length = length

class FountainPen(Pen):
    def __init__(self, manufacturer = "Waterman", *args, **kwargs):
        Pen.__init__(self, *args, **kwargs)
        self.manufacturer = manufacturer
        self.cartridge_state =  "non-empty"

>>> instance_FP = FountainPen(5, 1)
>>> instance_FP.mean_radius
>>> print instance_FP.mean_radius
1    
>>> print instance_FP.length
None

5实例化中作为参数传递的整数FountainPen会发生什么? 为什么print instance_FP.mean_radius会返回1而不是5

4 个答案:

答案 0 :(得分:6)

你必须这样认为:*args**kwargs“吃掉”它们之前的“常规”参数留下的所有位置/关键字参数。如果你把它们放在最后,它们只会得到任何不符合“常规参数”的东西。

所以,当你写FountainPen(5,1)时,会发生FountainPen.__init__被调用的事情:

  • self设置为新创建的实例;
  • manufacturer获取第一个参数,即5;
  • *args“吃掉”所有剩余的位置参数,即1;因此,args现已设置为[1];
  • *kwargs会留下任何关键字参数,但没有,所以它变为{}

很明显,调用Pen.__init__仅使用1作为参数(self除外),length仍然设置为其默认值(None )。

答案 1 :(得分:2)

Matteo Italia提到了什么是错的,基本上manufacturer是一个位置论证。您可以稍微将FountainPen的{​​{1}}更改为以下内容来解决此问题:

__init__

执行此操作会使def __init__(self, *args, manufacturer = "Waterman", **kwargs): 成为关键字参数,因此要更改它,您必须调用:

manufacturer

注意:不幸的是,这种语法(在FountainPen(manufacturer="newval") 参数之后只有关键字参数)只在Python 3中有效.Jon Clements有一个solution可以解决Python 2的这个问题。

答案 2 :(得分:2)

更优雅的解决方案是:

class FountainPen(Pen):
    def __init__(self, *args, **kwargs):
        Pen.__init__(self, *args, **kwargs)
        self.manufacturer = kwargs.get('manufacturer', 'Waterman')
        self.cartridge_state =  "non-empty"

blah = FountainPen(5, 1, manufacturer='Waterman')

答案 3 :(得分:0)

在您的代码中,5分配给参数manufacturer,1分配给*args

将没有键的参数传递给函数时,必须首先提供显式的参数。其余的传递给* args。为避免这种情况,请在调用构造函数时提供关键字:

>>> instance_FP = FountainPen(mean_radius=5, length=1)