mutable/inmutable Instanz/Referenz

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
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Erstmal ein Beispiel:

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: UTF-8 -*-

class test:
    def __init__(self):
        self.data = {
            "test": "init"
        }
        self.d = self.data["test"]

    def test(self):
        print self.data
        print self.d

        print id(self.d)
        print id(self.data["test"])

        print

    def change_dict(self):
        self.data["test"] = "changed!"

    def change_d(self):
        self.d="changed!"


t = test()
t.test()
t.change_d()
t.test()

print "="*80

t = test()
t.test()
t.change_dict()
t.test()
Ausgabe:
{'test': 'init'}
init
-1210445760
-1210445760

{'test': 'init'}
changed!
-1210445472
-1210445760

================================================================================
{'test': 'init'}
init
-1210445760
-1210445760

{'test': 'changed!'}
init
-1210445760
-1210445536
Also wie man sehen kann, ist es so, das self.d und self.data["test"] erstmal das selbe Objekt sind, aber nachdem eines von Beiden geändert wird, ist es nicht mehr das selbe Objekt, denn auch der Wert wird nicht direkt beim anderen geändert...

Ich hätte es aber eigentlich gern so, das sich immer gleichzeitig beide Werte ändert. Wie mach ich das???

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Hm! Mit einer "Hilfs-Klasse" würde es gehen:

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: UTF-8 -*-

class data:
    def __init__(self):
        self.data = "init"

    def change(self, txt):
        self.data = txt

    def __repr__(self):
        return self.data

class test:
    def __init__(self):
        self.data = {
            "test": data()
        }
        self.d = self.data["test"]

    def test(self):
        print self.data
        print self.d

        print id(self.d)
        print id(self.data["test"])

        print

    def change_dict(self):
        self.data["test"].change("changed!")

    def change_d(self):
        self.d.change("changed!")


t = test()
t.test()
t.change_d()
t.test()

print "="*80

t = test()
t.test()
t.change_dict()
t.test()
{'test': init}
init
-1210372532
-1210372532

{'test': changed!}
changed!
-1210372532
-1210372532

================================================================================
{'test': init}
init
-1210372404
-1210372404

{'test': changed!}
changed!
-1210372404
-1210372404
Allerdings möchte ich eigentlich nur vier Zustände speichern: "init", "install", "command", "normal"

...hm... ich überleg mal...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Hm! Das ganze könnte so aussehen:

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: UTF-8 -*-

class runlevel(object):
    state = "init"

    def set_install(self):
        self.state = "install"
    def set_command(self):
        self.state = "command"
    def set_normal(self):
        self.state = "normal"

    def is_install(self):
        return self.state == "install"
    def is_command(self):
        return self.state == "command"
    def is_normal(self):
        return self.state == "normal"

    def __repr__(self):
        return "<runlevel object with state = '%s'>" % self.state


class test:
    def __init__(self):
        self.runlevelata = {
            "runlevel": runlevel()
        }
        self.runlevel = self.runlevelata["runlevel"]

    def test(self):
        print self.runlevelata
        print self.runlevel

        print id(self.runlevel)
        print id(self.runlevelata["runlevel"])

        print

    def change_dict(self):
        self.runlevelata["runlevel"].set_command()

    def change_d(self):
        self.runlevel.set_command()


t = test()
t.test()
t.change_d()
t.test()

print "="*80

t = test()
t.test()
t.change_dict()
t.test()
{'runlevel': <runlevel object with state = 'init'>}
<runlevel object with state = 'init'>
-1210412980
-1210412980

{'runlevel': <runlevel object with state = 'command'>}
<runlevel object with state = 'command'>
-1210412980
-1210412980

================================================================================
{'runlevel': <runlevel object with state = 'init'>}
<runlevel object with state = 'init'>
-1210410900
-1210410900

{'runlevel': <runlevel object with state = 'command'>}
<runlevel object with state = 'command'>
-1210410900
-1210410900
Funktioniert so wie ich das brauche, aber ist das nicht vielleicht ein wenig zu viel???

Nun frage ich nicht mehr mit if runlevel == "install" ... sondern nur mit if runlevel.is_install() ...

Is das ok so??? Was meint ihr???

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

jens hat geschrieben:Is das ok so??? Was meint ihr???
Hi Jens!

Den kennst du ja schon: "Viele Wege führen nach Rom..." :twisted:

