Instanzvariablen in der if-Bedingung

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
Qubit
User
Beiträge: 128
Registriert: Dienstag 7. Oktober 2008, 09:07

Irgendwie stehen ich gerade auf dem Schlauch :shock:

Code: Alles auswählen

>>> class test:
	def __init__(self,*args):
		self.arg = (args[0],args[1])
	def test(self,dic={}):
		temp = self.arg[0]
		if dic == {}:
			dic[self.arg[0]] = ''
			dic[temp] = ''
		print "debug1 dic:", dic
		dic[temp] = ''
		print "debug2 dic:", dic

		
>>> t1=test('1_eins','1_zwei')
>>> t2=test('2_eins','2_zwei')
>>> t1.arg[0],t1.arg[1]
('1_eins', '1_zwei')
>>> t2.arg[0],t2.arg[1]
('2_eins', '2_zwei')
>>> t1.test()
debug1 dic: {'1_eins': ''}
debug2 dic: {'1_eins': ''}
>>> t2.test()
debug1 dic: {'1_eins': ''}
debug2 dic: {'2_eins': '', '1_eins': ''}
>>> 
Wieso zeigt in der if-Bedigung self.arg[0] bzw. temp auf t1.arg[0]?
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Weil du in der Funktionssignatur von ``test`` ein Mutables Objekt nutzt, nämlich ein ``dict`` und dies von allen Instanzen geteilt wird (es wird erstellt wenn du die Funktion definierst, nicht wenn du die Klasse instanziierst). Wie alle Funktionssignaturen, aber das ist solange kein Problem, bis man versucht sie zu verändern und das ist bei dir ja in ``test`` der Fall.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Qubit
User
Beiträge: 128
Registriert: Dienstag 7. Oktober 2008, 09:07

Leonidas hat geschrieben:Weil du in der Funktionssignatur von ``test`` ein Mutables Objekt nutzt, nämlich ein ``dict`` und dies von allen Instanzen geteilt wird (es wird erstellt wenn du die Funktion definierst, nicht wenn du die Klasse instanziierst). Wie alle Funktionssignaturen, aber das ist solange kein Problem, bis man versucht sie zu verändern und das ist bei dir ja in ``test`` der Fall.
Ah, danke, verstehe..
bei Aufruf von t2.test() [und weiteren tn.test()] ist also die if-Bedingung gar nicht erfüllt!
Gemeine "Falle" ;-)
Qubit
User
Beiträge: 128
Registriert: Dienstag 7. Oktober 2008, 09:07

Noch eine kleine Frage dazu:
Kann man auf dieses mutable object 'dic' auch über eine Referenz ausserhalb der Funktion test() zugreiffen? Oder gibt es diese Referenz nur innerhalb dieser Funktion?
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Wenn du `dic' in `self.dic' änderst, dann wird es zur Instanz-Variable.

Allerdings solltest du die Funktionssignatur in

Code: Alles auswählen

def test(self, dic=None):
ändern und den Code anpassen:

Code: Alles auswählen

if dic is None: ...

Code: Alles auswählen

def test(self,dic=None):
        temp = self.arg[0]
        if dic is None:
            self.dic[self.arg[0]] = ''
            self.dic[temp] = ''
        else:
            self.dic = dic
        print "debug1 dic:", self.dic
        self.dic[temp] = ''
        print "debug2 dic:", self.dic
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Qubit hat geschrieben:Kann man auf dieses mutable object 'dic' auch über eine Referenz ausserhalb der Funktion test() zugreiffen?
Ja, über einen hmm, eher als Hack zu bezeichnenden Code: ``test.func_defaults``. Dort siehst du dann dass ``dic`` sich zwischen den Aufrufen von ``test`` ändert.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Qubit
User
Beiträge: 128
Registriert: Dienstag 7. Oktober 2008, 09:07

Leonidas hat geschrieben:
Qubit hat geschrieben:Kann man auf dieses mutable object 'dic' auch über eine Referenz ausserhalb der Funktion test() zugreiffen?
Ja, über einen hmm, eher als Hack zu bezeichnenden Code: ``test.func_defaults``. Dort siehst du dann dass ``dic`` sich zwischen den Aufrufen von ``test`` ändert.
Hiermit könnte man dann auch sowas wie ein "Singleton" basteln:

Code: Alles auswählen

