2011-11-18 69 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

相關問題