Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Singleton

9 réponses
Avatar
jeremie fouche
Je souhaiterai implémenter un singleton. on voit pas mal de choses sur
le net, mais je galère pour trouver ce que je cherche :

Un truc sympa me paraissait :

class Singleton(object):
_instance = None

def __new__(cls):
print 'Singleton.__new__()'
if cls._instance is None:
cls._instance = object.__new__(cls)
return cls._instance

class A(Singleton) :

def __init__(self) :
print 'A.__init__()'

def a(self) :
print 'A.a'


if __name__ == '__main__':
A().a()
a = A()
b = A()

print id(a)
print id(b)


mais on voit bien que le constructeur de A est appelé à chaque appel au
singleton (pas terrible, surtout si je veux initialiser mon singleton).

J'aurai souhaité une classe qui permette de ne pas se soucier dans
l'implémentation de la classe dérivé que nous somme dans un singleton,
et donc que je ne mette pas en place des magouilles terribles du genre
une variable supplémentaire du type isInitialized

Des idées ?
Merci
--
Jérémie

9 réponses

Avatar
jeremie fouche
On 30 mar, 11:13, jeremie fouche wrote:
Je souhaiterai implémenter un singleton. on voit pas mal de choses sur
le net, mais je galère pour trouver ce que je cherche :

Un truc sympa me paraissait :

class Singleton(object):
_instance = None

def __new__(cls):
print 'Singleton.__new__()'
if cls._instance is None:
cls._instance = object.__new__(cls)
return cls._instance

class A(Singleton) :

def __init__(self) :
print 'A.__init__()'

def a(self) :
print 'A.a'


J'entrevois une solution :

A = A()

if __name__ == '__main__':
A.a()
a = A
b = A

print id(a)
print id(b)

Mais j'ai l'impression qu'en fait, cette solution n'a plus rien à voir
avec un singleton, car je n'instancie qu'une seul fois mon singleton.
Donc en gros, je n'ai pas besoin de faire une classe de base Singleton
(qui ne sert plus à rien).
Je tourne en rond !
Qu'en pensez vous ? Le premier qui me répond : "jamais le week end" a
un gage ;)
--
Jérémie

Avatar
Jean-Baptiste renard
jeremie fouche wrote:

On 30 mar, 11:13, jeremie fouche wrote:
Je souhaiterai implémenter un singleton. on voit pas mal de choses sur
le net, mais je galère pour trouver ce que je cherche :

Un truc sympa me paraissait :

class Singleton(object):
_instance = None

def __new__(cls):
print 'Singleton.__new__()'
if cls._instance is None:
cls._instance = object.__new__(cls)
return cls._instance

class A(Singleton) :

def __init__(self) :
print 'A.__init__()'

def a(self) :
print 'A.a'


J'entrevois une solution :

A = A()

if __name__ == '__main__':
A.a()
a = A
b = A

print id(a)
print id(b)

Mais j'ai l'impression qu'en fait, cette solution n'a plus rien à voir
avec un singleton, car je n'instancie qu'une seul fois mon singleton.
Donc en gros, je n'ai pas besoin de faire une classe de base Singleton
(qui ne sert plus à rien).
Je tourne en rond !
Qu'en pensez vous ? Le premier qui me répond : "jamais le week end" a
un gage ;)
--
Jérémie


un bon snippset de singleton est
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/102187

quant à ton problème, je ne l'ai pas compris

A+


Avatar
bruno.desthuilliers
On 30 mar, 11:13, jeremie fouche wrote:
Je souhaiterai implémenter un singleton.


Dans la grande majorité des cas, un module suffit.

on voit pas mal de choses sur
le net, mais je galère pour trouver ce que je cherche :

Un truc sympa me paraissait :

class Singleton(object):
_instance = None

def __new__(cls):
print 'Singleton.__new__()'
if cls._instance is None:
cls._instance = object.__new__(cls)
return cls._instance

class A(Singleton) :

def __init__(self) :
print 'A.__init__()'

def a(self) :
print 'A.a'

if __name__ == '__main__':
A().a()
a = A()
b = A()

print id(a)
print id(b)

mais on voit bien que le constructeur de A


<mode="pedant">
En Python, constructeur = __new__ + __init__

stricto sensu, __init__ tout seul est un initialiseur, pas un
constructeur.
</mode>

est appelé à chaque appel au
singleton (pas terrible, surtout si je veux initialiser mon singleton).

J'aurai souhaité une classe qui permette de ne pas se soucier dans
l'implémentation de la classe dérivé que nous somme dans un singleto n,
et donc que je ne mette pas en place des magouilles terribles du genre
une variable supplémentaire du type isInitialized

Des idées ?


Version sauvage:

class Singleton(object):
_instance = None

def __new__(cls):
print 'Singleton.__new__()'
if cls._instance is None:
cls._instance = object.__new__(cls)
else:
del cls.__init__
return cls._instance

Mais bon, a tu vraiment besoin d'autre chose que d'un module ?

Avatar
jeremie fouche
On 31 mar, 22:16, ""
wrote:
On 30 mar, 11:13, jeremie fouche wrote:

