Как вы можете установить атрибуты класса из переменных аргументов (kwargs) в python


Предположим у меня есть класс с конструктором (или другой функции), которая принимает переменное число аргументов, а затем устанавливает их в качестве атрибутов класса условно.

Я мог бы установить их вручную, но кажется, что переменные параметры достаточно распространены в python, что для этого должна быть общая идиома. Но я не уверен, как это сделать динамически.

У меня есть пример использования eval, но это вряд ли безопасно. Я хочу знать правильный способ сделать это -- может лямда?

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])
8 68

8 ответов:

вы можете обновить __dict__ атрибут (который представляет атрибуты класса в виде словаря) с ключевыми аргументами:

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

затем вы можете:

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

и с чем-то вроде:

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

вы можете фильтровать ключи заранее (используйте iteritems вместо items если вы все еще используете Python 2.икс.)

можно использовать setattr() способ:

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

есть аналог getattr() метод извлечения атрибутов.

большинство ответов здесь не охватывают хороший способ инициализации всех разрешенных атрибутов только до одного значения по умолчанию. Итак, чтобы добавить к ответам, данным @fqxp и @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)

Я предлагаю вариант ответ fqxp, который, помимо атрибуты, позволяет установить значения по умолчанию для атрибутов:

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)

Это Python 3.X код, для Python 2.x вам нужна хотя бы одна настройка, iteritems() на месте items().

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

Я вызвал класс SymbolDict потому что это по существу словарь, который работает с использованием символов вместо строк. Другими словами, вы делаете x.foo вместо x['foo'] но под одеялом это действительно то же самое происходит.

этот самый простой через larsks

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

мой пример:

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

их может быть лучшим решением, но то, что приходит мне на ум:

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}

Я подозреваю, что в большинстве случаев лучше использовать именованные args (для лучшего самодокументирования кода), поэтому это может выглядеть примерно так:

class Foo:
    def setAll(a=None, b=None, c=None):
        for key, value in (a, b, c):
            if (value != None):
                settattr(self, key, value)