Есть ли ярлык для `self.somevariable = somevariable` в конструкторе класса Python?

Конструкторы в Python часто выглядят так:

class SomeClass:
    def __init__(self, a, b = None, c = defC):
        self.a = a
        self.b = b or []
        self.c = c

Есть ли ярлык для этого, например. просто определить __init__(self,**kwargs) и использовать ключи как свойства self?

Ответ 1

Одна проблема с

self.__dict__.update(locals())

заключается в том, что он включает self, поэтому вы получаете self.self. Было бы лучше отфильтровать self из locals()

например.

vars(self).update((k,v) for k,v in vars().items() if k != 'self')

Вы можете защитить от случайных методов перезаписи с помощью этого варианта

vars(self).update((k,v) for k,v in vars().items()
                   if k != 'self' and k not in vars(self))

Если вы не хотите, чтобы он терпел неудачу, вы также можете проверить заранее, как это сделать

if any(k in vars(self) for k in vars()):
    raise blahblah
vars(self).update((k,v) for k,v in vars().items() if k != 'self')

Ответ 2

Одна идиома, которую я видел, это self.__dict__.update(locals()). Если вы запустите его в начале метода, это будет обновлять словарь объектов с помощью аргументов (так как это единственные локали в начале метода). Если вы пройдете **kwargs, вы можете сделать self.__dict__.update(**kwargs).

Конечно, это хрупкий подход. Это может привести к загадочным ошибкам, если вы случайно передадите аргумент, который маскирует существующий атрибут. Например, если ваш класс имеет метод .doSomething(), и вы случайно передаете конструктор doSomething=1, он переопределит этот метод и позже вызовет ошибку, если вы попытаетесь вызвать этот метод. По этой причине лучше не делать этого, кроме как в некоторых тривиальных случаях (например, какой-то прокси-объект, единственная цель которого состоит в том, чтобы служить "сумкой", содержащей несколько атрибутов).

Ответ 3

Да:

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