Probleme mit der Referenzierung

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
Tobias Schenk
User
Beiträge: 7
Registriert: Montag 12. Juli 2004, 13:35

Hallo zusammen!

Ich habe ein ganz seltsames Problem mit meinem Skript!

Die Ausgabe am Ende lautet:
(x,y,z) : (5.000,6.000,7.000)
(x,y,z) : (5.000,6.000,7.000)
(x,y,z) : (5.000,6.000,7.000)

Eigentlich bin ich das Meinung, daß dies die Ausgabe sein müsste:
(x,y,z) : (0.000,0.000,0.000)
(x,y,z) : (1.000,2.000,3.000)
(x,y,z) : (5.000,6.000,7.000)

...Vielleicht kann mir ja jmd. bei meinem grundlegendem Verständnis für Python helfen... ich kann's mir nicht erklären!

Code: Alles auswählen


# =======================================================================
# Class: coords
# generalyzed coords
# =======================================================================

class coords:
    """ Generalyzed space coordinates """

    # ===== member variables
    coList = [0.0,0.0,0.0] # internal data structure, external: c0, c1, c2

    # ===== construktor    
    def __init__(self, c0=0.0 ,c1=0.0 ,c2=0.0):
        """Constructor"""
        self.coList[0] = c0
        self.coList[1] = c1
        self.coList[2] = c2
        
    # ===== representation
    def __repr__(self):
        """
        Representation of coords
        - rounded on 3 digits
        """
        return "(%.3f,%.3f,%.3f)" % (self.coList[0],self.coList[1],self.coList[2] )

    # ===== get Index
    # - help method for getattr/setattr
    def getIndex(self,attr):
        """
        getIndex
        help method fot getattr / setattr
        """
        c = attr[1]
        # check for errors
        if len(attr)!=2:
           pass # Error: length not 2
        elif c in '012':
            return '012'.index(c)
        else:
            pass # Error: not 0,1,2
        # still here <-> error occured
        print "found: ",attr
        print "valid attributes are c0, c1, c2"
        raise AttributeError, "unknown attribute"           
        
    # ===== get Attributes
    def __getattr__(self, attr):
        """
        get Attribute
        - attr: c0,c1,c2
        - returns an attribute
        """
        if attr=="__str__":
            return self.__str__()
        else:
            ind = self.getIndex(attr)
            return self.coList[ind]

    # ===== set Attributes
    def __setattr__(self, attr,value):
        """
        set Attribute
        - attr: c0,c1,c2
        - sets an attribute
        """
        ind = self.getIndex(attr)
        self.coList[ind] = value

# ======================================================================
# Class: decart
# cartesian coords
# =======================================================================

class decartCoords(coords):
    """Decart xyz coordinates"""

    # ===== constructor    
    def __init__(self, x=0.0, y=0.0, z=0.0):
        coords.__init__(self, x,y,z)
              
    # ===== representation
    def __repr__(self):
       """
       Representation of cartesian coords
       """ 
       return "(x,y,z) : %s" % coords.__repr__(self)

   # ===== string
    def __str__(self):
        return self.__repr__()

# =======================================================================
# Execution
# =======================================================================

if __name__ == "__main__":
    print "Run script"
    t0 = decartCoords()
    t1 = decartCoords(1,2,3)
    t2 = decartCoords(5,6,7)
    print t0
    print t1
    print t2
Würde mich sehr über eine Antwort freuen, da dies für mich (bei der Arbeit) recht dringend ist!!!

Vielen Dank!

Gruß, Tobias
Milan
User
Beiträge: 1078
Registriert: Mittwoch 16. Oktober 2002, 20:52

Hi. Schreib doch mal "coList=[0.0,0.0,0.0]" in __init__ von coords. Dann bekommst du deine Ausgaben, wie du wolltest :wink: Auf deine Art und Weise ist coList nämlich eine Klassenvariable, die für ALLE Instanzen gleich ist. Wenn diese also geändert wird, dann für alle, deswegen die Ausgabe. Wenn du sie aber im Konstruktor erst festlegst, ist es eine Instanzvariable, die nur für diese eine Instanz gilt...
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Hi Tobias,

