*args 与 **kwargs 参数的疑惑

*args 与 **kwargs 参数的疑惑

看 wxPython 的源文件和其他一些用 wxPython 开发的程序(例如 Ulipad)的源文件,会发现有非常多的函数或类方法使用 *args 和 **kwargs 作为参数。

比如说吧,在 wxPython 的核心文件 _core.py 中,对于 wx.Image 类的 __init__() 方法的定义如下:

[Copy to clipboard] [ - ]
CODE:
    def __init__(self, *args, **kwargs):
        """
        __init__(self, String name, long type=BITMAP_TYPE_ANY, int index=-1) -> Image

        Loads an image from a file.
        """
        _core_.Image_swiginit(self,_core_.new_Image(*args, **kwargs))
    __swig_destroy__ = _core_.delete_Image
    __del__ = lambda self : None;

从上面这段代码可以看出,正常的参数自然是 self, *args, **kwargs 这三个。然而,如果你真的一板一眼地按照这种方式传递参数,比如说胡乱传递一个:

[Copy to clipboard] [ - ]
CODE:
image = wx.Image("ImageIcon", 32, 25, a = 23, b ="dafa")

这么构造对象自然是会报错的。

正确的方式当然是按照 doc 中的说明,使用 __init__(self, String name, long type=BITMAP_TYPE_ANY, int index=-1) 方式来构建对象。

因此,作为刚入门的菜鸟,我的疑问是:为什么会给出 def __init__(self, *args, **kwargs) 这种形式呢?如果没有后面的 doc 说明,那不是都不知道该如何传递正确的参数。

这篇文章我早看过了,但是无助于事啊。

它就不能解释为什么必须使用 __init__(self, String name, long type=BITMAP_TYPE_ANY, int index=-1)  的形式来构造 Image 对象,而不能使用 __init__(self, *args, **kwargs)  的形式
*args是一个tuple,**kwargs是一个dict,你这样传"ImageIcon", 32, 25, a = 23, b ="dafa"当然不行了,根本对应不上啊。


QUOTE:
原帖由 jjj137 于 2008-10-11 02:23 发表
*args是一个tuple,**kwargs是一个dict,你这样传"ImageIcon", 32, 25, a = 23, b ="dafa"当然不行了,根本对应不上啊。

其实传 "ImageIcon", 32, 25, a = 23, b ="dafa" 就等同于:

*args = ("ImageIcon", 32, 25)
**kwargs = {"a":23, "b":"dafa"}

这个怎么不行呢?
那你应该传("ImageIcon", 32, 25),{"a":23, "b":"dafa"}才能对应(不知道正不正确)。
要不然就利用特性,按说明去传。
很显然_core_.new_Image()只接受3个参数,你传了5个,当然不行。
传 ("ImageIcon", 32, 25),{"a":23, "b":"dafa"} 估计也不行吧?

本来正儿八经的调用就是传 (self, String name, long type=BITMAP_TYPE_ANY, int index=-1),这个才是对的。

我就是纳闷,为什么本来需要传 (self, String name, long type=BITMAP_TYPE_ANY, int index=-1),干嘛要写一个 (self, *args, **kwargs) 呢?搞得人都摸不清状况。


QUOTE:
原帖由 lephon 于 2008-10-11 16:58 发表
传 ("ImageIcon", 32, 25),{"a":23, "b":"dafa"} 估计也不行吧?

本来正儿八经的调用就是传 (self, String name, long type=BITMAP_TYPE_ANY, int index=-1),这个才是对的。

我就是纳闷,为什么本来需要 ...

这样参数就可变了啊。
比如有一个函数,既想接受self, String name, long type=BITMAP_TYPE_ANY,又可以接受self, int num, int index=-1,用这个直接处理*arg和**kwargs就可以了,否则用可选参数的话,就让人觉得莫名其妙。
当然这只是我个人的猜想,可能还有很多其他用法,比如你的例子中的,把它们交给其他函数,可以判断它们,然后传给不同的函数。


QUOTE:
原帖由 jjj137 于 2008-10-11 23:03 发表

这样参数就可变了啊。
比如有一个函数,既想接受self, String name, long type=BITMAP_TYPE_ANY,又可以接受self, int num, int index=-1,用这个直接处理*arg和**kwargs就可以了,否则用可选参数的话,就让 ...

哎呀,你说这样做的目的是参数可变,那既然这样,我传一个 (self, ("ImageIcon", 32, 25),{"a":23, "b":"dafa"}) 有何不行啊?怎么又会报错?


QUOTE:
原帖由 lephon 于 2008-10-12 11:04 发表


哎呀,你说这样做的目的是参数可变,那既然这样,我传一个 (self, ("ImageIcon", 32, 25),{"a":23, "b":"dafa"}) 有何不行啊?怎么又会报错?

估计这是特殊用法,既然*args代表了所有必须参数,**kwargs代表所有可选参数,那估计把 ("ImageIcon", 32, 25),{"a":23, "b":"dafa"}这个传到*args里面,变成( ("ImageIcon", 32, 25),{"a":23, "b":"dafa"})了,所以这样传还是不行的,只能按__doc__说的那么传。