python超级调用中的*args和**kwds

har*_*jay 10 python

我试图理解在Python中创建子类时的使用*args**kwds.

我想了解为什么这段代码的行为方式.如果我离开了*args,并**kwds在一个呼叫super().__init__,我得到一些奇怪的说法拆包.

这是我的测试用例:

class Animal(object):
    def __init__(self, moves, num_legs):
        self.moves = moves
        self.num_legs = num_legs

    def describe(self):
        print "Moves :{} , num_legs : {}".format(self.moves, self.num_legs)

class Snake(Animal):
    def __init__(self, poisonous, *args, **kwds):
        self.poisonous = poisonous
        print "I am poisonous:{}".format(self.poisonous)
        # This next line is key. You have to use *args , **kwds.
        # But here I have deliberately used the incorrect form,
        # `args` and `kwds`, and am suprised at what it does.
        super(Snake, self).__init__(args, kwds)
Run Code Online (Sandbox Code Playgroud)

现在,当我创建Snake子类的实例时,它包含对super(…).__init__(我使用的地方argskwds不是*args**kwds)的错误调用,我得到一些有趣的"参数解包".

s1 = Snake(False, moves=True, num_legs=0)
s2 = Snake(poisonous=False, moves=True, num_legs=1)
s3 = Snake(False, True, 3)
s1.describe()
s2.describe()
s3.describe()
Run Code Online (Sandbox Code Playgroud)

我得到的是:

Moves :() , num_legs : {'moves': True, 'num_legs': 0}
Moves :() , num_legs : {'moves': True, 'num_legs': 1}
Moves :(True, 3) , num_legs : {}
Run Code Online (Sandbox Code Playgroud)

那么为什么在s1s2__init__假定moves = True和/ num_legs = 0或是1关键字参数,并设置num_legs为dict?

s3,它将两个变量解包为moves(在类中Animal)作为元组.


当我试图理解参数解包时,我偶然发现了这一点.提前抱歉 - 我不知道如何更好地构建这个问题.

Chr*_*ial 9

In Snake.__init__,args是所有位置参数之后的元组,poisonous并且kwds是除了之外的所有关键字参数的字典poisonous.通过电话

super(Snake,self).__init__(args,kwds)
Run Code Online (Sandbox Code Playgroud)

分配argsmoveskwdsnum_legsAnimal.__init__.这正是您在输出中看到的.

前两个调用除了之外没有任何位置参数poisonous,因此args后果moves是一个空元组.第三个调用没有关键字参数,所以kwds后果num_legs是一个空字典.


Sim*_*ser 6

简而言之:def __init__(self,poisonous,*args,**kwds):意味着:捕获元组中的位置参数args和字典中的关键字参数kwds.类似地,super(Snake,self).__init__(*args, **kwds)意味着:将元组args和字典解包kwds为参数,以便它们分别传递给__init__.

如果你不使用*,并**然后你传递argskwds,因为他们,这意味着你得到一个元组和字典.


正如你所说,你需要写:

super(Snake,self).__init__(*args, **kwds)
Run Code Online (Sandbox Code Playgroud)

正确打包/解包参数.在您当前的代码中,您没有打包/解压缩参数,因此它设置num_legs为字典,就像kwds现在的情况一样.


如果你不给出参数名称,那么它们就是位置参数.因此Snake(False,True,3)都是位置论证.

如果你确实给出了参数名称,那么它们就是关键字参数:Snake(poisonous=False,moves=True,num_legs=1).

在第一种情况下,您将两个位置参数和两个关键字参数组合在一起:Snake(False,moves=True,num_legs=0).