Как скопировать **kwargs себе?

Есть ли способ определить __init__, чтобы ключевые слова, определенные в **kwargs, были назначены классу?

Например, если бы мне нужно было инициализировать класс ValidationRule с помощью ValidationRule(other='email'), значение для self.other должно быть добавлено к классу без необходимости явно называть все возможные kwarg.

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

person mpen    schedule 29.03.2010    source источник
comment
Есть ли причина, по которой вы не используете классы нового стиля?   -  person Georg Schölly    schedule 29.03.2010
comment
@Georg: я даже не знаю, что такое классы нового стиля? Я использую Python 2.5, если это уместно.   -  person mpen    schedule 29.03.2010
comment
Чтобы создать класс нового стиля, вам просто нужно наследоваться от класса нового стиля (обычно object), поэтому используйте class ValidationRule(object): Подробнее здесь: python.org/doc/newstyle   -  person John La Rooy    schedule 29.03.2010
comment
Новый стиль..? кажется старым стилем в python3? это вообще там будет работать?   -  person holms    schedule 06.10.2015


Ответы (6)


Это может быть не самый чистый способ, но он работает:

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

Я думаю, что предпочитаю решение ony, потому что оно ограничивает доступные свойства, чтобы вы не проблемы, когда ваш вход поступает из внешних источников.

person Gabe    schedule 29.03.2010
comment
Это не будет работать правильно, если переменная является волшебной. Обратите внимание на свойства и объекты с прорезями. Это относится как к Python 2, так и к Python 3. - person WGH; 07.09.2013

Я думаю, что где-то в stackoverflow я видел такое решение. В любом случае это может выглядеть так:

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)

Этот класс будет принимать только аргументы с именами атрибутов из белого списка, перечисленными в __allowed.

person ony    schedule 29.03.2010
comment
ValidationRule — это всего лишь мой базовый класс, и у него нет собственных атрибутов, поэтому нет ничего, что они могли бы случайно перезаписать, но в остальном это было бы хорошей защитой;) Вместо этого я бы, вероятно, использовал черный список белого списка в этом случае, чтобы не ограничивать их слишком сильно. - person mpen; 29.03.2010
comment
Python-3 переименован в dict.iteritems -> dict.items, дополнительная информация - person Mr. Hobo; 05.01.2021
comment
Я не знаю, является ли это проблемой python3, но отправка недопустимого kwargs вызывает AssertionError в python 3.8. Я использовал try...catch, чтобы преодолеть это - person Mr. Hobo; 05.01.2021
comment
@Mr.Hobo, вы должны увидеть источник утверждения, и, скорее всего, он приведет к строке assert( k in self.__class__.__allowed ), которая должна обосновать последнее предложение ответа о проверке, и это единственная его роль;) Т.е. его можно удалить, если вам это не нравится, или заменить другим способом обработки этого. - person ony; 11.01.2021

Вы можете сделать что-то вроде этого:

class ValidationRule:
   def __init__(self, **kwargs):
      for (k, v) in kwargs.items():
         setattr(self, k, v)
person sth    schedule 29.03.2010
comment
Если список kwargs длинный, вы можете использовать iteritems() вместо items(). Хотя для вашей цели должно подойти. - person Georg Schölly; 29.03.2010
comment
@GeorgSchölly В чем разница между iteritems() и items()? - person Stevoisiak; 06.02.2018
comment
@StevenVascellaro В Python 2 iteritems() возвращает генератор, а items() возвращает список. В Python 3 items() возвращает представление элемента, а iteritems() было удалено. Я предпочитаю items(), потому что он совместим с обоими. Для очень больших диктов я все еще использую iteritems(). См. также stackoverflow.com/questions/13998492/iteritems-in-python. - person Georg Schölly; 07.02.2018

Вы можете установить аргументы kwargs, обновив атрибут __dict__ экземпляра.

class ValidationRule:
   def __init__(self, **kwargs):
       self.__dict__.update(kwargs)
person Ruslan Spivak    schedule 29.03.2010

Это можно считать более приятным, чем обновление __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'
person Greg    schedule 28.10.2015

Я нашел приведенные выше ответы полезными, а затем уточнил:

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)

Контрольная работа:

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

И валидация тоже есть:

>>> myobj = MyObj(key4=4)
TypeError: __init__() got an unexpected keyword argument 'key4'
person user394430    schedule 17.01.2012