Seite 1 von 1

Anzahl Instanzen einer Klasse

Verfasst: Samstag 24. Mai 2008, 16:44
von wuf
Hallo Forumfreunde

Ist es auf einfache Art möglich herauszufinden wieviele Instanzen einer Klasse erstellt wurden ohne sie explizit bei der Erstellung zu zählen? Gut wäre auch noch die Instanz-Referenzen als Liste abrufen zu können.

Gruss wuf :wink:

Verfasst: Samstag 24. Mai 2008, 17:26
von Leonidas
Mir ist kein solcher Weg bekannt. Normalerweise packt man gleichartige Klassen in Container und das passt dann schon so. Ich fände es seltsam, wenn Instanzen je nach Anzahl bereits existierender Instanzen sich anders verhalten würden.

Verfasst: Samstag 24. Mai 2008, 19:17
von BlackVivi
Wenn es denn sowas wie statische Attribute gäbe... Ja, dann könnte man es zumindest zum Teil implementieren. Aber ich habe hier irgendwie mal gelesen, dass der destruktor von Python eigentlich gar keiner ist... Aber ich habe den noch nie wirklich benutzt.

Verfasst: Samstag 24. Mai 2008, 19:42
von Karl
Also gibt's keine statischen Variablen in Python?
Wieder was gelernt ;p
Aber man kann doch theoretisch innerhalb des Konstruktors eine Variable außerhalb der Klasse (globale Variable?) hochzählen, oder?
Wobei das natürlich keinen Sinn macht, wenn der Destruktor, wie BlackVivi sagte, nicht richtig funktioniert bzw. nicht dafür gedacht ist ;o
Aber dann kann man ja noch notfalls, wenn's nicht zu umständlich ist (keine Ahnung, um was es genau geht, daher kann ich das auch nicht sagen), jedes mal wenn man eine Instanz zerstört, den Wert wieder eins runtersetzen. Aber das geht dann auch wieder nur, wenn man die Instanzen selbstständig zerstört.

Verfasst: Samstag 24. Mai 2008, 19:49
von veers
Gehen tut es:

Code: Alles auswählen

number_of_strings = sum(1 for obj in gc.get_objects() if isinstance(obj, str))
Schlau ist es sehr wahrscheinlich nicht. ;)

Und zu den Statischen Variablen es gibt Klassen Variablen:

Code: Alles auswählen

class GlobalCounter(object):
    counter = 0
    def count(self):
        GlobalCounter.counter += 1
        return GlobalCounter.counter
   ....: 

In [21]: GlobalCounter().count()
Out[21]: 1

In [22]: GlobalCounter().count()
Out[22]: 2

Verfasst: Samstag 24. Mai 2008, 19:55
von BlackVivi
VORSICHT GRAUSAM

Code: Alles auswählen

In [45]: a = int()

In [46]: global a

In [58]: class Foo(object):
   ....:     def __init__(self):
   ....:         global a
   ....:         a += 1
   ....:         
   ....:     def __del__(self):
   ....:         global a
   ....:         a -= 1
   ....:         
   ....:         

In [59]: Foo()
Out[59]: <__main__.Foo object at 0x85d72cc>

In [60]: Foo()
Out[60]: <__main__.Foo object at 0x85d716c>

In [61]: a
Out[61]: 2

In [63]: Foo()
Out[63]: <__main__.Foo object at 0x85d736c>

In [64]: Foo()
Out[64]: <__main__.Foo object at 0x85d73cc>

In [65]: Foo()
Out[65]: <__main__.Foo object at 0x85d74ac>

In [66]: a
Out[66]: 5

In [67]: foo = Foo()

In [68]: a
Out[68]: 6

In [69]: foo = None

In [70]: a
Out[70]: 5

In [71]: liste = [Foo(), Foo()]

In [72]: a
Out[72]: 7

In [73]: liste = None

In [74]: a
Out[74]: 5
Wie unfassbar sinnfrei.