Code: Alles auswählen

class coords:
    """ Generalyzed space coordinates """

    # ===== member variables
    coList = [0.0,0.0,0.0] # internal data structure, external: c0, c1, c2

    # ===== construktor   
    def __init__(self, c0=0.0 ,c1=0.0 ,c2=0.0):
        """Constructor"""
        self.coList[0] = c0
        self.coList[1] = c1
        self.coList[2] = c2
...
hier steckt der Teufel im Detail.
coList ist eine Klassenvariable, also für alle Instanzen ein und das selbe Objekt. Daher wird der Inhalt der Liste, die ja mutable ist bei jedem Aufruf von __init__(...) verändert und das gilt für alle Instanzen!

Lass mal die Klassenvariable weg und erstelle für jede instanz eine eigene Liste.

Code: Alles auswählen

class coords:
    """ Generalyzed space coordinates """

    # ===== construktor   
    def __init__(self, c0=0.0 ,c1=0.0 ,c2=0.0):
        """Constructor"""
        self.colist = [c0, c1, c2]
...

Gruß

Dookie
Tobias Schenk
User
Beiträge: 7
Registriert: Montag 12. Juli 2004, 13:35

Hallo!

Vielen Dank für die Tips, aber offensichtlich funktioniert das leider noch nicht ganz!

Code: Alles auswählen

class coords:
    """ Generalyzed space coordinates """

    # ===== member variables
    # coList = [0.0,0.0,0.0] # internal data structure, external: c0, c1, c2

    # ===== construktor    
    def __init__(self, c0=0.0 ,c1=0.0 ,c2=0.0):
        """Constructor"""
        self.coList = [0.0,0.0,0.0]
        self.coList = [c0,c1,c2]
        
    # ===== representation
    def __repr__(self):
        """
        Representation of coords
        - rounded on 3 digits
        """
        return "(%.3f,%.3f,%.3f)" % (self.coList[0],self.coList[1],self.coList[2] )

    # ===== string
    def __str__(self):
        return self.__repr__()
    
    # ===== get Index
    # - help method for getattr/setattr
    def getIndex(self,attr):
        """
        getIndex
        help method fot getattr / setattr
        """
        c = attr[1]
        # check for errors
        if len(attr)!=2:
           pass # Error: length not 2
        elif c in '012':
            return '012'.index(c)
        else:
            pass # Error: not 0,1,2
        # still here <-> error occured
        print "found: ",attr
        print "valid attributes are c0, c1, c2"
        raise AttributeError, "unknown attribute"           
        
    # ===== set Attributes
    def __setattr__(self, attr,value):
        """
        set Attribute
        - attr: c0,c1,c2
        - sets an attribute
        """
         ind = self.getIndex(attr)
         self.coList[ind] = value

#=======================================================================
# Execution
# =======================================================================

if __name__ == "__main__":
    print "Run script"
    t0 = coords()
    t1 = coords(1,2,3)
    t2 = coords(5,6,7)
    print t0
    print t1
    print t2
tx = coords(x,y,z) aufzurufen ist jetzt möglich, aber bei print gibts ne Fehlermeldung, daß coList kein Attribut von coords ist...
Ich denke, vielleicht liegt der Fehler hierbei an dem setAttribute!? aber ich weiß es ehrlich gesagt nicht und würde mich über Hilfe freuen!

Gruß, Tobias
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Hi nochmal,

jo du vermutest richtig, es liegt an dem __setattr__.

Code: Alles auswählen

    # ===== set Attributes
    def __setattr__(self, attr,value):
        """
        set Attribute
        - attr: c0,c1,c2
        - sets an attribute
        """
        if attr in ["c0","c1","c2"]:
            ind = self.getIndex(attr)
            self.coList[ind] = value
        else: # set other attributes
            self.__dict__[attr] = value
Gruß

Dookie
[code]#!/usr/bin/env python
import this[/code]
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Nochmal ich :)

ich würde Dir empfehlen, daß ganze mit Newstyle-Klassen zu machen.
Damit kannst Du auch properties definieren.

