Как адаптировать шаблон Singleton?(Предупреждение об устаревании) - PullRequest
14 голосов
/ 07 июня 2011

Несколько лет назад я нашел реализацию шаблона Singleton в Python от Дункана Бута :

class Singleton(object):
    """
    Singleton class by Duncan Booth.
    Multiple object variables refers to the same object.
    http://web.archive.org/web/20090619190842/http://www.suttoncourtenay.org.uk/duncan/accu/pythonpatterns.html#singleton-and-the-borg
    """
    _instance = None

    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super(Singleton, cls).__new__(
                               cls, *args, **kwargs)
        return cls._instance

Тот же подход описан в вопросе " Есть липростой, элегантный способ определения синглетонов в Python?"

Я использую синглтон через подкласс:
class Settings(Singleton)
class Debug(Singleton)

Недавно я сделалнекоторые изменения в программе и это предупреждение:

/media/KINGSTON/Sumid/src/miscutil.py:39: DeprecationWarning: 
object.__new__() takes no parameters
cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)

Я нашел объяснение (по Гвидо) об устаревании __new__, в котором говорится, что параметры не используются вообще.Передача ненужного аргумента может быть признаком ошибки.

Поэтому я решил очистить параметры:

class Singleton(object):
_instance = None

def __new__(cls):
    if not cls._instance:
        cls._instance = super(Singleton, cls).__new__()
    return cls._instance

, что привело к следующему исключению:

Traceback (most recent call last):
 File "sumid.py", line 1168, in <module>
  settings = Settings()
 File "/media/KINGSTON/Sumid/src/miscutil.py", line 45, in __new__
  cls._instance = super(Singleton, cls).__new__()
 TypeError: object.__new__(): not enough arguments

Когда я изменю строку на cls._instance = super(Singleton, cls).__new__(cls), я получу:

Traceback (most recent call last):
  File "sumid.py", line 1174, in <module>
    debug = Debug(settings)
TypeError: __new__() takes exactly 1 argument (2 given)

Дай мне предложит другое решение : _instance = type.__new__(cls).Для меня это нарушает наследство:

Traceback (most recent call last):
  File "sumid.py", line 1168, in <module>
    settings = Settings()
  File "/media/KINGSTON/Sumid/src/miscutil.py", line 40, in __new__
    _instance = type.__new__(cls)
TypeError: type.__new__(Settings): Settings is not a subtype of type

Та же самая проблема имеет также Менно Смитса.Но я не понимаю предложенное решение .Более того, у меня нет множественного наследования в соответствующем коде.

Я не пробовал другой пример в "Есть ли простой, элегантный способ определения синглетонов в Python?", Но навозможно, проблема будет та же.

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

  • Синглтон не так.Не используйте синглтон вообще.
  • Вместо этого используйте Борг, он более питонический.
  • Использовать модуль вместо класса.

В заключение я повторю вопрос:
Как адаптировать шаблон Singleton с учетом предупреждения об устаревании с минимальное влияние на существующий код?

Редактировать: Строка cls._instance = object.__new__(cls) вызывает ошибку TypeError, когда инициализация дочернего элемента принимает аргумент:

class Child(Singleton):
    def __init__(self,param=None):
        print(param)
        print("Doing another stuff.")

ch = Child("Some stuff") 

Ответы [ 3 ]

9 голосов
/ 07 июня 2011

Вам нужно отбросить любые дополнительные аргументы, которые вы передаете при создании объекта. Измените оскорбительную строку на:

        cls._instance = object.__new__(cls)

или

        cls._instance = super(Singleton, cls).__new__(cls)

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

P.S. Я попробовал это предложение, и оно работает для меня, поэтому я не знаю, почему оно не сработало для вас.

Редактировать в ответ на комментарий @ dragonx: Как указано в комментариях, object.__new__ будет выдавать исключение, если вы передадите *args, **kwargs, поэтому супер вызов __new__ не должен включать никаких аргументы помимо cls. Это был не тот случай, когда была написана оригинальная статья. Также, конечно, если вы решите основывать свой синглтон на каком-то другом типе, таком как tuple, вам нужно будет передать соответствующие аргументы.

1 голос
/ 07 июня 2011

Итак, основываясь на ответах @Sven и @Duncan, я нашел решение, которое работает для меня. На самом деле проблема была не в строке кода, вызывающей ошибку TypeError, а в сигнатуре метода __new__(). Вызов object.__new__(cls) должен быть без * args, ** kwargs, но они должны оставаться в определении Singleton.__new__(). Это модифицированный синглтон:

class Singleton(object):
    """
    Singleton class by Duncan Booth.
    Multiple object variables refers to the same object.
    http://www.suttoncourtenay.org.uk/duncan/accu/pythonpatterns.html
    """
   _instance = None

    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super(Singleton, cls).__new__(cls)
        return cls._instance

И это пример подкласса (который был проблемой):

class Child(Singleton):  
    def __init__(self,param=None):  
            print param  
            print 'Doing another stuff'  

ch=Child('Some stuff')

Я до сих пор не понимаю, почему подпись Child'а __init__() должна совпадать с ` new () Синглтона, но это решение работает .

0 голосов
/ 21 октября 2014

Я нашел этот паттерн, описанный в паттерне Python 3 и источнике идиом. Это, безусловно, должно помочь. Я хотел бы знать, решит ли это вашу проблему, хотя это может нарушить условие минимального воздействия в вашем вопросе.

Python 3: Синглтон

...