>>> class test(object):
	def __new__(self):
		try:
			instance = self.__init__.func_defaults[0]['instance']
			return instance
		except:
			return object.__new__(self)
	def __init__(self,dic={}):
		if dic == {}: dic.update({'instance':self})
		object.__init__(self)

		
>>> t1=test()
>>> t2=test()
>>> t1,t2
(<__main__.test object at 0x016B1A30>, <__main__.test object at 0x016B1A30>)
>>> t1.wert='test'
>>> t2.wert
'test'
>>> del t1,t2
>>> t3=test()
>>> t3.wert
'test'
>>> 
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Warum sollte man sowas machen? Weil ``globale`` Variablen so toll sind?

Für Python gibt es übrigens etwas ähnliches wie das Singleton-Pattern, es heißt Borg-Pattern. Ob's sinnvoll ist, das sei mal dahingestellt.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
mkesper
User
Beiträge: 919
Registriert: Montag 20. November 2006, 15:48
Wohnort: formerly known as mkallas
Kontaktdaten:

Ein brauchbares Beispiel für Singletons sind Datenbankanbindungen, wenn ich mich richtig entsinne. Gemeinhin möchte man nicht im gleichen Programm zwei Zugriffe auf die selbe DB erstellen. :)
Benutzeravatar
helduel
User
Beiträge: 300
Registriert: Montag 23. Juli 2007, 14:05
Wohnort: Laupheim

Moin,
mkallas hat geschrieben:Ein brauchbares Beispiel für Singletons sind Datenbankanbindungen, wenn ich mich richtig entsinne. Gemeinhin möchte man nicht im gleichen Programm zwei Zugriffe auf die selbe DB erstellen. :)
Singletons werden für DB-Anbindungen oft benutzt, wenn auch nicht wirklich gebraucht ;-). Wenn ich nur eine Instanz haben will, dann erstelle ich mir nur eine und benutze diese. Warum eine Klasse dafür sorgen soll, dass sie nur einmal instanziert werden kann, erschließt sich mir nicht ganz. In dieser einen Anwendung mag das toll sein, aber in einer anderen brauche ich vielleicht zwei oder mehr Instanzen dieser Klasse. Dann darf ich umschreiben...

Gruß,
Manuel
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

mkallas hat geschrieben:Ein brauchbares Beispiel für Singletons sind Datenbankanbindungen, wenn ich mich richtig entsinne. Gemeinhin möchte man nicht im gleichen Programm zwei Zugriffe auf die selbe DB erstellen. :)
Und wer erstellt denn zusätzliche Datenbankverbindungen wenn nicht der Programmierer? Und wenn es der Programmierer ist, dann könnte er es auch sein lassen.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Qubit
User
Beiträge: 128
Registriert: Dienstag 7. Oktober 2008, 09:07

helduel hat geschrieben:Warum eine Klasse dafür sorgen soll, dass sie nur einmal instanziert werden kann, erschließt sich mir nicht ganz. In dieser einen Anwendung mag das toll sein, aber in einer anderen brauche ich vielleicht zwei oder mehr Instanzen dieser Klasse. Dann darf ich umschreiben...
Das ist zB nützlich, wenn man Kontrolle über den Zugriff auf Daten haben will, bspw. für einen Objektmanager..

Code: Alles auswählen

class objmgr(object):
    def __new__(self):
        try:
            instance = self.__init__.func_defaults[0]['instance']
            return instance
        except:
            return object.__new__(self)
    def __init__(self,dic={}):
        if dic == {}: dic.update({'instance':self})
        object.__init__(self)

    def _set(self,key='',value=''):
        try:
            if getattr(self.__obj,key)['owner'] == self:
                setattr(self.__obj,key,{'owner':self,'value':value})
            else: return False
        except:
            setattr(self.__obj,key,{'owner':self,'value':value})
        print "set message to "%s"" %(value)

    def _del(self,key=''):
        try:
            if getattr(self.__obj,key)['owner'] == self:
                delattr(self.__obj,key)
            else: return False
        except:
            return False
                    
    def obj(self):
        return self.__obj

	
class test(objmgr):
    def __init__(self):
        self._objmgr__obj = objmgr()


t1=test()
t2=test()
t1._set('message','von t1 an alle instanzen')
print "Message an t2:", t2.obj().message['value']
t2._set('message','von t2 an alle instanzen')
print "Message an t1:",t1.obj().message['value']
t1._del('message')
t2._set('message','von t2 an alle instanzen')
print "Message an t1:",t1.obj().message['value']
BlackJack

