Чтобы ответить на более общий вопрос о том, как создавать ограниченные экземпляры, это зависит от ограничения. Оба приведенных выше примера являются своего рода «одиночками», хотя второй пример - это вариант, в котором вы можете иметь много экземпляров одного класса, но у вас будет только один на входное значение.
И то, и другое можно сделать, переопределив метод класса '__new__
, так что класс создает экземпляры, если он еще не создан, и оба возвращают его, и сохраняют его как атрибут на классе (как было предложено выше). Однако, чуть менее хакерский способ - использовать метаклассы. Это классы, которые изменяют поведение классов, и синглтоны являются отличным примером того, когда использовать метаклассы. И самое замечательное в этом то, что вы можете повторно использовать метаклассы. Создав метакласс Singleton, вы можете использовать этот метакласс для всех ваших синглетонов.
Хороший пример Python в Википедии: http://en.wikipedia.org/wiki/Singleton_pattern#Python
Вот вариант, который создаст другой экземпляр в зависимости от параметров:
(Это не идеально. Если вы передадите параметр, который является диктом, он, например, потерпит неудачу. Но это только начало):
# Notice how you subclass not from object, but from type. You are in other words
# creating a new type of type.
class SingletonPerValue(type):
def __init__(cls, name, bases, dict):
super(SingletonPerValue, cls).__init__(name, bases, dict)
# Here we store the created instances later.
cls.instances = {}
def __call__(cls, *args, **kw):
# We make a tuple out of all parameters. This is so we can use it as a key
# This will fail if you send in unhasheable parameters.
params = args + tuple(kw.items())
# Check in cls.instances if this combination of parameter has been used:
if params not in cls.instances:
# No, this is a new combination of parameters. Create a new instance,
# and store it in the dictionary:
cls.instances[params] = super(SingletonPerValue, cls).__call__(*args, **kw)
return cls.instances[params]
class MyClass(object):
# Say that this class should use a specific metaclass:
__metaclass__ = SingletonPerValue
def __init__(self, value):
self.value = value
print 1, MyClass(1)
print 2, MyClass(2)
print 2, MyClass(2)
print 2, MyClass(2)
print 3, MyClass(3)
Но в Python есть и другие ограничения, чем создание экземпляров. Многие из них можно сделать с помощью метаклассов. У других есть ярлыки, вот класс, который позволяет вам устанавливать атрибуты 'items' и 'fruit', например.
class Constrained(object):
__slots__ = ['items', 'fruit']
con = Constrained()
con.items = 6
con.fruit = "Banana"
con.yummy = True
Если вам нужны ограничения на атрибуты, но не такие сильные, вы можете переопределить __getattr__, __setattr__ and __delattr__
, чтобы произошло много фантастических и ужасных вещей. :-) Существуют также пакеты, которые позволяют устанавливать ограничения на атрибуты и т. Д.