Setattr с kwargs, pythonic или нет?

Я использую __init__() как это в некоторых ORM-классах SQLAlchemy, которые имеют много параметров (до 20).

def __init__(self, **kwargs):
    for k, v in kwargs.iteritems():
        setattr(self, k, v)

Является ли это "pythonic" для установки таких атрибутов?

Ответы

Ответ 1

Да. Другой способ сделать это.

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

Ответ 2

Да, если нет "лучшего" способа подачи аргументов.

Например, используя ваши классы ORM, которые вы упомянули, возможно, это будет больше Python'y, чтобы разрешить...

col = Varchar()
col.index = True
col.length = 255

.. а не..

col = Varchar(index = True, length = 255)

Хорошо, что это не лучший пример, так как метод **kwargs был бы действительно приятнее.. но я хочу сказать, что вы всегда должны рассматривать альтернативные методы достижения чего-то, прежде чем использовать иногда обескураженные вещи, такие как **kwargs..

Еще одна вещь, о которой следует помнить, - это потерять поведение, которого ожидает пользователь, например, повышение типа TypeError, если пользователь поставляет недопустимое ключевое слово arg, которое можно было бы работать, как..

def __init__(self, **kwargs):
    valid_kwargs = ['x', 'y', 'z']
    for k, v in kwargs.iteritems():
        if k not in valid_kwargs:
            raise TypeError("Invalid keyword argument %s" % k)
        setattr(self, k, v)

Последнее, что нужно учитывать:

class Hmm:
    def __init__(self, **kwargs):
        for k, v in kwargs.iteritems():
            setattr(self, k, v)
    def mymethod(self):
        print "mymethod should print this message.."

x = Hmm(mymethod = None)
x.mymethod() # raises TypeError: 'NoneType' object is not callable

Ответ 3

Мне кажется, это довольно pythonic, если вам нужно только это в одном месте в вашем коде.

Следующая ссылка предоставляет более "общий" подход к одной и той же проблеме (например, с декоратором и некоторыми дополнительными функциями), посмотрите на: http://code.activestate.com/recipes/551763/