Bonjour à tous,
Sauriez vous quelle commande permet de donner la liste des instances d'une classe.
Exemple :
MerciCode:
1
2
3
4
5
6
7
8
9 class Toto: def __init__(self,num): self.num=num t1=Toto("un") t2=Toto("Deux") print Toto.? ["t1","t2"]
Alex
Version imprimable
Bonjour à tous,
Sauriez vous quelle commande permet de donner la liste des instances d'une classe.
Exemple :
MerciCode:
1
2
3
4
5
6
7
8
9 class Toto: def __init__(self,num): self.num=num t1=Toto("un") t2=Toto("Deux") print Toto.? ["t1","t2"]
Alex
Hello Alex,
Ça ne se fait pas tout seul malheureusement. Mais avec un petit peu de brol, tu peux vite arriver à un résultat convainquant :)
Solution simple: mettre un décorateur sur l'__init__ de ta classe, qui va capturer les nouvelles instances.
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 >>> import functools >>> class Gatherer(object): ... def __init__(self): ... self.objects = [] ... ... def __call__(self, func): ... @functools.wraps(func) ... def newInit(itself, *args, **kwargs): ... func(itself, *args, **kwargs) ... self.objects.append(itself) # Ou une weakref ... ... return newInit ... >>> g = Gatherer() >>> class MyClass(object): ... @g ... def __init__(self): pass ... >>> MyClass() <__main__.MyClass object at 0x1004d2dd0> >>> MyClass() <__main__.MyClass object at 0x1004d2e90> >>> g.objects [<__main__.MyClass object at 0x1004d2dd0>, <__main__.MyClass object at 0x1004d2e90>]
Salut,
A ma connaissance, il n'y a pas de liste d'instances d'une classe: il faut la construire à la mimine lors de la création des instances.
Un peu plus light que la solution précédente.
On met les instances crées dans une liste de classe.
Genre:
Ca à l'avantage d'être simple.... Même si je n'aime pas du tout.Code:
1
2
3
4
5
6
7
8
9
10 class Toto(object): instances = [] def __init__(self,num): self.num=num self.instances.append(self) def __del__(self): '''c'est bien d'empiler mais...''' self.instances.remove(self)
- W
Hello
C'est vrai que c'est une bonne idée de retirer les objets quand ils sont désalloués... Je rajouterai ça à ma todo list :P
Ceci dit, il me semble que les objets ne seront jamais désalloués dans ce cas-ci, puisqu'il restera tjs au moins une référence pour chaque objet: celle qui se trouve dans la liste.
Le problème peut se régler en utilisant des weak refs.
Bonsoir,
Sauf que l'item reste dans la liste en cas de del de la référence.
C'est normal mais bon...Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 class Toto(object): instances = [] def __init__(self,num): self.num=num self.instances.append(self) def __del__(self): self.instances.remove(self) def getinstances(self): return self.instances a = Toto(1) Toto(2) c = Toto(3) print(c.getinstances()) del c d = Toto(4) print(d.getinstances()) for i in d.getinstances(): del i e = Toto(5) print(e.getinstances()) print(Toto.instances)
@+
Bon, je vais utiliser la solution de wiztricks,
Je n'aurais pas pensé non plus à l'effacement de l'instance...
Merci,
Alex
Ouais, mais comme l'a dit PauseKawa la référence contenu dans la liste n'est pas supprimée, ce qui empêche l'appel de la méthode __del__ de l'objet.
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 # -*- coding: cp1252 -*- class Toto(object): instances = [] def __init__(self,num): self.num=num self.instances.append(self) def __del__(self): '''c'est bien d'empiler mais...''' self.instances.remove(self) "Print - Objet : Toto-%d Détruit" % (self.num) a = Toto(1) b = Toto(2) del a del b print (Toto.instances)
Citation:
>>>
[<__main__.Toto object at 0x00F2A490>, <__main__.Toto object at 0x00F2A2F0>]
>>>
weakref ?
Avec le module <gc>, il est possible de retrouver tous les objects faisant référence à un objet donné.
Dans le cas de la classe Toto.Code:gc.get_referrers(Toto)
Le léger soucis, c'est d'ensuite mettre au point une fonction récursive qui retourne tous les instances de <Toto> contenu dans cette Liste.
Salut,
Je vous avais écrit que la chose ne me plaisait pas. :mrgreen:
Les weakrefs bien sûr mais çà rend la chose _compliquée_.
Si on veut rester simple ajouter une méthode delete en lieu et place de __del__ évite d'attendre indéfiniment l'arrivée du GC.
Tout dépend de la confiance faite au client (le code qui utilisera la classe Toto) pour penser à...
La chose ne me plaît pas plus... Mais restons simple.Code:
1
2
3
4
5
6
7
8 class Toto(object): instances = [] def __init__(self,num): self.num=num self.instances.append(self) def delete(self): self.instances.remove(self)
- W
Bonjour,
Une solution : Utiliser une classe singleton pour stocker/destocker on demand les instances les classes qui le demande dans un objet (dico[classe]: (instance, instance)).
Pour avoir la liste des instances d'une classe il suffit alors de demander au singleton.
Pas jolie hein...
@+
Le singleton c'est mal... Surtout quand on fait du multithreading.
Oui... Surtout que cela n'arrange en rien l'histoire du __del__, du moins sans trop 'magouiller'.
Donc restons simple que le dit wiztricks.
Bon pas simple ce truc,
Il semble plus compliqué d'adresser un seul objet que l'ensemble des objets de classes sans les connaître à priori.
Quand j'ai un problème comme ceci en général je revois mon réel besoin...
Je ne comprend pas deux points :
"instance" est un attribut de classe, alors pourquoi doit on s'y référer avec self.instances.append(self) puisque que ""self" est un attribut d'instance ?Code:
1
2 class Toto(object): instances = []
Que change le fait d'avoir une méthode delete au lieu de __del__ ?
Merci de votre aide
Alex
Bonjour,
Vous pouvez utilisez Toto.instances si cela vous semble plus 'logique'/'propre'.
Vous avez aussi accès aux attributs de classe via l'instance
Et c'est ce qui est fait ici.Code:
1
2
3
4
5
6
7
8 >>> class Toto(object): ... instances = [] ... def verifitem(self): ... return hasattr(self, 'instances') ... >>> c = Toto() >>> c.verifitem() True
Pour ce qui est de del (et __del__) c'est une histoire de compteur et garbage collector qui prend son temps.Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14 >>> class Toto(object): ... instances = [] ... def __init__(self): ... self.instances.append(self) ... def getitem(self): ... return self.instances ... >>> t1 = Toto() >>> t2 = Toto() >>> t3 = Toto() >>> t3.getitem() [<__main__.Toto object at 0x022FCC30>, <__main__.Toto object at 0x022FCB70>, <__ main__.Toto object at 0x022FCD30>] >>>
Utiliser une méthode delete permet d'avoir une liste 'viable' des instances.
@+
Salut,
Je ne connais pas d'applications qui ne doivent pas avoir des variables globales ici ou là. Une variable "globale", c'est d'abord la possibilité de la désigner via un nom de chemin. module.Toto.instances est une variable "globale".
Et comme en Python les modules sont techniquement des "Singleton"s... il faudra quand même traiter la sérialisation des accès aux variables globales.
Deux choses au moins que MonoState / Borg fait mieux que Singleton (en MT) sont:
- nous avons l'assurance d'avoir un état global unique sans avoir à faire un double verrouillage à la création de l'instance "single" du ton,
- on peut sous-classer un monostate. Un Singleton c'est plus tordu.
Une chose que Singleton fait mieux que MonoState, c'est "attention danger!" pourvu qu'on s'applique à rester orthodoxe, i.e. l'interface d'accès reste la méthode de classe singleton.getInstance (pas facile d'obliger à en Python).
Monostate nous retourne une instance avec des variables partagées sans forcément nous alerter sur la chose.
Note: C'est un des aspects que je n'aime pas dans ce code.
- W
Bonsoir,
De toute manière l'idée n'est pas bonne (elle est de moi ? Ah ok...).
Le problème est dans la suppression des références ET des 'instances' dans la liste, pas dans le stockage.
@+
Salut,
Pourquoi weakref c'est "compliqué".... parce que je ne sais pas faire plus simple que ci dessous.
:cry:Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 import weakref class Toto(object): instances = [] def __init__(self, number): self.number = number self.instances.append(weakref.proxy(self, Toto._delete)) @classmethod def _delete(cls, ref): assert ref in cls.instances cls.instances.remove(ref) def __del__(self): print ('__del__(%s)' % self) def __str__(self): return 'Toto: number = %(number)d' % vars(self) t1 = Toto(1) print 't1:', t1 print 'instances', Toto.instances del t1 print 'instances', Toto.instances
- W
Pour ma part j'ai d'un coté:
Et de l'autre...Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 #coding:latin-1 #Méthode 2, avec n'importe quelle classe! import gc def getInstances(classRef): if classRef in (int, str, float, unicode) or isinstance(classRef,(int,str,float,unicode)): raise TypeError("classRef must be a class, not of type %s " % (classRef)) lst = gc.get_referrers(classRef) res = list() findAllInstances(classRef, lst, res) return res def findAllInstances(classRef, db , lst): if classRef in (int, str, float, unicode): raise TypeError("classRef must be a class, not of type <%s> " % (classRef)) if isinstance(db, (list, tuple, set)): for obj in db: findAllInstances(classRef, obj, lst) elif isinstance(db, dict): for obj in db.values(): findAllInstances(classRef, obj, lst) elif isinstance(db, classRef) and not (db in lst): lst.append(db) class Toto(): def __init__(self): pass a = Toto() b = Toto() db = dict(me=Toto(),you=Toto(),this=Toto(),moi=Toto()) lst = list(db.values()) print ("Instances - 1") print (getInstances(Toto)) del (lst, db) gc.collect() print ("\nInstances - 2") print (getInstances(Toto))
Le proxy pour les weakref, faudrait m'expliquer, j'ai rien compris.Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 #coding:latin-1 #Méthode 1, avec une classe construite par soi-même import weakref class Toto: __refs = [] __id = [0] def __init__(self): self.__refs.append(weakref.ref(self)) self.id = self.__id[0] self.__id[0] +=1 def __del__(self): print "Deleted object <%d>" % (self.id) def getInstances(self): res = [] for ref in self.__refs: obj = ref() if (obj==None): self.__refs.remove(ref) else: res.append(obj) return res a = Toto() b = Toto() db = dict(me=Toto(),you=Toto(),this=Toto(),moi=Toto()) lst = list(db.values()) print (a.getInstances()) del (lst, db) print (a.getInstances())
Bonjour,
Dans l'esprit 'faire simple' weakref.ref n'est il pas suffisant ?
OutputCode:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 #!/usr/bin/env python # -*- coding: ISO8859-1 -*- # # import weakref from sys import version if version.startswith('3'): raw_input = input class Toto(object): instances = [] def __init__(self): self.ref = weakref.ref(self) self.instances.append(self.ref) def __del__(self): self.instances.remove(self.ref) print ('__del__(%s)' % self) def __str__(self): return repr(self) t1 = Toto() print('t1:', t1) print('instances', Toto.instances) t2 = Toto() t3 = Toto() t4 = Toto() t5 = Toto() print('instances', Toto.instances) del t1 print('instances', Toto.instances) del t2 del t3 del t4 print('instances', Toto.instances) raw_input("Fin de code: Appuillez sur une touche pour finir.") print("Grand ménage")
@+Code:
1
2
3
4
5
6
7
8
9
10
11
12 ('t1:', <__main__.Toto object at 0xb780da6c>) ('instances', [<weakref at 0xb78100cc; to 'Toto' at 0xb780da6c>]) ('instances', [<weakref at 0xb78100cc; to 'Toto' at 0xb780da6c>, <weakref at 0xb78100f4; to 'Toto' at 0xb780daec>, <weakref at 0xb781011c; to 'Toto' at 0xb780db0c>, <weakref at 0xb7810144; to 'Toto' at 0xb780db2c>, <weakref at 0xb781016c; to 'Toto' at 0xb780db4c>]) __del__(<__main__.Toto object at 0xb780da6c>) ('instances', [<weakref at 0xb78100f4; to 'Toto' at 0xb780daec>, <weakref at 0xb781011c; to 'Toto' at 0xb780db0c>, <weakref at 0xb7810144; to 'Toto' at 0xb780db2c>, <weakref at 0xb781016c; to 'Toto' at 0xb780db4c>]) __del__(<__main__.Toto object at 0xb780daec>) __del__(<__main__.Toto object at 0xb780db0c>) __del__(<__main__.Toto object at 0xb780db2c>) ('instances', [<weakref at 0xb781016c; to 'Toto' at 0xb780db4c>]) Fin de code: Appuillez sur une touche pour finir. Grand ménage __del__(<__main__.Toto object at 0xb780db4c>)
Edit: Rajout de getinstances
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 #!/usr/bin/env python # -*- coding: ISO8859-1 -*- # # import weakref from sys import version if version.startswith('3'): raw_input = input class Toto(object): instances = [] def __init__(self): self.ref = weakref.ref(self) self.instances.append(self.ref) def __del__(self): self.instances.remove(self.ref) print ('__del__(%s)' % self) def __str__(self): return repr(self) def getinstances(self): return [ref() for ref in self.instances] t1 = Toto() print('t1:', t1) print('instances', Toto.instances) t2 = Toto() t3 = Toto() t4 = Toto() t5 = Toto() print('getinstances', t5.getinstances()) print('instances', Toto.instances) del t1 print('instances', Toto.instances) print('getinstances', t5.getinstances()) del t2 del t3 del t4 print('instances', Toto.instances) print('getinstances', t5.getinstances()) raw_input("Fin de code: Appuillez sur une touche pour finir.") print("Grand ménage")