Code: Alles auswählen

class coords(object):
    """ Generalyzed space coordinates """
    __slots__ = ["coList"]

    def _get_c0(self):
        return self.coList[0]
    def _set_c0(self, value):
        self.coList[0] = value
    c0 = property(_get_c0, _set_c0)

    def _get_c1(self):
        return self.coList[1]
    def _set_c1(self, value):
        self.coList[1] = value
    c1 = property(_get_c1, _set_c1)

    def _get_c2(self):
        return self.coList[2]
    def _set_c2(self, value):
        self.coList[2] = value
    c2 = property(_get_c2, _set_c2)

    def __init__(self, c0=0.0, c1=0.0, c2=0.0):
        """ Constructor """
        self.coList = [float(c0),float(c1),float(c2)]

    def __repr__(self):
        return "%s(%f, %f, %f)" % (self.__class__.__name__,
                                   self.coList[0],
                                   self.coList[1],
                                   self.coList[2])

    def __str__(self):
        return "(%.3f, %.3f, %.3f)"  % (self.coList[0],
                                        self.coList[1],
                                        self.coList[2])


# =========================================
# Execution
# =========================================

if __name__ == "__main__":
    print "Run script"
    t0 = coords()
    t1 = coords(1,2,3)
    t2 = coords(5,6,7)
    print t0
    print t1
    print t2
    print "Test Properties"
    print t1.c0, t1.c1, t1.c2
    print "Test repr"
    print repr(t2)
__repr__ sollte immer einen String zurückgeben, aus dem sich z.B. mit eval ein Objekt des selben Typs mit den selben Attributen erzeugen lässt.


Gruß

Dookie
[code]#!/usr/bin/env python
import this[/code]
Frank

Hallo Leute,

zum Thema Instanzen, Klassenvariablen und Objektvariablen möchte ich auch geren mitmischen und meine Fragen los werden.

Ich dachte immer den Unterschied zwischen Objekt- und Klassenvariablen verstanden zu haben (Klassenvariablen global gültig für alle Instanzen der Klasse). Leider kommen ich mit dem Variablenzugriff nicht klar.

Ich habe mir hierzu mal eine Beispiel-Skript gebastelt (zum Üben):

Code: Alles auswählen

Aeussen= 10

def getAueVar():
    return Aeussen

def setAueVar(value):
    TestVar.Aeussen=value
    
class SuperKlasse:

    Innere=20

    def __init__(self, a,b):
        self.A=a
        self.B=b

    def getObjVar(self):
        return [self.A, self.B]

    def setObjVar(self,valuea,valueb):
        self.A=valuea
        self.B=valueb

    def __str__(self):
        return str(self.A)+" , "+str(self.B)

    def getInnVar():
        return Innere

    def setInnVar(value):
        Innere=value
Die Innere Variable müßte meines Erachtens eine Klassenvariable sein, die für alle SuperKlassen-Objekte gültig ist. Der Abruf des Inhaltes ist über den Klassennamen problemlos möglich, nur wenn ich den Wert jetzt ändern möchte wird "instance as first argument" gefordert.

Ich habe mir dann noch mal das ganze eine Ebene höher erstellt, hier gibt es keinen Fehler, nur der Variabeln Inhalt bleibt konstant. ist das hier ein Problem des Namensraums?

Ursprung meiner Frage ist eine kleine Übung, bei der ich zum Beispiel zwei Punkte oder Vektoren vergleichen möchte. Bei einer Unterschreitung einer als Klassenvariablen definierten Abweichungsgrenze solle dann eine entsprechendes Ergebnis ausgegeben werden.

Vielen Dank für Eure Hilfe und für Anregungen und Kritik immer offen
Frank
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Hi Frank,

Klassenvariablen werden innerhalb von Methoden bei lesendem Zugriff über self.name angesprochen. Soll der Wert der Klassenvariablen geändert werden, so muss dies über die Klasse geschehen. Sonst wird eine neue Instanzvariable angelegt. Hier sind auch wieder Newstyleklassen im Vorteil, da damit auch Klassenmethoden erzeugt werden können.