@veers
Die Dinger habe ich vorhin gesucht =_= Ich wusste das ich sie schonmal benutzt hatte, aber ich bin einfach zu lange raus und muss durch die Hochschule halt Java lernen... Da verdrängt man schnell mal ein paar Sachen. Ich bin so doof ~_~

Verfasst: Samstag 24. Mai 2008, 19:58
von lunar

Code: Alles auswählen

gc.get_referrers(MyClass)
Die Doku sagt dazu allerdings: "Avoid using get_referrers() for any purpose other than debugging."

Diese Warnung sollte man beherzigen. Wenn man eine Liste aller Instanzen einer Klasse braucht, dann sollte man das explizit über ein Klassenattribut und das Überschreiben des Konstruktors lösen.

Alles andere ist zu magisch und hat imho in sauberem Code nichts zu suchen!

Verfasst: Samstag 24. Mai 2008, 20:16
von Leonidas
BlackVivi, das ist keine gute Idee. Der Zeitpunkt an dem ``__del__`` aufgerufen wird ist in Python undefiniert. Vielleicht auch gar nicht, dann stimmt der Counter gar nicht mehr. Jetzt nehmen wir noch Threads dazu, die gleichzeitig ``a`` modifizieren und das Chaos ist komplett.

Verfasst: Samstag 24. Mai 2008, 20:22
von BlackVivi
Leonidas hat geschrieben:BlackVivi, das ist keine gute Idee. Der Zeitpunkt an dem ``__del__`` aufgerufen wird ist in Python undefiniert. Vielleicht auch gar nicht, dann stimmt der Counter gar nicht mehr. Jetzt nehmen wir noch Threads dazu, die gleichzeitig ``a`` modifizieren und das Chaos ist komplett.
Jap, deswegen steht auch "VORSICHT GRAUSAM" davor :3 Und deswegen steht dazwischen auch einige Beispiele, wo __del__ scheinbar gar nicht in einem absehbaren Zeitraum aufgerufen wird... Wenn man es nämlich nie an einen Namen bindet. Wollte damit nur zeigen, dass __del__ fei doof ist, mehr nicht ._.

Verfasst: Samstag 24. Mai 2008, 22:34
von wuf
Hallo Forumfreunde

Danke für all eure interessanten Rückmeldungen. Es war nicht meine Absicht euch ein so schwer verdaubaren Braten aufzutischen.

Gruss wuf :wink:

Verfasst: Sonntag 25. Mai 2008, 10:08
von BlackJack
Lösungsmöglichkeit: In der `__init__()` eine schwache Referenz auf `self` in eine Liste stecken, die an die Klasse gebunden ist. Schwache Referenz -> `weakref`-Modul. Und wenn man wissen will wieviele Exemplare es gibt, dann schaut man einfach wieviele von den Referenzen noch "leben".

Die Vorgehensweise hat natürlich auch so ihre Nachteile. Zum Beispiel kann die Liste mit "toten" Referenzen lang werden und die Laufzeit der Abfrage der Anzahl ist nicht in O(1).

Verfasst: Sonntag 25. Mai 2008, 10:45
von sma
veers hat geschrieben:Gehen tut es:

Code: Alles auswählen

number_of_strings = sum(1 for obj in gc.get_objects() if isinstance(obj, str))
Schlau ist es sehr wahrscheinlich nicht. ;)
Funktioniert das überhaupt? Dies hier

Code: Alles auswählen

len([o for o in gc.get_objects() if type(o) is str])
gibt bei mir immer 0 - auch wenn ich "int" benutze oder "isinstance" statt "type".

Stefan

Verfasst: Sonntag 25. Mai 2008, 14:27
von veers

Code: Alles auswählen

In [21]: sum(1 for obj in gc.get_objects() if isinstance(obj, str))
Out[21]: 12

In [22]: test = "some string"

In [23]: sum(1 for obj in gc.get_objects() if isinstance(obj, str))
Out[23]: 13
Testweise - Ja. Praktisch - vielleicht.