На этом шаге мы рассмотрим способ решения указанной задачи.
Вам нужно создать экземпляр, но вы по какой-то причине хотите обойти выполнение метода __init__().
"Голый" экземпляр может быть создан с помощью прямого вызова метода класса __new__(). Например, рассмотрите такой класс:
>>> class Date: def __init__(self, year, month, day): self.year = year self.month = month self.day = day >>>
Вот как вы можете создать экземпляр Date без вызова init():
>>> d = Date.__new__(Date) >>> d <__main__.Date object at 0x000002E72EA19880> >>> d.year Traceback (most recent call last): File "<pyshell#4>", line 1, in <module> d.year AttributeError: 'Date' object has no attribute 'year' >>>
Как вы можете видеть, получившийся экземпляр не инициализирован. Поэтому теперь установка нужных переменных экземпляра лежит на вашей ответственности. Например:
>>> data = {'year': 2012, 'month': 8, 'day': 29}
>>> for key, value in data.items():
setattr(d, key, value)
>>> d.year
2012
>>> d.month
8
>>>
Задача обхода метода __init__() иногда возникает, когда экземпляры создаются нестандартным путем, таким как десериализация данных или реализация метода класса, определенного в качестве альтернативного конструктора. Например, в показанном классе Date некто может определить альтернативный конструктор today(), как показано тут:
from time import localtime class Date: def __init__(self, year, month, day): self.year = year self.month = month self.day = day @classmethod def today(cls): d = cls.__new__(cls) t = localtime() d.year = t.tm_year d.month = t.tm_mon d.day = t.tm_mday return d
При десериализации данных из JSON вы можете получить словарь, подобный этому:
data = {'year': 2012, 'month': 8, 'day': 29}
Если вы хотите превратить его в экземпляр Date, просто используйте показанный в решении прием.
При создании экземпляров нестандартным путем обычно лучше не делать слишком много предположений по поводу их реализации. В общем случае лучше не писать код, который напрямую манипулирует внутренним словарем __dict__, если вы не знаете точно, что он гарантированно будет определен. В противном случае код поломается, если класс использует __slots__, свойства, дескрипторы или другие продвинутые приемы. Если же вы будете использовать для присваивания значений setattr(), то ваш код будет настолько универсальным, насколько это возможно.
На следующем шаге мы рассмотрим расширение классов с помощью миксин (mixins).