Рубрики
Без рубрики

Как создать синглтон в Python?

Магистерские кодеры ведут себя как архитекторы, которые подключаются и создают различные шаблоны дизайна для создания функционального целого. Одним из самых важных конструктивных узоров является Singleton — класс, который имеет только один экземпляр. Вы можете спросить: как это выглядит? Давайте посмотрим на код, реализующий синглтон в нашем интерактивном … Как создать синглтон в Python? Прочитайте больше “

Автор оригинала: Michael Petersen.

Мастер-кодеры ведут себя как архитекторы, которые соединяются и строят на разных Дизайн шаблонов создать функциональное целое. Один из самых важных шаблонов дизайна – это Singleton – класс, который имеет только один экземпляр. Вы можете спросить: Как это выглядит? Давайте посмотрим на код, реализующий синглтон в нашем интерактивном коде, оболочке:

Упражнение : Попробуйте создать несколько экземпляров класса Singleton. Ты можешь сделать это?

Давайте погрузимся в более глубокое понимание синглтона. Мы обсудим этот код в нашем первом методе, поэтому продолжайте читать!

Что такое синглтон?

Singleton – это класс, который имеет только один экземпляр. Все переменные для класса указывают на тот же экземпляр. Это просто и просто создать и использовать, и это один из шаблонов дизайна, описанных Банда из четырех Отказ После создания первого экземпляра все остальные создания создаются на первом создании экземпляра. Это также решает проблему глобального доступа к ресурсу без использования глобальных переменных. Мне нравится это краткое определение от Голова Первый дизайн шаблонов :

Шаблон Singleton гарантирует, что у класса имеет только один экземпляр, и обеспечивает глобальную точку доступа к нему.

Почему вам нужен синглтон?

Если вы читаете это, вы, вероятно, уже имеете возможное использование. Singleton – одна из банды из четырех лет Творческий шаблоны. Читайте дальше, чтобы определить, является ли его хороший кандидат на проблему, вам нужно решить.

Singleton можно использовать для доступа к общему ресурсу, такому как базу данных или Файл Отказ На его использовании есть немного противоречия. На самом деле, противоречие могут быть описаны как откровенные синглтон, божемые. Если это касается вас, я перечислял некоторые из объектов ниже с некоторыми ссылками. Несмотря на то, что Singletons могут быть полезны и питон. От Дзен Питона (Pythonistas говорят ом):

  • Просто лучше сложного
  • Практичность побеждает чистоту

Тем не менее, возражения имеют заслуги и могут обратиться к коду, над которой вы работаете. И даже если они не применяются, понимание тех возражений может дать вам лучшее понимание объектных принципов и тестирование единиц.

Singleton может быть полезен для контроля доступа к чему-либо, что изменяется во всем мире, когда он используется. В дополнение к базам данных и файлам Singleton может обеспечить выгоду для доступа к этим ресурсам:

  • Регистратор
  • Нить пулы
  • кэширует
  • Диалоговые окна
  • HTTP-клиент
  • обрабатывает на настройки предпочтения
  • Объекты для ведения журнала
  • Ручки для драйверов устройств, таких как принтеры.
  • (?) Любой единый ресурс или глобальный сбор

Singleton можно использовать вместо использования глобальной переменной. Глобальные переменные потенциально грязны. У Singletons имеют некоторые преимущества по глобальным переменным. Синглтон может быть создан с нетерпением или ленивым творением. Стремление может создать ресурс, когда запускается программа. Ленивое творение создаст экземпляр только тогда, когда он сначала нужен. Глобальные переменные будут использовать нетерпеливое создание, нравится вам это или нет. Singletons не загрязняют глобальное пространство имен.

И, наконец, синглтон может быть частью более крупного рисунка дизайна. Это может быть частью любого из следующих шаблонов:

  • Абстрактный заводской шаблон
  • Строитель шаблон
  • узор прототипа
  • фасадный рисунок
  • Узор состояний объектов, если вы не слышали об этом, никаких забот. Это не повлияет на ваше понимание рисунка Singleton.

