Класс Python: синглтон или не синглтон путем передачи значения? - PullRequest
2 голосов
/ 08 октября 2019

У меня есть класс Python 3, который в настоящее время является синглтоном, определенным с использованием @singleton декоратора, но иногда ему нужно, чтобы не был синглтоном.

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

Я пытаюсь найти альтернативу дублированиюкласс и делает его не единичным, но тогда у нас будет множество дублированного кода.

Foo.py

def singleton(cls):
    instances={}

    def getinstance(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]

    return getinstance

@singleton
Class Foo:
    def hello(self):
        print('hello world!')

FooNotSingleton.py

Class FooNotSingleton:
    def hello(self):
        print('hello world!')

main.py

from Foo import Foo
from FooNotSingleton import FooNotSingleton

foo = Foo()
foo.hello()

bar = FooNotSingleton()
bar.hello()

Ответы [ 3 ]

1 голос
/ 08 октября 2019

Вы можете добавить некоторую дополнительную обработку в вашу оболочку singleton с помощью ключевого триггера, чтобы обойти не единственные экземпляры с singleton=False в вашем классе:

def singleton(cls):
    instances={}

    def getinstance(*args, **kwargs):
        # thanks to sanyash's suggestion, using a default return instead of try/except            
        singleton = kwargs.pop('singleton', True)
        if singleton:
            if cls not in instances:
                instances[cls] = cls(*args, **kwargs)
            return instances[cls]
        else:
            return cls(*args, **kwargs)

    return getinstance

@singleton
class Foo:
    def __init__(self, val):
        self.val = val
    def hello(self):
        print(f'I have value {self.val}')

Тест:

s1 = Foo('single')
s2 = Foo('another single')
ns = Foo('not single', singleton=False)
s1.hello()
# I have value single
s2.hello()
# I have value single
ns.hello()
# I have value not single

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

0 голосов
/ 08 октября 2019

Я считаю, что эту проблему легко решить с помощью наследования. FooNotSingleton становится базовым классом со всеми деталями реализации, а Foo выводится из него с использованием декоратора @singleton:

FooNotSingleton.py

class FooNotSingleton:
    def hello(self):
        print('hello world!')

Foo.py

import FooNotSingleton

def singleton(cls):
    instances={}

    def getinstance(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]

    return getinstance

@singleton
class Foo(FooNotSingleton.FooNotSingleton):
    pass

main.py

from Foo import Foo
from FooNotSingleton import FooNotSingleton

print(id(FooNotSingleton()))
print(id(FooNotSingleton()))  # different
print(id(Foo()))
print(id(Foo()))  # same
FooNotSingleton().hello()  # both works
Foo().hello()
0 голосов
/ 08 октября 2019

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

def singleton(cls):
    instances={}
    def getinstance(*args, **kwargs):
        key = "{}__{}".format(cls, kwargs.get("id"))
        if key not in instances:
            instances[key] = cls(*args, **kwargs)
        return instances[key]
    return getinstance

@singleton
class Foo:
    def __init__(self, *args, **kwargs):
        self.x = 0
    def hello(self):
        print('My X is:', self.x)

f1 = Foo()
f1.x = 5
f1.hello()

f2 = Foo() # same as f1
f2.hello()

f3 = Foo(id='abc') # new instance, because of new "id" parameter
f3.x = 1024
f3.hello()

f4 = Foo() # same as f1
f4.hello()

Вывод:

My X is: 5
My X is: 5
My X is: 1024
My X is: 5

Дополнительно: вы можете удалить id аргумент из kwargs перед передачей его конструктору класса - и, конечно, вы можете назвать id чем-то совершенно другим.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...