我现在创建的对象是这样的:
class Obj(object):
def __init__(self,**kwargs):
params = ['val1','val2','val3','val4',...]
for p in params:
setattr(self,p,kwargs.get(p,None))
我这样做,所以我不需要这样做:
class Obj(object):
def __init__(self,val1=None,val2=None,val3=None,val4=None,...):
self.val1=val1
self.val2=val2
self.val3=val3
self.val4=val4
...
我的问题是,你能把两者结合起来吗?在哪里我可以定义预期的参数,但仍然循环参数来设置属性?我喜欢定义预期参数的想法,因为它是自记录的,其他开发人员不必搜索使用的kwargs。
我知道这看起来很琐碎,但是我是从一些XML创建一个对象,所以我将传入许多参数,这只会使代码混乱并使我感到困扰。
我谷歌了一下,但是找不到任何东西,可能是因为dictionary和kwargs一起指向kwarg的例子。
UPDATE:更具体地说,是否有可能获得传入参数的字典,因此我根本不必使用kwargs ?
Sudo代码:
class Obj(object):
def __init__(self,val1=None,val2=None,val3=None,val4=None,...):
for k,v in dictionary_of_paramters.iteritems():
setattr(self,k,v)
您可以使用inspect
模块:
import inspect
def myargs(val1, val2, val3=None, val4=5):
print inspect.currentframe().f_locals
显示当前栈帧中所有可用的局部变量。
myargs('a','b')
==> {'val3': None, 'val2': 'b', 'val1': 'a', 'val4': 5}
(注意:不能保证在所有Python解释器上实现)
edit:我同意这不是一个漂亮的解决方案。我要做的是:
def _yourargs(*names):
"returns a dict with your named local vars"
alllocs = inspect.stack()[1][0].f_locals
return {n:alllocs[n] for n in names}
def askformine(val1, val2, val3=None, val4=5):
"example to show just those args i'm interested in"
print _yourargs('val1','val2','val3','val4')
class Obj(object):
"example inserting some named args as instance attributes"
def __init__(self, arg1, arg2=4):
self.__dict__.update(_yourargs('arg1','arg2'))
edit2稍好:
def pickdict(d,*names):
"picks some values from a dict"
return {n:d[n] for n in names}
class Obj(object):
"example inserting some named args as instance attributes"
def __init__(self, arg1, arg2=4):
self.__dict__.update(pickdict(locals(),'arg1','arg2'))
没有很好的方法来获取函数的所有参数的字典。**kwargs
语法只收集额外的关键字参数,而不收集与函数定义中显式参数匹配的关键字参数。
虽然不使用kwargs或inspect模块(参见其他答案)就无法获取参数,但您可以这样做…
class Obj(object):
def __init__(self, **kwargs):
self.__dict__.update(**kwargs)
每个对象都有一个存储所有属性的字典,您可以通过self.__dict__
访问该字典。然后使用update来设置对象内部字典中的所有属性。
如果您想在定义任何局部变量之前,在方法的最顶部获得参数字典,这很简单,如下所示:
class Obj(object):
def __init__(self,val1=None,val2=None,val3=None,val4=None):
kwargs = dict(locals())
以后要读这个字典,需要一些自省魔法:
class Obj(object):
def __init__(self,val1=None,val2=None,val3=None,val4=None):
# feel free to add more locals
loc = dict(locals())
fun = sys._getframe().f_code
kwargs = {x:loc[x] for x in fun.co_varnames[:fun.co_argcount]}
还可以通过添加如下函数使后者可重用:
def getargs():
f = sys._getframe(1)
return {x:f.f_locals[x] for x in f.f_code.co_varnames[:f.f_code.co_argcount]}
然后:
class Obj(object):
def __init__(self,val1=None,val2=None,val3=None,val4=None):
# feel free to add more locals
kwargs = getargs()
可以将两者混合使用。见下文:
def method(a, b=1, *args, **kwargs):
'''some code'''
这是有效的。:
'a' is a required argument
'b' is a default argument
'args' will have all the non-keyword arguments and
'kwargs' will have all the keyword arguments.
的例子:
method(1,2,3,4,5,test=6,test1=7)
这个调用将有:
a=1
b=2
args=(3,4,5)
kwargs={'test':6,'test1':7}
一种丑陋的解决方法:在kwargs中注入额外的参数,并在你想循环遍历所有关键字参数的地方使用它(PS这是inspect模块的一个示例用法,但不建议在生产环境中使用):
#!/usr/bin/env python
import inspect
def inject_defaults(func):
""" injects '__defaults' key into into kwargs,
so it can be merged with kwargs in the decorated method """
args, varargs, varkwargs, defaults = inspect.getargspec(func)
have_defaults = args[-len(defaults):]
defaults_dict = dict(zip(have_defaults, defaults))
def fun(*args, **kwargs):
kwargs['__defaults'] = defaults_dict
return func(*args, **kwargs)
return fun
@inject_defaults
def f1(a,b,c, x=1, **kwargs):
kwargs.update(kwargs['__defaults'])
del kwargs['__defaults']
for k, v in kwargs.items():
# here, x, y and z will appear
print(k, v)
f1(1, 2, 3, y=3, z=2)
# prints
# ('y', 3)
# ('x', 1)
# ('z', 2)