Реализация

Стандартные реализации C # и Java полагаются на создание класса с частным конструктором. Доступ к объекту предоставляется через метод: GetInstance ()

Вот типичный ленивый синглтон внедрение в Java:
public Singleton {
    private static Singleton theOnlyInstance;
    private Singleton() {}                   
    public static Singleton getInstance() {  
        if (theOnlyInstance) == null){
            theOnlyInstance = new Singleton()
        }
            return new Singleton();
    }
}

Есть много способов реализации Singleton в Python Отказ Я покажу все четыре первыми и обсудим их ниже.

Метод 1: использовать __new__

class Singleton:
    _instance = None

    def __new__(cls):
        if cls._instance is None:
            cls._instance = super(Singleton, cls).__new__(cls)
            # Initialize here. No need to use __init__()..
            cls.val = 0
        return cls._instance
    
    def business_method(self, val):
        self.val = val

x = Singleton()
y = Singleton()
x.val = 42
x is y, y.val

Используется Python Dumper __new__ Это было добавлено к Python, чтобы обеспечить альтернативное метод создания объекта. Это тот тип использования Case __new__ был разработан для

Плюсы :

  • Я считаю, что эта реализация самая близкая по душе в реализации GOF. Он будет выглядеть знакомым для кого-либо, знакомых со стандартным исполнением Singleton.
    • Легко понять, что значение кода важно для команд и обслуживания.
  • Использует один класс для создания и реализации Singleton.

Минусы :

  • Несмотря на его «правильность», многие кодеры Python должны будут посмотреть __new__ Чтобы понять специфику создания объекта. Достаточно знать, что

    1. __new__ создает объект.
    2. Код, который обычно идет __init__ можно разместить в __new__ Отказ
    3. Для того, чтобы правильно работать переопределенным __new__ должен позвонить своим родителям __new__ метод. В этом случае объект является родительским. Информация происходит здесь с этой строкой:

      • Объект .__ Новое __ (Class_, * args, ** kwargs)

Способ 2: декоратор

def singleton(Cls):
    singletons = {}
    def getinstance(*args, **kwargs):
        if Cls not in singletons:
            singletons[Cls] = Cls(*args, **kwargs)
        return singletons[Cls]
    
    return getinstance

@singleton
class MyClass:
    def __init__(self):
        self.val = 3

x = MyClass()
y = MyClass()
x.val = 42
x is y, y.val, type(MyClass)

Плюс

  • Код для записи декоратора отдельно от создания класса.
  • Это можно повторно использовать как можно больше синглтонов, сколько вам нужно.
  • Синглтон декоратор отмечает намерение, которое ясно и понятно

Господин

  • Звонок Тип (MyClass) будет разрешаться как Функция Отказ

    • Создание метода класса в MyClass приведет к ошибке синтаксиса.

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

pip install singleton_decorator

Библиотека Singleton_Decorator обертывания и переисканы класс Singleton. Поочередно вы можете написать свой собственный. Вот реализация:

def singleton(Cls):
    class Decorated(Cls):
        
        def __init__(self, *args, **kwargs):
            if hasattr(Cls, '__init__'):
                Cls.__init__(self, *args, **kwargs)
                
        def __repr__(self) : 
            return Cls.__name__ + " obj"
        
        __str__ = __repr__
        
    Decorated.__name__ = Cls.__name__
    
    class ClassObject:
        
        def __init__(cls):
            cls.instance = None
            
        def __repr__(cls):
            return Cls.__name__
        
        __str__ = __repr__
        
        def __call__(cls, *args, **kwargs):
            if not cls.instance:
                cls.instance = Decorated(*args, **kwargs)
            return cls.instance
    return ClassObject()

@singleton
class MyClass():
    pass

x = MyClass()
y = MyClass()
x.val = 42
x is y, y.val

Вывод:

(True, 42)

