假设我有两个班级......
class A:
def __init__(self, *args, arg1="default1", arg2="default2"):
# Initialise class A
class B:
def __init__(self, arg3="default3", arg4="default4"):
# Initialise class B
每个类都有自己的关键字参数,其中一个有位置参数。
现在假设有一个函数可以创建每个类的实例,使用自己的参数来执行此操作:
def make_objs(*args, arg1="default1", arg2="default2", arg3="default3", arg4="default4"):
objA = ClassA(*args, arg1=arg1, arg2=arg2)
objB = ClassB(arg3=arg3, arg4=arg4)
这里我手动将函数接收的关键字参数分配给正确的类。这有点单调乏味 - 我必须在函数定义中复制关键字,更改类将意味着更改函数的参数。
理想情况下,我会做这样的事情:
def make_objs(*args, **kwargs):
objA = ClassA(*args, **kwargs)
objB = ClassB(**kwargs)
每个类将获取所有关键字参数,并仅提取与其相关的参数。这不是上面代码实际上会做的事情,它会抛出异常,因为ClassA
不期望一个名为arg3
的参数。
有没有这样做?某种方法使函数将**kwargs
作为参数并确定哪些参数可以转到哪个类?
答案 0 :(得分:1)
为避免所有重复输入,您可以创建一个实用程序函数,该函数使用inspect
模块检查所涉及的函数/方法的调用顺序。
这是将代码应用于代码的可运行示例。效用函数是名为get_kwarg_names
:
from inspect import signature, Parameter
class ClassA:
def __init__(self, *args, arg1="default1", arg2="default2"):
print('ClassA.__init__(): '
'*args={}, arg1={!r}, arg2={!r}'.format(args, arg1, arg2))
class ClassB:
def __init__(self, arg3="default3", arg4="default4"):
print('ClassB.__init__(): arg3={!r}, arg4={!r}'.format(arg3, arg4))
def get_kwarg_names(function):
""" Return a list of keyword argument names function accepts. """
sig = signature(function)
keywords = []
for param in sig.parameters.values():
if(param.kind == Parameter.KEYWORD_ONLY or
(param.kind == Parameter.POSITIONAL_OR_KEYWORD and
param.default != Parameter.empty)):
keywords.append(param.name)
return keywords
# Sample usage of utility function above.
def make_objs(*args, arg1="default1", arg2="default2",
arg3="default3", arg4="default4"):
local_namespace = locals()
classA_kwargs = {keyword: local_namespace[keyword]
for keyword in get_kwarg_names(ClassA.__init__)}
objA = ClassA(*args, **classA_kwargs)
classB_kwargs = {keyword: local_namespace[keyword]
for keyword in get_kwarg_names(ClassB.__init__)}
objB = ClassB(**classB_kwargs)
make_objs(1, 2, arg1="val1", arg2="val2", arg4="val4")
输出:
ClassA.__init__(): *args=(1, 2), arg1='val1', arg2='val2'
ClassB.__init__(): arg3='default3', arg4='val4'
答案 1 :(得分:0)
如果您在课程的*arg
方法中添加**kwargs
和__init__
,则可以实现您期望的行为。就像下面的例子中一样:
class A(object):
def __init__(self, a, b, *arg, **kwargs):
self.a = a
self.b = b
class B(object):
def __init__(self, c, d, *arg, **kwargs):
self.c = c
self.d = d
def make_objs(**kwargs):
objA = A(**kwargs)
objB = B(**kwargs)
make_objs(a='apple', b='ball', c='charlie', d='delta')
但需要注意的是,如果您打印objA.c
和objA.d
,则会在charlie
参数中返回delta
和make_objs
。
答案 2 :(得分:0)
class A:
def __init__(self, *args, a1 = 'd1', a2 = 'd2'):
self.a1 = a1
self.a2 = a2
class B:
def __init__(self, a3 = 'd3', a4 = 'd4'):
self.a3 = a3
self.a4 = a4
使用inpect.signature获取呼叫签名,然后在创建对象之前过滤kwargs
。
from inspect import signature
from inspect import Parameter
sig_a = signature(A)
sig_b = signature(B)
def f(*args, **kwargs):
d1 = {}
d2 = {}
for k, v in kwargs.items():
try:
if sig_a.parameters[k].kind in (Parameter.KEYWORD_ONLY,
Parameter.POSITIONAL_OR_KEYWORD,
Parameter.VAR_KEYWORD):
d1[k] = v
except KeyError:
pass
try:
if sig_b.parameters[k].kind in (Parameter.KEYWORD_ONLY,
Parameter.POSITIONAL_OR_KEYWORD,
Parameter.VAR_KEYWORD):
d2[k] = v
except KeyError:
pass
return (A(args, **d1), B(**d2))
d = {'a1':1, 'a2':2, 'a3':3, 'a4':4}
x, y = f(2, **d)
>>> x.a1
1
>>> x.a2
2
>>> y.a3
3
>>> y.a4
4
>>>
检查参数是否为关键字参数的检查可能过度。