2010-03-29 19 views
14

Czy istnieje sposób, który można zdefiniować __init__, aby słowa kluczowe zdefiniowane w **kwargs zostały przypisane do tej klasy?Jak skopiować ** kwargs do siebie?

Na przykład, jeśli mam zainicjować klasę ValidationRule z ValidationRule(other='email'), wartość dla self.other powinna zostać dodana do klasy bez konieczności jawnego nazwania każdego możliwego kwarg.

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

Czy istnieje powód, dla którego nie używasz zajęć w nowym stylu? –

+0

@ Georg: Nie wiem nawet, jakie są zajęcia w nowym stylu? Używam Pythona 2.5, jeśli jest to istotne. – mpen

+3

Aby utworzyć klasę newstyle, musisz dziedziczyć po klasie newstyle (zazwyczaj 'object'), więc użyj klasy ValidationRule (object):' Więcej informacji tutaj: http://www.python.org/doc/newstyle/ –

Odpowiedz

10

To może nie być najczystszy sposób, ale działa:

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

Chyba wolę ony's solution ponieważ ogranicza dostępne właściwości aby utrzymać się z dala od kłopotów, gdy wejście pochodzi ze źródeł zewnętrznych.

+0

Nie będzie działać poprawnie, jeśli zmienna jest "magiczna". Rozważ [propeties] (http://docs.python.org/2/library/functions.html#property) i [slotted objects] (http://docs.python.org/2/reference/datamodel.html?highlight = __ slotów __ # gniazd). Dotyczy to zarówno Python 2, jak i Python 3. – WGH

11

Można zrobić coś takiego:

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

Jeśli lista kwargs jest długa, możesz użyć * iteritems() * zamiast * items() *. Dla twojego celu powinno to jednak być w porządku. –

+0

@ GeorgSchölly Jaka jest różnica między 'iteritems()' a 'items()'? –

+0

@StevenVascellaro W Pythonie 2 'iteritems()', zwraca generator, podczas gdy 'items()' zwraca listę. W Pythonie 3 'items()' zwraca widok elementu, a 'iteritems()' został usunięty. Wolę 'items()', ponieważ jest kompatybilny z obydwoma. W przypadku bardzo dużych dyktorów nadal używam 'iteritems()'. Zobacz także https: // stackoverflow.com/questions/13998492/iteritems-in-python –

17

myślę somewhere on the stackoverflow Widziałem takie rozwiązanie. Zresztą może to wyglądać tak:

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) 

Klasa ta będzie akceptować tylko argumenty z białej listy nazw atrybutów wymienionych w __allowed.

+0

ValidationRule jest moją podstawową klasą i nie ma żadnych własnych atrybutów, więc nie ma niczego, co mogłoby przypadkowo nadpisać, ale poza tym byłoby to dobre bezpieczny strażnik;) Prawdopodobnie użyłbym czarnej listy zamiast białej listy w tym przypadku, aby nie ograniczać ich zbytnio. – mpen

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

Można ustawić argumenty kwargs, aktualizując atrybut __dict__ instancji.

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

znalazłem powyższe odpowiedzi pomocny i następnie rafinowana:

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) 

Test:

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

i walidacja jest również tam:

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

Mogłoby to zostać uznane ładniejsza niż aktualizacja __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'