Интерактивное упражнение : Запустите следующую интерактивную визуализацию памяти. Сколько экземпляров Singleton вы найдете?

Способ 3: Используйте метакласс и наследующуюся от типа и переопределения __Call__ для создания экземпляра фильтра или фильтра

class Singleton(type):
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]

class MyClass(metaclass=Singleton):
    pass

x = MyClass()
y = MyClass()
x.val=4
x is y, y.val

Вывод выглядит следующим образом:

(True, 4)

Метод 3 создает новый Пользовательские метакласс наследующуюся от типа. MyClass затем назначает Singleton в качестве метаданных:

учебный класс):

Механика класса Singleton интересна. Он создает словарь для удержания экземпляров синглтона объектов. Ключи Dict – это названия классов. В переопределении __call__ Метод, Super .__ call__ вызывается для создания экземпляра класса. Посмотреть Пользовательские метакласс Чтобы лучше понять __call__ метод.

Плюс

  • Singleton код отделен. Несколько синглтонов могут быть созданы с помощью того же

Господин

  • Метаклассы остаются таинственными для многих кодеров Python. Это то что тебе нужно знать:
    • В этой реализации тип унаследован:
      • Класс Singleton (тип)
    • Для того, чтобы правильно работать переопределенным __call__ должен позвонить своим родителям __call__ метод.

      • CLS._Instances [CLS] (Singleton, CLS) .__ Call __ (* args, ** kwargs)

Метод 4: Используйте базовый класс

class Singleton:
    _instance = None
    def __new__(class_, *args, **kwargs):
        if not isinstance(class_._instance, class_):
            class_._instance = object.__new__(class_, *args, **kwargs)
        return class_._instance

class MyClass(Singleton):
    pass
x = MyClass()
y = MyClass()
x.val=4
x is y, y.val

Вывод выглядит следующим образом:

(True, 4)

