У більшості відомих мов OO такий вираз SomeClass(arg1, arg2)
виділяє новий екземпляр, ініціалізує атрибути екземпляра та поверне його.
У більшості відомих мов OO частина «ініціалізація атрибутів екземпляра» може бути налаштована для кожного класу шляхом визначення конструктора , який в основному є лише кодом коду, який працює в новому екземплярі (використовуючи аргументи, надані виразу конструктора ) встановити будь-які початкові умови. У Python це відповідає __init__
методу class ' .
Python - __new__
це не більше і не менше, ніж аналогічна індивідуальна настройка частини "виділити новий екземпляр". Звичайно, це дозволяє робити незвичайні речі, такі як повернення наявного екземпляра, а не виділення нового. Отже, в Python ми не повинні вважати цю частину обов'язковою частиною розподілу; все, що нам потрібно, це те, що __new__
десь придумує відповідний екземпляр.
Але це ще лише половина роботи, і система Python не може знати, що іноді ви хочете виконувати іншу половину завдання ( __init__
), а іноді - ні. Якщо ви хочете такої поведінки, ви повинні сказати це прямо.
Часто ви можете рефакторировать так, що вам потрібно __new__
, або так вам не потрібно __new__
, або так, що __init__
поводиться по-різному на вже ініціалізованому об'єкті. Але якщо ви дійсно цього хочете, Python насправді дозволяє вам переосмислити "роботу", так що SomeClass(arg1, arg2)
не обов'язково викликати __new__
наступні __init__
. Для цього потрібно створити метаклас і визначити його __call__
метод.
Метаклас - це просто клас класу. І __call__
метод 'class' керує тим, що відбувається, коли ви викликаєте екземпляри класу. Таким чином , метод метакласу__call__
контролює те, що відбувається під час виклику класу; тобто дозволяє переглядати механізм створення екземплярів від початку до кінця . Це рівень, на якому ви зможете найелегантніше реалізувати абсолютно нестандартний процес створення екземпляра, такий як шаблон одиночної форми. Насправді, з менш ніж 10 рядків коду ви можете реалізувати Singleton
метаклассом , що тоді навіть не зажадає від вас futz з __new__
на всіх , і може перетворити будь-який інший-нормальний клас в Сінглтон, просто додаючи __metaclass__ = Singleton
!
class Singleton(type):
def __init__(self, *args, **kwargs):
super(Singleton, self).__init__(*args, **kwargs)
self.__instance = None
def __call__(self, *args, **kwargs):
if self.__instance is None:
self.__instance = super(Singleton, self).__call__(*args, **kwargs)
return self.__instance
Однак це, мабуть, глибша магія, ніж це дійсно гарантовано для цієї ситуації!