[python] stiekem toch pointers? (bug, kom er niet uit)

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • denpries
  • Registratie: Februari 2010
  • Laatst online: 07-06 10:41
Beste mensen,

Ik zit met een issue, want ik ben tot de conclusie gekomen dat ik er geen kont meer van snap, hoewel ik toch een tijdje al weer zit te programmeren in Python. En aangezien ik het idee heb dat ik iets heel erg basis fout doe, is dat gevaarlijk voor de rest van mijn brouwsels dus heb ik hulp nodig.

Ik heb een eigen 'class' waarin ik simuleer dat ik een matrix heb. Ofwel het bevat gewoon een lijst met waaden en als cols en rows 8 is en ik een lijst van 64 waarden heb, kan ik dan mooi waarde (2,3) bijvoorbeeld opvragen.

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Mat:
    
    def __init__(self, rows, columns):
        #initialize a 'matrix'
        if rows <=0 or columns <= 0:
            raise Exception("Cannot use 0 or negative as value for rows/columns")
        self.rows=rows
        self.columns=columns
        self.data=[]

    def getpx(self,row,column):
        #return a certain pixel
        if len(self.data) == 0:
            raise Exception("There is no data in the current Matrix")
        if row <=0 or column <= 0:
            raise Exception("Cannot use 0 or negative as value for rows/columns")           
        return self.data[(row-1)*self.columns+(column-1)]


Nu doe ik het volgende (versimpeld), om het gemiddelde van de laagste 3 waarden te verkrijgen

code:
1
2
3
4
testmatrix = Mat(8,8,lijstvan64waarden) #initialiseren
datalijst = testmatrix.data
sortlijst=datalijst.sort()
avgmindata=sum(sortlijst[0:3])/3 #laagste 3 waarden optellen en delen door 3


Dat gaat allemaal prima. Denk je. Alleen nu blijkt dat de data in testmatrix ook gewoon wordt gesorteerd. Het lijkt dus alsof ipv de data naar datalijst wordt gekopieerd er in werkelijkheid een referentie wordt gekopieerd.

Ook als ik het via een omslachtige, gare manier doe gaat het fout
code:
1
2
3
4
5
sortmat=Mat(8,8)
gridDataAvgMat.copyData(sortmat)
sortlijst=sortmat.data
sortlijst.sort()
avgmindata=sum(sortlijst[0:3])/3


idee was ik doe het wel via een andere 'matrix', maar copydata doet in feite:
code:
1
2
3
4
5
6
7
8
9
    def copyData(self,targetmatrix):
        #Function to copy all data from one Mat to another
        if not isinstance(targetmatrix, Mat):
            raise Exception("Trying to copy data from Mat object to non-Mat object")
        if targetmatrix.rows != self.rows or targetmatrix.columns != self.columns:
            raise Exception("Trying to copy data from Mat object to another Mat object while columns / rows do not match!")
        if len(self.data) == 0:
            raise Exception("There is no data in the current Matrix to copy")
        targetmatrix.data=self.data


targetmatrix.data = self.data geeft dus wellicht ook gewoon een referentie door?

Los van het feit dat er allerlei andere handige dingen gebruikt kunnen worden voor het achterliggende doel, hoe voorkom ik dat de rest meesorteert?

Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

Kijk hier eens bij puntje 3. En dat los je zo op.

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • denpries
  • Registratie: Februari 2010
  • Laatst online: 07-06 10:41
:|

Hoe simpel kan het zijn. (facepalm)

Acties:
  • 0 Henk 'm!

  • denpries
  • Registratie: Februari 2010
  • Laatst online: 07-06 10:41
Ik snap nu heel goed (getest, en het werkt :P) hoe je dus lijsten behoort te kopieren.

Echter, stel dat ik nu heb:
testmatrix = Mat(8,8,lijstvan64waarden) #initialiseren

mijn Mat object heeft natuurlijk geen copy functie.
Dit is dan niet valide, toch?

code:
1
testmatrix2=testmatrix


Moet ik dan bv doen:
code:
1
2
3
4
5
6
def copy(self):
    newmat = Mat(8,8)
    newmat.data = self.data[:]
    newmat.columns = self.columns
    newmat.rows = self.rows
    return self


of is dat niet zoals het zou moeten?

Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

Ik zou het niet weten, ik ken geen Python en heb bovenstaande net even bij elkaar gegoogled. :P Volgens mij is dit wat je zoekt.

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • HuHu
  • Registratie: Maart 2005
  • Niet online
denpries schreef op maandag 01 september 2014 @ 13:36:
Ik snap nu heel goed (getest, en het werkt :P) hoe je dus lijsten behoort te kopieren.

Echter, stel dat ik nu heb:
testmatrix = Mat(8,8,lijstvan64waarden) #initialiseren

mijn Mat object heeft natuurlijk geen copy functie.
Dit is dan niet valide, toch?

code:
1
testmatrix2=testmatrix


Moet ik dan bv doen:
code:
1
2
3
4
5
6
def copy(self):
    newmat = Mat(8,8)
    newmat.data = self.data[:]
    newmat.columns = self.columns
    newmat.rows = self.rows
    return self


of is dat niet zoals het zou moeten?
Ik denk dat het "return newmat" moet zijn. Je kan ook even testen of de copy.copy() functie doet wat je wilt (zie post NMe).

