捕获python中的许多args之一__init__

时间:2014-01-07 15:09:32

标签: python

如果我有这样的课程:

class foo(object):
    def __init__(self, a, b=None, c=None, d=None):
    print a, b, c, d

和这样的派生类:

class bar(foo):
    def __init__(self, *args, **kwargs):
        if "c" in kwargs:
            kwargs['c'] = 'else'  # CHANGE C IFF IT IS PRESENT
        super(bar, self).__init__(*args, **kwargs)

当有人调用此构造函数时,他们可以这样做:

bar('a','b','c','d')

或者他们可以这样称呼它:

bar('a', c='something')

在第二种情况下,我的构造函数按计划工作,但是在第一次调用c的情况下,在args数组中潜行。这看起来像我必须观察args数组的长度以及kwargs,这看起来很脆弱到无法使用的程度。有什么办法可以让这种情况变得更好,除了枚举foo中的参数吧? (这种做法本身有点脆弱,但更容易识别)。

2 个答案:

答案 0 :(得分:2)

如何使用kwargs填充args

class bar(foo):
    def __init__(self, *args, **kwargs):
        for name, value in zip(['a', 'b', 'c', 'd'], args): # <---
            kwargs[name] = value                            # <---
        args = ()                                           # <---
        if "c" in kwargs:
            kwargs['c'] = 'else'
        super(bar, self).__init__(*args, **kwargs)

<强>更新

使用inspect.getcallargs的替代方案:

import inspect

class bar(foo):
    def __init__(self, *args, **kwargs):
        kwargs = inspect.getcallargs(foo.__init__, self, *args, **kwargs)
        kwargs.pop('self')
        if 'c' in kwargs:
            kwargs['c'] = 'else'
        super(bar, self).__init__(**kwargs)

答案 1 :(得分:1)

这比你想象的要脆弱。您是否考虑过某人传递foo.__init__的参数列表中不存在的关键字参数的情况(例如bar('a', f='something'))?我的建议是要求bar仅使用关键字参数,然后过滤foo.__init__的参数列表中不存在的键(您可以使用inspect.getargspec [或相关函数通过内省来确定较新版本的Python,特别是从3.3开始的SignatureParameter对象,如果参数可能会改变)。当然,这本身就有它自己的脆弱形式,因为使用bar的程序员需要知道foo的构造函数的相关参数名称,但取决于bar是什么被用于他们可能需要知道什么参数foo无论如何,当有人知道他们通常知道参数的名称是什么时。

现在我再次查看inspect,我意识到您可以使用另一种方法:inspect.getcallargs,这可能对您更有用。有了这个,你可以这样做,inspect.getcallargs(super(bar, self).__init__, *[self, 1], **{'c':3, 'd':4})并获得以下词典:{'a': 1, 'self': <bar object>, 'b': None, 'c': 3, 'd': 4}。然后,您可以修改该字典并将其作为super(bar, self).__init__(**fixed_dict)或类似的东西提供。您仍然遇到foo.__init__的参数列表中不存在关键字参数的问题,但是(getcallargs在传递无效参数时会引发相同的错误foo.__init__