Wie krank ist das denn? Dein `test` *erbt* von `objmgr` und erstellt in seiner `__init__()` ein Exemplar davon um es als Attribut an sich selbst zu binden!? Argh!

Wenn man schon von `objmgr` erbt kann man auch einfach im Konstruktor dessen `__init__()` aufrufen, da wird `self` als Argument übergeben, was prima dazu verwendet werden kann eine Referenz auf das Objekt zu bekommen.
Qubit
User
Beiträge: 128
Registriert: Dienstag 7. Oktober 2008, 09:07

BlackJack hat geschrieben:Wie krank ist das denn? Dein `test` *erbt* von `objmgr` und erstellt in seiner `__init__()` ein Exemplar davon um es als Attribut an sich selbst zu binden!? Argh!

Wenn man schon von `objmgr` erbt kann man auch einfach im Konstruktor dessen `__init__()` aufrufen, da wird `self` als Argument übergeben, was prima dazu verwendet werden kann eine Referenz auf das Objekt zu bekommen.
Findest du?
'test()' nutzt die Methoden aus 'objmgr' um auf Daten aus 'objmgr()' zuzugreiffen ;-)
Benutzeravatar
helduel
User
Beiträge: 300
Registriert: Montag 23. Juli 2007, 14:05
Wohnort: Laupheim

Qubit hat geschrieben:Findest du?
'test()' nutzt die Methoden aus 'objmgr' um auf Daten aus 'objmgr()' zuzugreiffen ;-)
Ich steh wahrscheinlich nur auf dem Schlauch, aber ich verstehe das Beispiel nicht. Was bringt mir das?
Qubit
User
Beiträge: 128
Registriert: Dienstag 7. Oktober 2008, 09:07

helduel hat geschrieben:
Qubit hat geschrieben:Findest du?
'test()' nutzt die Methoden aus 'objmgr' um auf Daten aus 'objmgr()' zuzugreiffen ;-)
Ich steh wahrscheinlich nur auf dem Schlauch, aber ich verstehe das Beispiel nicht. Was bringt mir das?
Bei einfachen Applikationen wenig ;-)
Es geht darum, das Interface von den Daten und Daten von den Services zu trennen. 'test' ist eine Logikklasse, die auf "Services" von 'objmgr' zugreiffen soll und dabei die Daten in der singulären Instanz 'objmgr()' adressiert. Zwischen Logik ('test') und Services ('objmgr') für den Datenzugriff ('objmgr()') können hierbei unterschiedliche Interfaces zwischengeschaltet werden, die zB für die Logikklassen allesamt die gleiche Signatur haben, d.h. bei Änderung des "Services" müssen die Logikklassen nicht geändert werden. Die Interfaces bieten des weiteren verschiedene Pre- und Posttasks, zB zur Datenaufbereitung für In- / Outputmanagement, etc. Und um verschiedene Services auf den Daten zu implementieren, werden die Daten als Instanz adressiert. Wenn Daten, Services und Interfaces zusammenfallen, dann lässt sich auch alles in einer Klasse erledigen.

Code: Alles auswählen

class interface1_objmgr(objmgr):
    def setObj(self,key='',value=''):
        print "PREACTION1"
        self._set(key,value)
        print "POSTACTION1"

class interface2_objmgr(objmgr):
    def setObj(self,key='',value=''):
        print "PREACTION2"
        self._set(key,value)
        print "POSTACTION2"

class test2(interface1_objmgr):
    def __init__(self):
        self._objmgr__obj = objmgr()

i=test2()
i.setObj('info1',"hallo1")

class test2(interface2_objmgr):
    def __init__(self):
        self._objmgr__obj = objmgr()

i=test2()
i.setObj('info2',"hallo2")

class objmgr2(object):
    def _set(self,key='',value=''):
        setattr(self.__obj,key,{'owner':self,'value':value})

class interface3_objmgr(objmgr2):
    def setObj(self,key='',value=''):
        print "PREACTION3"
        self._set(key,value)
        print "POSTACTION3"        

class test3(interface3_objmgr):
    def __init__(self):
        self._objmgr2__obj = objmgr()

i=test3()
i.setObj('info3','hello3')
Antworten