2011-11-18 183 views
58

假设有一个带有构造函数(或其他函数)的类,该类带有可变数量的参数,然后将它们有条件地设置为类属性。如何在python中设置可变参数(kwargs)的类属性

我可以手动设置它们,但似乎变量参数在python中已经足够普遍,应该有一个常见的习惯用法。但我不知道如何动态地做到这一点。

我有一个使用eval的例子,但这不是安全的。我想知道正确的方法来做到这一点 - 也许与lambda?

class Foo: 
    def setAllManually(self, a=None, b=None, c=None): 
     if a!=None: 
      self.a = a 
     if b!=None: 
      self.b = b 
     if c!=None: 
      self.c = c 
    def setAllWithEval(self, **kwargs): 
     for key in **kwargs: 
      if kwargs[param] != None 
       eval("self." + key + "=" + kwargs[param]) 
+0

它看起来像这些问题是相似的:http://stackoverflow.com/questions/3884612/automatically-setting-class-member-在python中的变量http://stackoverflow.com/questions/356718/how-to-handle-constructors-or-methods-with-a-different-set-or-type-of-argument http:// stackoverflow。 com/questions/1446555/python-decorator-to-ensure-that-kwargs-are-correct,因此它看起来像我想要的可能是this-- self .__ dict __ [key] = kwargs [key] – fijiaaron

+0

与你无关问题,但你可能想检查[PEP8](http://www.python.org/dev/peps/pep-0008/)关于传统Python样式的一些提示。 –

+0

这里有一个很棒的图书馆,叫做attrs。只需'pip install attrs',用'@ attr.s'装饰你的类,并设置参数为'a = attr.ib(); b = attr.ib()'等。阅读更多[这里](https://glyph.twistedmatrix.com/2016/08/attrs.html)。 –

回答

105

可以使用setattr方法:

class Foo: 
    def setAllWithKwArgs(self, **kwargs): 
    for key, value in kwargs.items(): 
     setattr(self, key, value) 

有检索属性类似getattr方法。

+0

@larsks谢谢,但任何想法如何我们只能解压字典密钥? http://stackoverflow.com/questions/41792761/calling-and-using-an-attribute-stored-in-variable-using-beautifulsoup-4 – JinSnow

0

他们可能是一个更好的解决方案,但会想到什么对我来说是:

class Test: 
    def __init__(self, *args, **kwargs): 
     self.args=dict(**kwargs) 

    def getkwargs(self): 
     print(self.args) 

t=Test(a=1, b=2, c="cats") 
t.getkwargs() 


python Test.py 
{'a': 1, 'c': 'cats', 'b': 2} 
+0

我正在寻找的是有条件地设置基于验证的属性。我意识到使用kwargs的问题在于它不验证(或文档)哪些属性可接受 – fijiaaron

+0

是的,我意识到@larsks回答更好。在SO学习每天新的东西! – Tom

-1

我怀疑这可能是在大多数情况下,最好使用命名ARGS(为了更好的自我记录的代码),所以它可能看起来是这样的:

class Foo: 
    def setAll(a=None, b=None, c=None): 
     for key, value in (a, b, c): 
      if (value != None): 
       settattr(self, key, value) 
+0

这个迭代不起作用:'for key,value in(a,b,c)' – rerx

2
class SymbolDict(object): 
    def __init__(self, **kwargs): 
    for key in kwargs: 
     setattr(self, key, kwargs[key]) 

x = SymbolDict(foo=1, bar='3') 
assert x.foo == 1 

我叫类SymbolDict,因为它本质上是经营用符号代替字符串的字典。换句话说,你做的是x.foo而不是x['foo'],但是在它的封面下它确实是一样的事情。

65

这难道不是更简单吗?

class Bar(object): 
    def __init__(self, **kwargs): 
     self.__dict__.update(kwargs) 

那么你可以:

>>> bar = Bar(a=1, b=2) 
>>> bar.a 
1 

和喜欢的东西:

allowed_keys = ['a', 'b', 'c'] 
self.__dict__.update((k, v) for k, v in kwargs.iteritems() if k in allowed_keys) 

,你可以事先筛选键。

+1

更好地设置allowed_keys一组:) :) – PascalVKooten

4

我建议fqxp的回答,其中,除了允许的属性的变化,可以让你设置默认值的属性:

class Foo(): 
    def __init__(self, **kwargs): 
     # define default attributes 
     default_attr = dict(a=0, b=None, c=True) 
     # define (additional) allowed attributes with no default value 
     more_allowed_attr = ['d','e','f'] 
     allowed_attr = list(default_attr.keys()) + more_allowed_attr 
     default_attr.update(kwargs) 
     self.__dict__.update((k,v) for k,v in default_attr.items() if k in allowed_attr) 

这是Python的3.x代码,对于Python 2.x,您至少需要一次调整,iteritems()代替items()

1

这一次是通过larsks

class Foo: 
    def setAllWithKwArgs(self, **kwargs): 
     for key, value in kwargs.items(): 
      setattr(self, key, value) 

我的例子最简单的:

class Foo: 
    def __init__(self, **kwargs): 
     for key, value in kwargs.items(): 
      setattr(self, key, value) 

door = Foo(size='180x70', color='red chestnut', material='oak') 
print(door.size) #180x70 
+0

可以解释什么是kwargs.items()? –

+0

'kwargs'是关键字参数的字典,'items()'是一个返回字典'(key,value)'对列表副本的方法。 – harryscholes

4

这里大部分的答案不包括一个很好的方式来初始化所有允许的属性只是一个默认值。 因此,要添加到@fqxp和@mmj给出的答案:

class Myclass: 

    def __init__(self, **kwargs): 
     # all those keys will be initialized as class attributes 
     allowed_keys = set(['attr1','attr2','attr3']) 
     # initialize all allowed keys to false 
     self.__dict__.update((key, False) for key in allowed_keys) 
     # and update the given keys by their given values 
     self.__dict__.update((key, value) for key, value in kwargs.items() if key in allowed_keys) 
+0

我认为这是最完整的答案,因为inisialization到'False'。好点子! – Kyrol

相关问题