Pour répondre à la question plus générique de la création d'instances contraintes, cela dépend de la contrainte. Les deux exemples ci-dessus sont une sorte de "singletons", bien que le second exemple soit une variation où vous pouvez avoir plusieurs instances d'une classe, mais vous n'en aurez qu'une par valeur d'entrée.
Ceux-ci peuvent aussi bien fait en redéfinissant la méthode de classe __new__
, de sorte que la classe crée les instances si elle n'a pas déjà été créés, et les renvoie, et stocke comme un attribut de la classe (comme a été suggéré ci-dessus). Cependant, un moyen un peu moins hackish est d'utiliser des métaclasses. Ce sont des classes qui modifient le comportement des classes, et singletons est un excellent exemple de quand utiliser les métaclasses. Et la grande chose à ce sujet est que vous pouvez réutiliser les métaclasses. En créant une métaclasse Singleton, vous pouvez ensuite utiliser cette métaclasse pour tous les singletons que vous avez.
Un bel exemple Python dans Wikipedia: http://en.wikipedia.org/wiki/Singleton_pattern#Python
Voici une variante qui va créer une instance différente en fonction des paramètres: (Il est pas parfait Si vous passez un paramètre qui est un dict, il le fera. échouer, par exemple.Mais c'est un début):
# 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)
Mais il existe d'autres contraintes dans Python que l'instanciation. Beaucoup d'entre eux peuvent être fait avec des métaclasses. D'autres ont des raccourcis, voici une classe qui vous permet seulement de définir les attributs 'items' et 'fruit', par exemple.
class Constrained(object):
__slots__ = ['items', 'fruit']
con = Constrained()
con.items = 6
con.fruit = "Banana"
con.yummy = True
Si vous voulez des restrictions sur les attributs, mais pas tout à fait ce fort, vous pouvez remplacer __getattr__, __setattr__ and __delattr__
faire beaucoup de choses fantastiques et horribles se produisent. :-) Il y a aussi des paquetages qui vous permettent de définir des contraintes sur les attributs, etc.
En Python, deux entiers avec la même valeur ne sont pas nécessairement la même instance (voir la réponse de Roberto Liffredo ci-dessous). –