Je souhaiterai implémenter un singleton.


Dans la grande majorité des cas, un module suffit.


heuuu, je ne vois pas trop pourquoi ? Comment garantir l'unicité d'un
objet avec juste la notion de module ? Rien ne m'empeche d'instencier
plusieurs fois un objet d'un module ?

<mode="pedant">
En Python, constructeur = __new__ + __init__

stricto sensu, __init__ tout seul est un initialiseur, pas un
constructeur.
</mode>


Non, non, pas pedant du tout, je viens de comprendre un peu mieux...

Version sauvage:

class Singleton(object):
_instance = None

def __new__(cls):
print 'Singleton.__new__()'
if cls._instance is None:
cls._instance = object.__new__(cls)
else:
del cls.__init__
return cls._instance


A tester. Si je comprends bien, un peu detruire une methode (__init__
dans ce cas) d'une classe, et donc cette methode n'existe plus
ensuite... Donc plus d'appels à l'initialisateur de la classe. C'est
vraiment un language à part (je viens du C++).

Mais bon, a tu vraiment besoin d'autre chose que d'un module ?


Bah, finallement, j'en sais trop rien... Je voyais la notion de module
comme l'import de fonctionnalités, tout comme (en tres gros) un .h. Tu
aurais des references plus precises de ce qu'est un module comme tu
l'entends ?
Merci encore pour tes explications.
--
Jérémie


Avatar
Bruno Desthuilliers
On 31 mar, 22:16, ""
wrote:
On 30 mar, 11:13, jeremie fouche wrote:

Je souhaiterai implémenter un singleton.
Dans la grande majorité des cas, un module suffit.



heuuu, je ne vois pas trop pourquoi ? Comment garantir l'unicité d'un
objet avec juste la notion de module ? Rien ne m'empeche d'instencier
plusieurs fois un objet d'un module ?



Je parles d'utiliser le module lui-même en guise de singleton. A
l'exécution, un module Python est un objet. Et tu peux être
raisonnablement sûr de l'avoir en un seul examplaire !-)

<mode="pedant">
En Python, constructeur = __new__ + __init__

stricto sensu, __init__ tout seul est un initialiseur, pas un
constructeur.
</mode>


Non, non, pas pedant du tout, je viens de comprendre un peu mieux...

Version sauvage:

class Singleton(object):
_instance = None

def __new__(cls):
print 'Singleton.__new__()'
if cls._instance is None:
cls._instance = object.__new__(cls)
else:
del cls.__init__
return cls._instance


A tester. Si je comprends bien, un peu detruire


supprimer

une methode (__init__
dans ce cas) d'une classe, et donc cette methode n'existe plus
ensuite...


Oui. On peut aussi ajouter / supprimer / remplacer des méthodes (ou
d'autres attributs) dynamiquement. Voire même changer la classe d'un
objet à l'exécution (même si c'est généralement, en pratique, une assez
mauvaise idée). Ou (encore pire) changer le code (le byte-code compilé)
d'une fonction (ça par contre, ça m'a été utile au moins une fois). Le
dynamisme de Python va bien au dela du typage !-)

Accessoirement, si tu veux garder la fonction sous le coude, mais
qu'elle ne soit pas appelée après la première instanciation, c'est
toujours possible, d'une façon ou d'une autre:

class Singleton(object):
_instance = None

def __new__(cls):
print 'Singleton.__new__()'
if cls._instance is None:
cls._instance = object.__new__(cls)
else:
init = cls.__dict__.get('__init__', None)
if init:
cls._old_init = init
del cls.__init__
return cls._instance

Donc plus d'appels à l'initialisateur de la classe. C'est
vraiment un language à part (je viens du C++).

Mais bon, a tu vraiment besoin d'autre chose que d'un module ?


Bah, finallement, j'en sais trop rien... Je voyais la notion de module
comme l'import de fonctionnalités, tout comme (en tres gros) un .h.


Les imports sont très différents des includes.

Tu
aurais des references plus precises de ce qu'est un module comme tu
l'entends ?


