如果我有这样的课程:
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中的参数吧? (这种做法本身有点脆弱,但更容易识别)。
答案 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开始的Signature
和Parameter
对象,如果参数可能会改变)。当然,这本身就有它自己的脆弱形式,因为使用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__
。