Seite 1 von 1

Gültigkeit/Referenz von Instanzvariablen

Verfasst: Mittwoch 16. Januar 2019, 13:53
von GEEN55
Hallo,
ich bin Anfänger in Python. Mein Programm verhält sich für mich nicht erklärbar. Vielleicht hat jemand von Euch eine Idee was ich falsch mache.
Meine Klasse sieht wie folgt aus:

Code: Alles auswählen

import matplotlib.image as mpimg

class PolygonTest:
   
    def __init__(self, fileName):
        self.fileName = fileName
        self.__readOriginalFile()
        
    def __readOriginalFile(self):
        self.bild = mpimg.imread(self.fileName)
        return 
  
    def setRefRGB(self,x,y):
        self.refRGB = self.bild[y,x]
        return

    def getRefRGB(self):
        return self.refRGB

    def markLine(self,x,y):
        print("setRefRGB markLine 1:", self.refRGB)   #Testausgabe
        # Linie malen
        self.bild[y,x][0] = 0.0 #R
        self.bild[y,x][1] = 1.0 #G
        self.bild[y,x][2] = 1.0 #B
        print("setRefRGB markLine 2:", self.refRGB)   #Testausgabe
        return

Wenn ich diese nun in folgenden Programm nutze, dann verändert sich der Inhalt der Variable refRGB, obwohl ich dies nicht explizit (nach Initialisierung) tue.

Code: Alles auswählen


from polygon99 import PolygonTest

fileName = 'kurve-klein.png'
po1 = PolygonTest(fileName)
po1.setRefRGB(32,32)
po1.markLine(32,32)

die Ausgabe sieht wie folgt aus
setRefRGB markLine 1: [0. 0. 0.]
setRefRGB markLine 2: [0. 1. 1.]
Als wäre refRGB nur ein Zeiger auf bild[32,32]

Für einen Hinweis wäre ich dankbar.

Re: Gültigkeit/Referenz von Instanzvariablen

Verfasst: Mittwoch 16. Januar 2019, 14:08
von __deets__
Da ist so einiges im argen:

- vergiss, dass es doppelte Unterstriche gibt. Die tun nicht, was du glaubst das sie tun, und die Konvention fuer "private" Eigenschaften ist ein einfacher Unterstrich.
- getter und setter schreibt man nicht. In Python gibt es einen Property-Mechanismus, falls aus einem simplen mein_objekt.foo mehr werden muss. Spar dir also getRefRGB.
- die leeren returns kannst du dir ebenso sparen.


Last but not least: ja, Python bindet nur Objekte an Namen. Du kannst dieselbe Liste an tausend Namen binden, und wenn du die Liste veraenderst, dann greifst du durch diese 1000 Namen auch auf die veraenderte Liste zu.

Du musst also eine explizite Kopie der Liste machen, wenn es das ist, was du willst.

Code: Alles auswählen

class PolygonTest:
   
    def __init__(self, fileName):
        self.fileName = fileName
        self._readOriginalFile()
        self.refRGB = [-1, -1, -1]

    def _readOriginalFile(self):
        self.bild = mpimg.imread(self.fileName) 
  
    def setRefRGB(self,x,y):
        self.refRGB = list(self.bild[y,x])
       
    def markLine(self,x,y):
        print("setRefRGB markLine 1:", self.refRGB)   #Testausgabe
        # Linie malen
        self.bild[y,x][0] = 0.0 #R
        self.bild[y,x][1] = 1.0 #G
        self.bild[y,x][2] = 1.0 #B
        print("setRefRGB markLine 2:", self.refRGB)   #Testausgabe

Re: Gültigkeit/Referenz von Instanzvariablen

Verfasst: Mittwoch 16. Januar 2019, 14:15
von GEEN55
Ahhhh ... super. Danke für die Hinweise. Da hätte ich mir einen "Wolf" gesucht .....
Nochmals Danke für die schnelle Hilfe!!!

Re: Gültigkeit/Referenz von Instanzvariablen

Verfasst: Mittwoch 16. Januar 2019, 15:04
von __blackjack__
@GEEN55: Zur Namensschreibweise würde ich noch auf den Style Guide for Python Code hinweisen.

Die einzilige ”private” Methode ist IMHO nicht sinnvoll.

Das es sich nur um Namen für das jeweils gleiche Objekt handelt, kann man sich zunutze machen um nicht jedes mal das gleiche Pixel abzufragen in dem man das nur *einmal* am Anfang macht. Und wahrscheinlich kann man sich auch die drei Einzelzuweisungen sparen.

Ungetestet:

Code: Alles auswählen

class PolygonTest:
   
    def __init__(self, filename):
        self.filename = filename
        self.image = mpimg.imread(self.filename)
        self._reference_rgb = [-1, -1, -1]

    def set_reference_rgb(self, x, y):
        self._reference_rgb = list(self.image[y, x])
       
    def mark_line(self, x, y):
        print('reference_rgb mark_line 1:', self._reference_rgb)  # Testausgabe
        # Linie malen
        pixel = self.image[y, x]
        pixel[0] = 0.0 # R
        pixel[1] = 1.0 # G
        pixel[2] = 1.0 # B
        
        # Alternativ könnte auch das hier gehen statt der drei einzelnen
        # Zuweisungen:
        
        self.image[y, x][:] = [0.0, 1.0, 1.0]
        
        print('reference_rgb mark_line 2:', self._reference_rgb)  # Testausgabe

Re: Gültigkeit/Referenz von Instanzvariablen

Verfasst: Donnerstag 17. Januar 2019, 08:21
von GEEN55
Danke für den Hinweis, insbesondere für den Sytle Guide.