Code: Alles auswählen

Aeussen= 10

def getAueVar():
    return Aeussen

def setAueVar(value):
    global Aeussen  # jetzt kann Aeussen des Moduls 
    Aeussen=value   # geaendert werden
   
class SuperKlasse(object):

    Innere=20

    def __init__(self, a,b):
        self.A=a
        self.B=b

    def getObjVar(self):
        return [self.A, self.B]

    def setObjVar(self,valuea,valueb):
        self.A=valuea
        self.B=valueb

    def __str__(self):
        return str(self.A)+" , "+str(self.B)

    def getInnVar(cls):
        return cls.Innere
    getInnVar = classmethod(getInnVar)

    def setInnVar(cls, value):
        cls.Innere=value
    setInnVar = classmethod(getInnVar)
getInnVar ginge auch als normale Methode, so ists aber gleich ersichtlich daß hier auf die Klassenvariable zugegriffen wird.


Gruß

Dookie
[code]#!/usr/bin/env python
import this[/code]
Frank

Hallo und danke Dookie,

werde ich gleich ausprobieren und mich vertiefen.
Habe aber noch eine Frage betreffend "global". Ist die Variable jetzt nur innerhalb des Modules oder auch dort wo sie importiert wurde veröffentlicht? Erfolgt der Zugriff über den Modulnamen? Gerade bei Vergleichsoperationen mit Toleranzen hätte ich Sorge im Bezug auf ungewollte Beeinflussungen.

Auch wenn das hier jetzt nicht hier her gehört, möchte ich mal mein Lob an das Web-Design und die Struktur dieses Forums los werden. Da ich mich gern auch Vertieft mit HTML und vor allem mit DHTML beschäftigen möchte - kann mir jemand eine vergleichbares Forum empfehlen?

Grüße und Dank
Frank
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Hallo nochmal,
Habe aber noch eine Frage betreffend "global". Ist die Variable jetzt nur innerhalb des Modules oder auch dort wo sie importiert wurde veröffentlicht? Erfolgt der Zugriff über den Modulnamen?
Das global holt die Variable (in unserem Beispiel Aeussen) in den Namensraum der Funktion/Methode. So kann sie wie eine lokal definierte Variable verwendet werden, mit dem Unterschied, daß sie eben für das ganze Modul gültig ist. Natürlich wenn du von Aussen (also einem anderen Modul) die Variable ansprichst, kommt es darauf an, ob es sich bei dem Objekt, daß unter dem Variablennamen gespeichert ist, um ein "mutables" Objekt handelt oder nicht und wie man darauf zugreift. In dem Beispiel haben wir einen Integer der Variablen zugewiesen. So wird bei einem from modul import Aeussen der momentane Wert (zum Zeitpunkt des import) von Aeussen in das importierende Modul geholt. Wenn man aber import modul verwendet, und dann mit modul.Aeussen auf die Variable zugreift, wird der aktuelle Wert von modul.Aeussen verwendet oder auch geändert.
Anders ausgedrückt: Über modul.variable greifst du direkt über die referenz im Modul "modul" auf die variable zu. Bei "from modul import varible" bekommst Du eine Kopie der Referenz auf variable im importierenden Modul. Wenn es sich dabei dann z.B. um eine Liste handelt, zeigen natürlich beide referenzen auf die gleiche liste und Änderungen an der Liste sind für beide gültig. Ausser der Variablen wird eine neue Liste zugewiesen, was ja dann eine neue Referenz bedeutet.


Gruß

Dookie
[code]#!/usr/bin/env python
import this[/code]
Frank

Schönen Dank Dookie,

das war doch wirklich mal eine Erklärung für einen Dummi, wär es nicht für Einsteiger wie mich partktisch solche Erklärungen mit Beispielen diese Forums in einer Art Manuel abzulegen? Ich finde hier gibt es viele interessante Beiträge die dort Eingang finden könnten - wäre doch Schade wenn sie auf Grund von Überalterung einfach verloren gehen würden.

Grüße und Dank
Frank
Antworten