Anzahl Instanzen einer Klasse

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

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:
Take it easy Mates!
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

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.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
BlackVivi
User
Beiträge: 762
Registriert: Samstag 9. Dezember 2006, 14:29
Kontaktdaten:

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.
Karl
User
Beiträge: 252
Registriert: Freitag 29. Juni 2007, 17:49

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.
Benutzeravatar
veers
User
Beiträge: 1219
Registriert: Mittwoch 28. Februar 2007, 20:01
Wohnort: Zürich (CH)
Kontaktdaten:

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
[url=http://29a.ch/]My Website - 29a.ch[/url]
"If privacy is outlawed, only outlaws will have privacy." - Phil Zimmermann
Benutzeravatar
BlackVivi
User
Beiträge: 762
Registriert: Samstag 9. Dezember 2006, 14:29
Kontaktdaten:

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 ~_~
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!
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

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.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
BlackVivi
User
Beiträge: 762
Registriert: Samstag 9. Dezember 2006, 14:29
Kontaktdaten:

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 ._.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

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:
Take it easy Mates!
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).
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

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
Benutzeravatar
veers
User
Beiträge: 1219
Registriert: Mittwoch 28. Februar 2007, 20:01
Wohnort: Zürich (CH)
Kontaktdaten:

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.
[url=http://29a.ch/]My Website - 29a.ch[/url]
"If privacy is outlawed, only outlaws will have privacy." - Phil Zimmermann
Antworten