2010-03-29 11 views
14

¿Hay alguna manera de que pueda definir __init__ para que las palabras clave definidas en **kwargs se asignen a la clase?¿Cómo copio ** kwargs a mí mismo?

Por ejemplo, si tuviera que inicializar una clase ValidationRule con ValidationRule(other='email'), el valor de self.other debe añadirse a la clase sin tener que nombrar explícitamente cada posible kwarg.

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

¿Hay alguna razón por la que no esté utilizando las clases de nuevo estilo? –

+0

@Georg: ¿Ni siquiera sé qué son las clases de nuevo estilo? Estoy usando Python 2.5 si eso es relevante. – mpen

+3

Para crear una clase newstyle, solo necesita heredar de una clase newstyle (generalmente 'object') así que use' class ValidationRule (object): 'Más información aquí: http://www.python.org/doc/newstyle/ –

Respuesta

10

esto puede no ser la manera más limpia, pero funciona:

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

creo que prefiero ony's solution porque restringe propiedades disponibles para mantenerlo fuera de problemas cuando su entrada proviene de fuentes externas.

+0

No funcionará correctamente si la variable es "mágica". Considere [propeties] (http://docs.python.org/2/library/functions.html#property) y [objetos ranurados] (http://docs.python.org/2/reference/datamodel.html?highlight = __ ranuras __ # ranuras). Eso se aplica tanto a Python 2 como a Python 3. – WGH

11

se podría hacer algo como esto:

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

Si la lista kwargs es larga, es posible que desee utilizar * iteritems() * en lugar de * elementos() *. Para su propósito, eso debería estar bien, sin embargo. –

+0

@ GeorgSchölly ¿Cuál es la diferencia entre 'iteritems()' y 'items()'? –

+0

@StevenVascellaro En Python 2 'iteritems()', devuelve un generador mientras 'items()' devuelve una lista. En Python 3, 'items()' devuelve una vista de elemento y 'iteritems()' se eliminó. Prefiero 'items()' porque es compatible con ambos. Para dicts muy grandes, todavía uso 'iteritems()'. Ver también https: // stackoverflow.com/questions/13998492/iteritems-in-python –

17

creo somewhere on the stackoverflow que he visto tal solución. De todos modos puede verse como:

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) 

Esta clase sólo aceptará argumentos con una lista blanca nombres de los atributos enumerados en __allowed.

+0

ValidationRule es solo mi clase base, y no tiene ninguno de sus propios atributos, por lo que no hay nada que puedan sobrescribir accidentalmente, pero de lo contrario, sería una buena opción. safe guard;) Probablemente usaría una lista negra en lugar de una lista blanca en este caso, para no restringirlos demasiado. – mpen

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

Puede establecer sus argumentos kwargs actualizando el atributo __dict__ de la instancia.

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

He encontrado las respuestas anteriores útil y luego refinada:

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) 

prueba:

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

y validación también está ahí:

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

Esto podría ser considerado mejor que actualizar __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'