Плюс

  • Код может быть повторно использован для создания большего количества синглтонов
  • Использует знакомые инструменты. (По сравнению с декораторами, метаклассами и методом __new__

Во всех четырех методах экземпляр создан первый раз, когда его задают. Все звонки после первого возврата первого экземпляра.

Синглтоны в резьбовой среде

Если ваш Singleton должен работать в многопоточной среде, то ваш метод Singleton должен быть сделан в потоке. Ни один из способов выше не является безопасным. Уязвимый код находится между проверкой существующего синглтона и созданием первого примера:

if cls._instance is None:
    cls._instance = super(Singleton, cls).__new__(cls)

Каждая реализация имеет аналогичный кусок кода. Чтобы сделать его потоком, этот код должен быть синхронизирован.

with threading.Lock():
    if cls._instance is None:
        cls._instance = super(Singleton, cls).__new__(cls)

Это работает нормально и с замком на месте, создание синглтона становится безопасной резьбой. Теперь каждый раз, когда поток запускает код, Threading.lock () называется, прежде чем он проверяет существующий экземпляр.

Если производительность не проблема, это здорово, но мы можем сделать лучше. Механизм блокировки дороги, и он должен работать только в первый раз. Создание экземпляра происходит только один раз, чтобы замок должен произойти максимум одновременно. Решение состоит в том, чтобы разместить замок после проверки проверки. Затем добавьте еще одну проверку после блокировки.

import threading
...
    if cls._instance is None:
        with threading.Lock():
            if cls._instance is None: 
                cls._instance = super(Singleton, cls).__new__(cls)

И вот как использовать « Дважды проверенные блокировки ».

Безопасная резьба версия метода 1

Рассмотрим следующую модификацию метода 1:

import threading
class Singleton:
    _instance = None

    def __new__(cls):
        if cls._instance is None:
            with threading.Lock():
                if cls._instance is None:
                    cls._instance = super(Singleton, cls).__new__(cls)
                    # Initialize here. No need to use __init__()..
                    cls.val = 0
        return cls._instance
    
    def business_method(self, val):
        self.val = val

x = Singleton()
y = Singleton()
x.val = 42
x is y, y.val

Вывод:

(True, 42)

Чтобы сделать его потоком, мы добавили две строки кода. Каждый метод может быть сделан резьбой аналогичным образом

Альтернативы использования Singleton

Используйте модуль как синглтон (глобальный шаблон объекта)

В Python модули являются одинокими, уникальными и глобально доступными. Глобальный шаблон объекта рекомендуется документами Python. Он просто означает создание отдельного модуля и создать свой объект в глобальном пространстве модуля. Последующие ссылки просто нужно импортировать его.

Используйте инъекцию зависимости

Как правило, это означает использование композиции для обеспечения объектов для зависимых объектов. Он может быть реализован бесчисленным способами, но в целом, поставить зависимости в конструкторов и избежать создания новых экземпляров объектов в бизнес-методах.

Проблемы с Singletons

Из всех 23 узоров в книге семенной 1994 года Дизайн шаблонов Singleton является наиболее употребленным, самым обсуждаемым и самым популярным. Это немного кролика, чтобы просеять через тысячи блогов и посты на переполнении стека, которые говорят об этом. Но ведь синглтон ненавидит, шаблон остается распространенным. Это почему? Это потому, что условия, которые предлагают его использование, очень распространены: одна база данных, один файл конфигурации, один пул резьбы …

Аргументы против его использования лучше всего утверждаются в некоторых элегантных (и старых) сообщениях блога, которые я не могу соответствовать. Но я дам резюме и ссылки для дальнейшего чтения.

Краткое резюме

Перефразированные от Brian кнопки в Почему синглтоны злые :

  1. Они обычно используются как глобальный экземпляр, почему так плохо? Поскольку вы скрываете зависимости вашего приложения в вашем коде вместо того, чтобы выдержать их через интерфейсы. Делать что-то глобальное, чтобы не пройти его вокруг, это код кода. (Это некоторое эффективное призывовное название. Какой бы код кода не так, это заставляет меня съедать немного и морщить нос, как я себе представляю).
  2. Они нарушают единственный принцип ответственности: в силу того, что они контролируют свое собственное творение и жизненный цикл.
  3. Они по своей сути причины тесно связаны с кодом. Это делает их подходящим в тесте довольно сложно во многих случаях.
  4. Они несут состояние вокруг на всю жизнь приложения. Еще один удар для тестирования, поскольку вы можете в конечном итоге с ситуацией, когда необходимо заказать тесты, что является большим нет для модульных тестов. Почему? Поскольку каждый тест на единицу должен быть независимым от другого.

Если вы используете Singletons в вашем коде?

Если вы спрашиваете себя, основываясь на блогах других народов, вы уже находитесь в кроличке. Слово «должно» не приветствуется в дизайне кода. Используйте Singletons или нет и не знайте возможных проблем. Refastor, когда есть проблемы.

Возможные проблемы, чтобы рассмотреть

Инструменты для людей, которые знают, как их использовать. Несмотря на все плохие вещи, написанные о Singletons, люди все еще используют их, потому что:

  1. Они наполняют необходимость лучше, чем альтернативы.

и/или

  1. Они не знают лучше, и они создают проблемы в своем коде, используя их.

Избегайте проблем. Не будь в группе 2.

Проблемы с Singletons вызваны, потому что они нарушают правило на одну ответственность. Они делают три вещи:

  1. Гарантия только один экземпляр существует
  2. Предоставить глобальный доступ к этому экземпляру
  3. Предоставить свою собственную бизнес-логику.
  • Потому что они нарушают правило на одну ответственность, синглтоны могут быть трудно проверить
    • Инверсия контроля МОК и Инъекция зависимости Являются ли модели, предназначенные для преодоления этой проблемы в ориентированной объектно-ориентированной форме, которая помогает сделать тестичный код.
  • Singletons могут привести к крепко Советный код Отказ Глобальный экземпляр, который имеет непостоянное состояние, может потребовать от объекта, чтобы зависеть от состояния глобального объекта.
  • Это директор OO для Отдельная творческая логика из бизнес-логики Отказ Придерживаясь этого принципа «Singletons Должны никогда не будешь использовать». Снова со словом следует. Вместо этого, будь Йода: « сделать или нет! ». Основание решения по вашему собственному коду.
  • Память, выделенная синглтоном, не может быть освобождена. Это только проблема, которую необходимо освободить память.

Дальнейшее изучение

Мета-ноты – Мишко Хревери.

Хевери работал в Google, когда он написал эти блоги. Его блоги были читаемыми, развлекательными, информативными, провокационными и вообще завышенными, чтобы сделать точку зрения. Если вы читаете его блоги, обязательно прочитайте комментарии. Singletons являются патологическими лжецами Имеет пример тестирования подразделения, который иллюстрирует, как Singletons могут затруднить выяснение цепей зависимости и запуск или тестирование приложения. Это довольно крайний пример злоупотребления, но он делает действительный смысл:

Singletons – не что иное, как глобальное государство. Глобальное состояние делает его, чтобы ваши объекты могли тайно получить вещи, которые не объявлены в их API, а в результате Singletons делают ваши API в патологические лжецы.

Конечно, он немного преувеличивает. Singletons обертывают глобальное состояние в классе и используются для вещей, которые являются «естественными» глобальными по природе. Как правило, hevery рекомендует инъекцию зависимостей для замены синглтонов. Это просто означает объекты, передают свои зависимости в их конструкторе.

Где у всех синглтонов ушли Делает то, что инъекция зависимостей позволила легко получить экземпляры для конструкторов, которые требуют их, что облегчает лечебную потребность позади плохих, глобальных синглтонов в патологических лжецах.

Meta Notes – Брэндон Родос Синглтон Узор

Python Programmers почти никогда не реализуют шаблон Singleton, как описано в банде из четырех книг, чья Singleton Class запрещает нормальное зрелище и вместо этого предлагает метод класса, который возвращает экземпляр Singleton. Python более элегантный, и позволяет классу продолжать поддерживать нормальный синтаксис для создания института при определении пользовательских __new __ () Метод, который возвращает экземпляр Singleton. Но еще более Pythonic подход, если ваш дизайн заставляет вас предлагать глобальный доступ к объекту Singleton, вместо этого используется глобальный шаблон объекта.

Meta Notes – J.B. Rainsberger Удивительно используют свои синглеты

Знать, когда использовать синглтоны, и когда оставить их позади

J.B. Rainsberger

Опубликовано 01 июля 2001 года 2001 г. Автоматизированное тестирование подразделения наиболее эффективно, когда:

  • Связь между классами только так же сильна, как это должно быть
  • Просто использовать MOCK Реализации сотрудничающих классов вместо реализации производства
Singletons знают слишком много

Существует одна реализация анти-образца, которая процветает в приложении с слишком многими синглетами: я знаю, где вы живете анти-образцом. Это происходит, когда, среди сотрудников классов совместных сотрудников, один класс знает, где получить экземпляры другого.

К приемлемым синглторам

Можно избежать злоупотребления синглтоном, глядя на проблему с другого угла. Предположим, что приложение необходимо только один экземпляр класса, а приложение настраивает этот класс при запуске: почему сам класс не отвечает за то, что он является синглтоном? Это кажется довольно логичным для приложения, чтобы принять эту ответственность, поскольку приложение требует такого поведения. Применение, а не компонент, должен быть синглтоном. Затем приложение делает экземпляр компонента, доступный для любого кода, специфичного приложения для использования. Когда приложение использует несколько таких компонентов, он может согревать их в то, что мы назвали инструментов.

Meta Notes – Mark Safayan Singleton Anti Pattern

Вместо того, чтобы использовать этот шаблон, просто создайте единый экземпляр и распространяйте его на места, которые используют объект в качестве параметра, чтобы сделать зависимость явной.