Python variablen mit den Wert einer Instanz einer Klasse zurückverfolgen

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
MupfSpace
User
Beiträge: 169
Registriert: Montag 25. Dezember 2017, 20:26

Hallo,

Ich habe eine Instanz einer Klasse.
Diese Instanz teile ich mehreren variablen in verschiedenen Klassen zu, diese Klassen instanziiere ich dann auch.

Code: Alles auswählen

foo = Foo()

class A:
    def __init__(self):
        self.a_foo = Foo()
		
class B:
    def __init__(self):
        self.b_foo = Foo()
		
a  = A()
b = B()


nun möchte ich, in der Foo Klasse eine Funktion haben, mit der ich alle Klassen und Instanzen der jeweiligen Foo-Instanz, und den Namen diese Variablen abfragen kann.
also...:

Code: Alles auswählen

class Foo:
    def get_locations(self):
        ...
		
foo = Foo()

... # siehe oben

print(foo.get_locations)

# erwartete Ausgabe: [("a_foo", <__main__.A object at ...>, <class '__main__.A'>), ("b_foo", <__main__.B object at ...>, <class '__main__.B'>)]
wie kann ich das realisieren?
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ein Weg besteht in einer (globalen!) klassenvariable auf Foo, die alle Instanzen nachverfolgt, weil die sich darin selbst registrieren. Den Namen wiederum bekommt du NICHT. Das ist ganz theoretisch machbar, aber dann wird es wenig robust und hässlich.

Grundsätzlich ist so ein Vorgehen aber erstmal ungewöhnlich, und sollte wegen der globalen Variable vermieden werden. Welches Problem willst du mit diesem Vorgehen lösen?
MupfSpace
User
Beiträge: 169
Registriert: Montag 25. Dezember 2017, 20:26

Ich möchte eine Property klasse schreiben, der ein wert zu gewiesen werden kann und die sich wie eine normale variable verhält (wie das funktioniert weiß ich, also __set__, __get__, __add__, ...).
Dann möchte ich, wenn sich der Wert verändert, mit isinstance überprüfen ob die Property in einer bestimmten Klasse ist (z.B. ein Widget), die ich selber geschrieben habe und die eine update Funktion enthält, diese update Funktion aufrufen und der Name der Variable soll übergeben werden um festzulegen was genau upgedated werden soll...
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das ist aber sehr weit weg von der ursprünglichen Frage. Weder kommen da jetzt alle Instanzen vor, noch war vom descriptor protocol die Rede.

Mit dem geht seit Python 3.4 oder so auch, dass man den Namen eines Properties bekommt, __set_name__ oder so. Musst du mal nachlesen.
MupfSpace
User
Beiträge: 169
Registriert: Montag 25. Dezember 2017, 20:26

Nein das mit dem set sachen ist für die Frage egal, da weiß ich wie das geht.
Ich muss auf die Instanzen und die Namen zugreifen, um eben beim Aufruf von z.B. __set__ zu überprüfen, ob die Position/Instanz eine Instanz von meiner Klasse ist, um dort eine update/rerender Funktion aufzurufen.
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich glaube du hast meine Antwort nicht verstanden. Ich rede nicht von __set__.
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Hier ist ein Beispiel dafür was __deets__ gemeint hat:

Code: Alles auswählen

class MyClass:
    def update(self, name, value):
        print("update", name, value)


class TheirClass:
    pass


class MyDescriptor:
    def __init__(self):
        self.name = None

    def __set_name__(self, owner, name):
        self.name = name

    def __set__(self, instance, value):
        if isinstance(instance, MyClass):
            # Safety: name is not None because it's guaranteed that __set_name__
            # is called with a name when the class `instance` is an instance
            # of is created.
            instance.update(self.name, value)
        else:
            print(f"Warning: cannot update {instance!r} not a subclass of MyClass")


class A(MyClass):
    foo = MyDescriptor()


class B(TheirClass):
    bar = MyDescriptor()


def main():
    a = A()
    a.foo = 1

    b = B()
    b.bar = 2


if __name__ == "__main__":
    main()
Die Alternative wäre über den Garbage Collector sich die Referenzen anzuschauen aber dass ist sehr ineffizient und nicht sinnvoll außer für Spielereien oder Debugging.
Antworten