Wie zuverlässig brauchst du es denn? Der hier ist schon ziemlich zuverlässig. Allerdings weiß ich nicht, ob du es in deinem Fall nicht einfach dabei belässt, direkt auf das Dictionary zuzugreifen.

Code: Alles auswählen

class Runlevel(object):
    
    __slots__ = "_runlevel"

    _possible_runlevels = ["install", "command", "normal"]
    
    def __init__(self, runlevel = "normal"):
        self._runlevel = runlevel
    
    def _get_state(self):
        return self._runlevel

    def _set_state(self, value):
        assert(value in self._possible_runlevels)
        self._runlevel = value
    
    def _del_state(self):
        self._runlevel = "normal"
        
    state = property(_get_state, _set_state, _del_state)
    
    def __repr__(self):
        return self._runlevel
    

class Test:
    def __init__(self):
        self.runlevelata = {
            "runlevel": Runlevel()
        }
        self.runlevel = self.runlevelata["runlevel"]

    def test(self):
        print self.runlevelata
        print self.runlevel

        print id(self.runlevel)
        print id(self.runlevelata["runlevel"])

        print

    def change_dict(self):
        self.runlevelata["runlevel"].state = "command"

    def change_d(self):
        self.runlevel.state = "install"


# TEST 1
r = Runlevel("command")
print r
r.state = "install"
print r.state
del r.state
assert (r.state == "normal")
print r

print 
print

# TEST 2
t = Test()
t.test()
t.change_dict()
t.test()
t.change_d()
t.test()
Ergebnis:

Code: Alles auswählen

command
install
normal


{'runlevel': normal}
normal
10368688
10368688

{'runlevel': command}
command
10368688
10368688

{'runlevel': install}
install
10368688
10368688
lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Um die Werte eines Dictionaries einzuschränken, könntest du aber auch so vorgehen:

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: UTF-8 -*-

class RunlevelData(dict):
    
    _possible_keys = ("runlevel",)
    _possible_runlevels = ("normal", "command", "install",)
    
    def __init__(self):
        dict.__init__(self)
        self["runlevel"] = "normal"
    
    def __setitem__(self, key, value):
        assert(key in self._possible_keys)
        if key == "runlevel":
            assert(value in self._possible_runlevels)
        dict.__setitem__(self, key, value)
        

r = RunlevelData()
print r

r["runlevel"] = "install"
print r
lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Danke für deine Hilfe, die zweite Variante sieht recht interessant aus ;) Aber nun hab ich wieder ein anderes/ähnliches grundlegende Problem:

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: UTF-8 -*-

class runlevel(object):
    pass


class bsp:
    def __init__(self, objects):
        self.runlevel = objects["runlevel"]

    def check(self):
        print "bsp:"
        print id(self.runlevel)
        print self.runlevel
        print


class test:
    def __init__(self):
        self.objects = {
            "runlevel": None
        }
        self.runlevel = self.objects["runlevel"]

        self.bsp = bsp(self.objects)
        self.bsp.check()

    def init2(self):
        # Hier reicht es nicht nur self.runlevel oder nur
        # self.objects["runlevel"] neu zu setzten :(
        self.runlevel = self.objects["runlevel"] = runlevel()

    def test(self):
        print "test:"
        print id(self.runlevel)
        print id(self.objects["runlevel"])
        print

        self.bsp.check()


t = test()
t.init2()
t.test()

print "="*80

t = test()
t.init2()
t.test()
Ich hab in test neben der normalen __init__() noch ein init2() (Das brauche ich in PyLucid, denn nicht alle Objekte kann ich zu jedem Zeitpunkt gebrauchen)

Nun ist es aber so, das in der Klasse bsp das runlevel-Objekt nicht "ankommt". Weil es zu den Zeitpunkt noch None ist und erst in init2() erzeugt wird... Das wird aber leider nicht "übertragen"...

Mir fällt da spontan keine Lösung für ein :( Ich dachte eigentlich ich würde es nur mit Referenzen zu tun haben, dem ist aber wohl leider nicht so...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Hab nun eine Lösung: Ich instanziere alle Objekte in __init__() sodas ich alles zusammen hab. Die Objekte die ich erst später in init2() benutzten kann, haben ebenfalls ein init2() welches ich dann erst ausführe ;)

.oO(Muß man jetzt nicht nachvollziehen können) :lol:

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Antworten