包装外部类的__init__以忽略多余的参数



我有一个第三方类,它在其__init__方法中接受许多参数。

class ThirdPartyClass:
def __init__(self, a, b, c):
pass

我希望能够实例化字典中给定多余参数的类(如下所示),由于参数de而抛出错误。

params = {"a": 1, "b": 2, "c":3, "d": 4, "e": 5}
ThirdPartyClass(**params)

我如何编写一个方便的包装器,其工作原理类似于将**kwargs添加到ThirdPartyClass__init__,而不以任何方式修改ThirdPartyClass的源代码?

当然,我可以编写自己的ThirdPartyClass模拟类,但我更喜欢更好的解决方案。

非常感谢!

编辑:我不想硬编码参数名称。不过,我可能可以使用inspect来完成这项工作。此外,解决方案应该是通用的,并适用于任何外部第三方类。

如果您需要一个完全通用的解决方案,可能最优雅的方法是编写一个装饰器。这将适用于函数和类,因为它们都是可调用的(在实例化类时调用类)。您可以将具有@语法的装饰器应用到您自己的代码中,或者将其用作包装库代码的高阶函数。

为了能够处理任意函数签名,我们将使用inspect模块来计算参数名称。有两点需要注意:

  • 如果函数已经有一个参数来接受可变关键字参数(**kwargs或其他名称),那么我们不需要改变任何东西,而且确实不应该改变任何东西。

  • 否则,如果函数有一个参数接受可变位置参数(*args,或其他名称),那么它的名称在调用的参数中不可用,在过滤传入关键字参数时应排除。

:

from functools import wraps
from inspect import signature, Parameter
def ignore_extra_keywords(func):
params = signature(func).parameters.values()
if any(p.kind == Parameter.VAR_KEYWORD for p in params):
return func
names = {p.name for p in params if p.kind != Parameter.VAR_POSITIONAL}
@wraps(func)
def wrapper(*args, **kwargs):
# using `names` as a closure
return func(*args, **{k: kwargs[k] for k in (kwargs.keys() & names)})
return wrapper

现在我们可以做

ignore_extra_keywords(ThirdPartyClass)(**params)

@ignore_extra_keywords
def my_func(a, b, c):
print(f'I got: {a}, {b}, {c}')
my_func(1, b=2, c=3, d=4)

知道"a"、"b"one_answers"c"是好的参数吗?

class ThirdPartyClass:
def __init__(self, a, b, c):
pass
bad_params = {"a": 1, "b": 2, "c":3, "d": 4, "e": 5}
good_keys = ["a", "b", "c"]
good_params = {}
for k,v in bad_params.items():
if k in good_keys:
good_params[k] = v
ThirdPartyClass(**good_params)

在线词典:

good_params = {k:v for (k,v) in bad_params.items() if k in good_keys}

如果知道的参数,可以这样写:

{k:params[k] for k in (params.keys() & {'a','b','c'})}

返回

{'a': 1, 'b': 2, 'c': 3}

在本例中

因此,代码的效果可以是:

obj = ThirdPartyClass(**{k:params[k] for k in (params.keys() & {'a','b','c'})})

如果你不知道正确的参数,你可以使用:

import inspect
correct_parameters = set(inspect.signature(ThirdPartyClass).parameters)

就变成了

obj = ThirdPartyClass(**{k:params[k] for k in (params.keys() & correct_paramters)})

相关内容

最新更新