Techniquement, un module est un objet (instance de la classe 'module').
Cet objet est généralement instancié par le mécanisme d'import, et ses
attributs seront alors tous les symboles définis au top-level du fichier
source (sachant que tout le code défini au top-level d'un fichier source
est executé lors de l'import). Egalement, le mécanisme d'import assure
que l'objet module ne sera (sauf circonstances très exceptionnelles
tenant plus du vilain hack que d'autre chose) instancié qu'une fois,
quelque soit le nombre d'imports, pour un process donné. Les variables
dites "globales" du module (qui ne sont "globales" qu'au module - il n'y
a pas de véritable espace de nommage global en Python) constituent donc
l'état de ton objet, et ses fonctions les méthodes.

Dans la pratique, dans la majeure partie des cas d'utilisation d'un
singleton en C++ ou Java, un module Python fait aussi bien l'affaire.
Reste probablement quelques cas qui nécessitent effectivement une
approche plus "traditionnelle", mais je ne les ait personnellement pas
encore recontrés (et j'utilise Python depuis pas mal d'années maintenant).

Merci encore pour tes explications.


Pas de quoi.



Avatar
olive
Salut,

Quand utilise-t'on(tu) un module comme singleton plutôt que le module
ConfigParser (par exemple) ?

... ou vice-versa.
Avatar
jeremie fouche
On 1 avr, 20:49, Bruno Desthuilliers <bruno.
wrote:

On 31 mar, 22:16, ""
wrote:
On 30 mar, 11:13, jeremie fouche wrote:

Je souhaiterai implémenter un singleton.


Dans la grande majorité des cas, un module suffit.



Techniquement, un module est un objet (instance de la classe 'module').
Cet objet est généralement instancié par le mécanisme d'import, et ses
attributs seront alors tous les symboles définis au top-level du fichier
source (sachant que tout le code défini au top-level d'un fichier source
est executé lors de l'import). Egalement, le mécanisme d'import assure
que l'objet module ne sera (sauf circonstances très exceptionnelles
tenant plus du vilain hack que d'autre chose) instancié qu'une fois,
quelque soit le nombre d'imports, pour un process donné. Les variables
dites "globales" du module (qui ne sont "globales" qu'au module - il n'y
a pas de véritable espace de nommage global en Python) constituent donc
l'état de ton objet, et ses fonctions les méthodes.


Bah voila, je prends ça, c'est encore mieux que ce que j'avais
imaginé. En fait, mon erreur venait du fait qu'en C++, il faut essayer
de bannir les variables globales. Mais avec ton explication, je
cronprends que je crée ma variable global dans un module, et qu'elle
est donc un singleton au sein de mon application, même si plusieurs
modules l'importent :

module1.py

class _A :
def do(self) :
print "A.do"

A = _A()

module2.py

import module1.A as A

A.do()


module3.py

import module1.A as A

A.do()


Et hop...
Formidable
Merci encore
--
Jérémie




Avatar
bruno.desthuilliers
On 2 avr, 19:15, jeremie fouche wrote:
On 1 avr, 20:49, Bruno Desthuilliers <bruno.



wrote:

On 31 mar, 22:16, ""
wrote:
On 30 mar, 11:13, jeremie fouche wrote:

Je souhaiterai implémenter un singleton.
Dans la grande majorité des cas, un module suffit.

Techniquement, un module est un objet (instance de la classe 'module').


Cet objet est généralement instancié par le mécanisme d'import, et ses
attributs seront alors tous les symboles définis au top-level du fichi er
source (sachant que tout le code défini au top-level d'un fichier sour ce
est executé lors de l'import). Egalement, le mécanisme d'import assu re
que l'objet module ne sera (sauf circonstances très exceptionnelles
tenant plus du vilain hack que d'autre chose) instancié qu'une fois,
quelque soit le nombre d'imports, pour un process donné. Les variables
dites "globales" du module (qui ne sont "globales" qu'au module - il n'y
a pas de véritable espace de nommage global en Python) constituent don c
l'état de ton objet, et ses fonctions les méthodes.


Bah voila, je prends ça, c'est encore mieux que ce que j'avais
imaginé. En fait, mon erreur venait du fait qu'en C++, il faut essayer
de bannir les variables globales.


Les vrais problèmes sont (AMHA):
1/ les dépendances sur des variables non explicitement importées
(impossible en Python), qui rendent le code non modulaire
2/ les fonctions qui modifient des variables non locales, rendant le
code plus difficile à comprendre / maintenir / faire évoluer.

La combinaison des deux, quand elle possible, étant une pure horreur,
en effet.

D'un autre côté, en Python, tous les noms que tu définis au top-level
d'un module (via un import, un def, un class ou une assignation) sont
techniquement des variables globales (au module), donc tu ne peux tout
simplement pas les bannir. Le tout est de savoir en user avec
discernement.

Mais avec ton explication, je
cronprends que je crée ma variable global dans un module, et qu'elle
est donc un singleton au sein de mon application,


Disons que le résultat pratique est le même.

même si plusieurs
modules l'importent :

module1.py

class _A :


<HS>
A moins que tu n'ai besoin d'assurer la compatibilité avec de vieilles
versions de Python, utilise de préférence les classes 'new-style' (cf
http://www.python.org/doc/newstyle/) :

class _A(object):
</HS>

(snip code)

Formidable


Simple, surtout !-)

D'une manière générale, en Python, il n'est pas nécessaire d'aller
chercher midi à quatorze heures - même s'il y a dans le langages
certains points assez complexes.

Au cas où, et dans le même ordre d'idée, ne t'emm... surtout pas à
écrire des accesseurs pour tes attributs - Python a un très bon
support pour les attributs calculés, totalement transparent pour le
code client.

Merci encore


De rien. Bienvenue au club.





Avatar
bruno.desthuilliers
On 2 avr, 17:29, olive wrote:
Salut,

Quand utilise-t'on(tu) un module comme singleton plutôt que le module
ConfigParser (par exemple) ?

... ou vice-versa.


désolé, je ne suis pas sûr de bien comprendre la question...