Acties:
  • 0 Henk 'm!

  • denpries
  • Registratie: Februari 2010
  • Laatst online: 07-06 10:41
HuHu schreef op maandag 01 september 2014 @ 14:35:
[...]

Ik denk dat het "return newmat" moet zijn. Je kan ook even testen of de copy.copy() functie doet wat je wilt (zie post NMe).
copy.copy() betekent toch de procedure copy aanroepen van object copy?
mijn Mat() heeft geen copy procedure.

En idd het moet iig return newmat zijn ;)

Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

denpries schreef op maandag 01 september 2014 @ 15:15:
[...]

copy.copy() betekent toch de procedure copy aanroepen van object copy?
Dat zou je even kunnen Googlen natuurlijk. ;)
http://effbot.org/pyfaq/h...y-an-object-in-python.htm

Het makkelijkst zal het ongetwijfeld zijn als je een copy-functie maakt op je class en daarin copy.copy() gebruikt om een kopietje terug te geven.

[ Voor 19% gewijzigd door NMe op 01-09-2014 15:56 ]

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • RayNbow
  • Registratie: Maart 2003
  • Nu online

RayNbow

Kirika <3

Ter samenvatting en verduidelijking, variabelen in Python bevatten *altijd* een verwijzing naar een object. Wanneer je een assignment uitvoert, dan laat je een variabel naar een ander object wjizen, maar het oorspronkelijke object wordt niet gekopieerd.

Als je trouwens een gesorteerde versie van een lijst wil hebben zonder de lijst zelf aan te passen, gebruik dan lijst2 = sorted(lijst1) i.p.v. lijst.sort().

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


Acties:
  • 0 Henk 'm!

  • deadinspace
  • Registratie: Juni 2001
  • Laatst online: 17:33

deadinspace

The what goes where now?

denpries schreef op maandag 01 september 2014 @ 12:42:
Dat gaat allemaal prima. Denk je. Alleen nu blijkt dat de data in testmatrix ook gewoon wordt gesorteerd. Het lijkt dus alsof ipv de data naar datalijst wordt gekopieerd er in werkelijkheid een referentie wordt gekopieerd.
Pretty much. Het korte verhaal is dat alles in Python een referentie is. (Het lange verhaal is iets subtieler, ik vind dit wel een aardige uitleg, de moeite van het lezen waard):
>>> a = [2,3,1]
>>> b = a
>>> b.sort()
>>> b
[1, 2, 3]
>>> a
[1, 2, 3]
Python:
1
2
3
4
testmatrix = Mat(8,8,lijstvan64waarden) #initialiseren
datalijst = testmatrix.data
sortlijst=datalijst.sort()
avgmindata=sum(sortlijst[0:3])/3 #laagste 3 waarden optellen en delen door 3
datalijst en testmatrix.data verwijzen dus naar dezelfde lijst. Ik zie ook een verwarring over wat .sort() precies doet, want list.sort() sorteert list zelf en returnt niks; sortlijst is dus None na die assignment:
>>> a = [2,3,1]
>>> b = a.sort()
>>> a
[1, 2, 3]
>>> b
>>> 

In plaats daarvan kun je sorted() gebruiken, die blijft van de lijst zelf af maar returnt een gesorteerde kopie. Dat lost in dit geval je originele probleem ook meteen op:
>>> a = [2,3,1]
>>> b = sorted(a)
>>> a
[2, 3, 1]
>>> b
[1, 2, 3]
denpries schreef op maandag 01 september 2014 @ 13:36:
Ik snap nu heel goed (getest, en het werkt :P) hoe je dus lijsten behoort te kopieren.
Als het zeker weten om een lijst gaat die je moet kopieren (en dat is het geval bij Mat.data), dan kun je simpelweg list() gebruiken om een kopie te maken:
>>> a = [2,3,1]
>>> b = list(a)
>>> b.sort()
>>> a
[2, 3, 1]
>>> b
[1, 2, 3]

Overigens heeft de numerieke library numpy al matrices ingebouwd, dus als je met je matrices wil rekenen is dat misschien een goede optie :)

Acties:
  • 0 Henk 'm!

  • RayNbow
  • Registratie: Maart 2003
  • Nu online

RayNbow

Kirika <3

deadinspace schreef op maandag 01 september 2014 @ 19:43:
(Het lange verhaal is iets subtieler, ik vind dit wel een aardige uitleg, de moeite van het lezen waard)
De reacties zijn wat beter dan de intro van het artikel:
"Python passes references, by value". (This is actually also what Java does.)

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


Acties:
  • 0 Henk 'm!

  • denpries
  • Registratie: Februari 2010
  • Laatst online: 07-06 10:41
Bedankt voor alle input beste mensen :)

@deadinspace : numpy... gaat em niet worden :P het python script draait in linino op een arduino Yun en helaas pindakaas daar is nog geen numpy voor, of althans 4 maanden terug waren mensen nog flink bezig om dat voor elkaar te krijgen. Numpy heeft GCC nodig om te compilen en dat werkt weer niet lekker op linino etc etc. Dus dacht: sja, ik moet het zelf maar een beetje doen dan ;)
Pagina: 1