2010-03-29 11 views
14

Esiste un modo per definire __init__ in modo che le parole chiave definite in **kwargs siano assegnate alla classe?Come posso copiare ** kwargs in self?

Per esempio, se io fossi per inizializzare una classe ValidationRule con ValidationRule(other='email'), il valore per self.other dovrebbero essere aggiunti alla classe senza dover nominare esplicitamente ogni possibile kwarg.

class ValidationRule: 
    def __init__(self, **kwargs): 
     # code to assign **kwargs to .self 
+0

C'è un motivo per cui non stai utilizzando classi di nuovo stile? –

+0

@Georg: Non so nemmeno quali sono le classi di nuovo stile? Sto usando Python 2.5 se questo è rilevante. – mpen

+3

Per creare una classe newstyle è sufficiente ereditare da una classe newstyle (di solito 'object'), quindi utilizzare' class ValidationRule (object): 'Ulteriori informazioni qui: http://www.python.org/doc/newstyle/ –

risposta

10

Questo non può essere il modo più pulito, ma funziona:

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

credo di preferire ony's solution perché limita le proprietà disponibili per tenervi fuori dai guai quando l'input proviene da fonti esterne.

+0

Non funzionerà correttamente se la variabile è "magica". Considera [propties] (http://docs.python.org/2/library/functions.html#property) e [slotted objects] (http://docs.python.org/2/reference/datamodel.html?highlight = __ __ slot # slot). Questo vale sia per Python 2 che per Python 3. – WGH

11

Si potrebbe fare qualcosa di simile:

class ValidationRule: 
    def __init__(self, **kwargs): 
     for (k, v) in kwargs.items(): 
     setattr(self, k, v) 
+2

Se l'elenco di kwargs è lungo, è possibile utilizzare * iteritems() * anziché * items() *. Per il tuo scopo dovrebbe comunque andare bene. –

+0

@ GeorgSchölly Qual è la differenza tra 'iteritems()' e 'items()'? –

+0

@StevenVascellaro In Python 2 'iteritems()', restituisce un generatore mentre 'items()' restituisce una lista. In Python 3, 'items()' restituisce un itemview e 'iteritems()' è stato rimosso. Preferisco 'items()' perché è compatibile con entrambi. Per i dicts molto grandi, uso ancora 'iteritems()'. Vedi anche https: // StackOverflow.it/questions/13998492/iteritems-in-python –

17

Penso somewhere on the stackoverflow ho visto tale soluzione. In ogni caso si può apparire come:

class ValidationRule: 
    __allowed = ("other", "same", "different") 
    def __init__(self, **kwargs): 
     for k, v in kwargs.iteritems(): 
      assert(k in self.__class__.__allowed) 
      setattr(self, k, v) 

Questa classe accetta solo argomenti con un nomi degli attributi elencati nella whitelist __allowed.

+0

ValidationRule è solo la mia classe base, e non ha nessuno dei suoi attributi, quindi non c'è nulla che possano sovrascrivere accidentalmente, ma altrimenti sarebbe una buona guardia sicura;) Probabilmente userò una lista nera invece di una lista bianca in questo caso, in modo da non limitarli troppo. – mpen

3
class ValidationRule: 
    def __init__(self, **kwargs): 
     self.__dict__.update(kwargs) 
1

È possibile impostare gli argomenti kwargs aggiornando l'attributo __dict__ dell'istanza.

class ValidationRule: 
    def __init__(self, **kwargs): 
     self.__dict__.update(kwargs) 
-1

ho trovato le risposte di cui sopra utile e poi raffinato:

class MyObj(object): 
    def __init__(self, key1=1, key2=2, key3=3): 
     for (k, v) in locals().iteritems(): 
      if k != 'self': 
       setattr(self, k, v) 

prova:

>>> myobj = MyObj(key1=0) 
>>> print myobj.key1 
0 

e la validazione è anche lì:

>>> myobj = MyObj(key4=4) 
TypeError: __init__() got an unexpected keyword argument 'key4' 
1

Questo potrebbe essere considerato più bello dell'aggiornamento __dict__:

class C: 
    def __init__(self, **kwargs): 
     vars(self).update(kwargs) 

>>> c = C(a='a', b='b') 
>>> c.a # returns 'a' 
>>> c.b # returns 'b' 
Problemi correlati