Класс, dict, self, init, args?

class attrdict(dict):
    def __init__(self, *args, **kwargs):
        dict.__init__(self, *args, **kwargs)
        self.__dict__ = self

a = attrdict(x=1, y=2)
print a.x, a.y

b = attrdict()
b.x, b.y  = 1, 2
print b.x, b.y

Может кто-нибудь объяснить первые четыре строки словами? Я читал о классах и методах. Но здесь это кажется очень запутанным.

Ответ 1

Вы не используете позиционные аргументы в своем примере. Соответствующий код:

class attrdict(dict):
    def __init__(self, **kwargs):
        dict.__init__(self, **kwargs)
        self.__dict__ = self

В первой строке вы определяете класс attrdict как подкласс dict. Во второй строке вы определяете функцию, которая автоматически инициализирует ваш экземпляр. Вы передаете аргументы ключевого слова (**kargs) этой функции. Когда вы создаете экземпляр a:

 a = attrdict(x=1, y=2)

вы на самом деле вызываете

attrdict.__init__(a, {'x':1, 'y':2})
Инициализация ядра элемента p > dict выполняется инициализацией встроенного суперкласса dict. Это делается в третьей строке, передающей параметры, полученные в attrdict.__init__. Таким образом,
dict.__init__(self,{'x':1, 'y':2})

делает self (экземпляр a) словарь:

self ==  {'x':1, 'y':2}

Хорошая вещь встречается в последней строке: Каждый экземпляр имеет словарь, содержащий его атрибуты. Это self.__dict__ (т.е. a.__dict__).

Например, если

a.__dict__ = {'x':1, 'y':2} 

мы могли бы написать a.x или a.y и получить значения 1 или 2. соответственно.

Итак, это то, что делает строка 4:

self.__dict__ = self

эквивалентно:

a.__dict__ = a  where a = {'x':1, 'y':2}

Тогда я могу вызвать a.x и a.y.

Надежда не слишком грязная.

Ответ 2

Мой снимок поэтапного объяснения:

class attrdict(dict):

Эта строка объявляет класс attrdict как подкласс встроенного класса dict.

def __init__(self, *args, **kwargs): 
    dict.__init__(self, *args, **kwargs)

Это ваш стандартный метод __init__. Вызов dict.__init__(...) - использовать супер class (в данном случае, dict) конструктор (__init__).

Конечная строка self.__dict__ = self делает так, чтобы ключевые слова-аргументы (kwargs), которые вы передаете методу __init__, можно получить как атрибуты, например, a.x, a.y в коде ниже.

Надеюсь, это поможет устранить вашу путаницу.

Ответ 3

Вот хорошая статья, в которой объясняется __dict__:

Динамический dict

Класс attrdict использует это, наследуя от словаря, а затем устанавливает объект __dict__ в этот словарь. Таким образом, любой доступ к атрибуту происходит против родительского словаря (т.е. Класса dict, который он наследует).

Остальная часть статьи также хороша для понимания объектов Python:

Атрибуты и методы Python