2011-11-18 9 views
58

Supponiamo di avere una classe con un costruttore (o un'altra funzione) che accetta un numero variabile di argomenti e quindi li imposta come attributi di classe in modo condizionale.Come è possibile impostare gli attributi di classe dagli argomenti variabili (kwargs) in python

Potrei impostarli manualmente, ma sembra che i parametri variabili siano abbastanza comuni in python che ci dovrebbe essere un idioma comune per farlo. Ma non sono sicuro di come farlo dinamicamente.

Ho un esempio con eval, ma non è sicuro. Voglio sapere il modo corretto di farlo, magari con 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

Sembra che queste domande sono simili: http://stackoverflow.com/questions/3884612/automatically-setting-class-member- variables-in-python http://stackoverflow.com/questions/356718/how-to-handle-constructors-or-methods-with-a-different-set-or-type-of-argument http: // stackoverflow. it/questions/1446555/python-decorator-to-ensure-that-kwargs-are-correct in modo che assomigli a ciò che voglio è forse questo --- self .__ dict __ [chiave] = kwargs [chiave] – fijiaaron

+0

Non proprio pertinente per il tuo domanda, ma potresti voler controllare [PEP8] (http://www.python.org/dev/peps/pep-0008/) per alcuni suggerimenti sullo stile Python convenzionale. –

+0

C'è una fantastica libreria per questo chiamato attrs. semplicemente 'pip install attrs', decora la tua classe con' @ attr.s', e imposta gli argomenti come 'a = attr.ib(); b = attr.ib() 'ecc. Leggi di più [qui] (https://glyph.twistedmatrix.com/2016/08/attrs.html). –

risposta

105

È possibile utilizzare il metodo setattr:

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

C'è un getattr metodo analogo per il recupero di attributi.

+0

@larsks, grazie, ma qualche idea su come possiamo decomprimere solo una chiave del dizionario? http://stackoverflow.com/questions/41792761/calling-and-using-an-attribute-stored-in-variable-using-beautifulsoup-4 – JinSnow

0

loro potrebbe essere una soluzione migliore, ma quello che viene in mente per me è:

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

Quello che sto cercando è impostare in modo condizionale gli attributi in base alla convalida. Mi sono reso conto che il problema con l'utilizzo di kwargs è che non convalida (o documenta) quali attributi sono accettabili – fijiaaron

+0

Sì, mi rendo conto che la risposta di @larsks è migliore. Impara qualcosa di nuovo ogni giorno in SO! – Tom

-1

ho il sospetto che potrebbe essere migliore nella maggior parte dei casi da usare args nome (per una migliore codice di autoregolamentazione che documentano) in modo che potrebbe apparire qualcosa di simile:

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

Questa iterazione non funziona: 'per chiave, valore 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 

ho chiamato la classe SymbolDict perché essenzialmente è un dizionario che opera utilizzando i simboli invece di stringhe. In altre parole, fai x.foo invece di x['foo'] ma sotto le coperte è davvero la stessa cosa che succede.

65

Non è ancora più semplice?

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

allora si può:

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

e con qualcosa di simile:

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

si potrebbe filtrare le chiavi in ​​anticipo.

+1

Ancora meglio per rendere permessi i set_keys :) – PascalVKooten

4

propongo una variante di risposta fqxp s', che, oltre a permesso attributi, consente di impostare valori predefiniti per gli attributi:

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) 

Si tratta di Python 3.x codice, per Python 2.x è necessaria almeno una regolazione, iteritems() al posto di items().

1

questo è il modo più semplice tramite larsks

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

il mio esempio:

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

potrebbe smb spiegare cos'è kwargs.items()? –

+0

'kwargs' è un dizionario di argomenti di parole chiave, e' items() 'è un metodo che restituisce una copia dell'elenco di' 'chiave, valore '' delle coppie di dizionari. – harryscholes

4

La maggior parte delle risposte qui non coprono un buon modo per inizializzare tutte permesso attributi ad un solo valore di default. Quindi, per aggiungere alle risposte fornite dal @fqxp e @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

Penso che questa sia la risposta più completa a causa della inizializzazione di 'False'. Buon punto! – Kyrol

Problemi correlati