numpy fehler ndarray no attribute append

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
TheCryperLp
User
Beiträge: 6
Registriert: Freitag 23. August 2013, 12:13

Hallo,
Ich habe eine Punkt-Klasse und eine Punktlistenklasse, aber innerhalb dieser Klasse erkennt python append() als Attribut. Wenn ich append() außerhalb aufrufe funktionierts. In der Klasse steht: self.list = numpy.array((), Point (so heißt meine Punktklasse) )
def addpointtolist(self, point):
self.list.append(point)
Und wenn ich in der klasse mit len(punktliste) die anzahl der punkte in der liste zählen will gibt er null zurück
:D
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo und willkommen im Forum!

Es wäre gut, wenn du deinen Beitrag noch einmal überarbeiten würdest. Ich habe ihn jetzt mehrfach gelesen und habe keine Idee, was du eigentlich sagen möchtest. Was für ein Problem hast du, wie äußert sich dieses (unerwartetes Verhalten, Fehlermeldung, etc.) und was für ein Ergebnis erwartest du. Im Falle einer Fehlermeldung solltest du diese, inklusive des gesamten Tracebacks, hier posten. Außerdem bietet es sich an, den betroffenen Code zu zeigen (das Forum hat übrigens Code-Tags, dann kann man den Code auch vernünftig lesen).
Das Leben ist wie ein Tennisball.
schaeffkoch
User
Beiträge: 38
Registriert: Dienstag 21. August 2012, 10:59

warum als numpy.array und nicht als list?
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@TheCryperLp: Verstehe ich es richtig, dass du ein Numpy-Array als Liste benutzen willst und dich darüber wunderst, dass dieses Numpy-Array kein `.append()` unterstützt? :o
TheCryperLp
User
Beiträge: 6
Registriert: Freitag 23. August 2013, 12:13

EyDu hat geschrieben:Hallo und willkommen im Forum!

Es wäre gut, wenn du deinen Beitrag noch einmal überarbeiten würdest. Ich habe ihn jetzt mehrfach gelesen und habe keine Idee, was du eigentlich sagen möchtest. Was für ein Problem hast du, wie äußert sich dieses (unerwartetes Verhalten, Fehlermeldung, etc.) und was für ein Ergebnis erwartest du. Im Falle einer Fehlermeldung solltest du diese, inklusive des gesamten Tracebacks, hier posten. Außerdem bietet es sich an, den betroffenen Code zu zeigen (das Forum hat übrigens Code-Tags, dann kann man den Code auch vernünftig lesen).
ok.
Hier der Code:

Code: Alles auswählen

import numpy
import math
from OpenGL import *
from OpenGL.GL import *
from OpenGL.GLU import *

class Point(object):
    def __init__(self, x = 0, y = 0, z = 0):
        self.x = x
        self.y = y
        self.z = z

    def __add__(self, other):
        try:
            rx = self.x + other.x
            ry = self.y + other.y
            rz = self.z + other.z
            return rx, ry, rz
        except(TypeError):
            print 'False Type(' + str(TypeError) + ')'
        except:
            print 'Cant add Point1(' + str(self) + ') and Point2(' + str(other) + ') !'

    def __sub__(self, other):
        try:
            rx = self.x - other.x
            ry = self.y - other.y
            rz = self.z - other.z
            return rx, ry, rz
        except(TypeError):
            print 'False Type(' + str(TypeError) + ')'
        except:
            print 'Cant subtract Point1(' + str(self) + ') and Point2(' + str(other) + ') !'

    def __mul__(self, other):
            rx = self.x * other.x
            ry = self.y * other.y
            rz = self.z * other.z
            return rx + ry + rz

    def __str__(self):
        return ('x: ' + str(self.x) + ', y: ' + str(self.y) + ', z: ' + str(self.z))

    def neg(self):
        self.x = 0 - self.x
        self.y = 0 - self.y
        self.z = 0 - self.z

    def get(self, var = None):
        if var == None:
            return self.x, self.y, self.z
        if var == 'x':
            return self.x
        if var == 'y':
            return self.y
        if var == 'z':
            return self.z
        
    def set(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z

class plist(list):
    def __init__(self):
        self.list = numpy.array((), Point)
        self.drawlist = numpy.array((), 'float32')
        self._highestPointInD = -1
        self.__wert = None
        self._wPoi = None
        
    def np(self, p = Point()):
        self.list.append(p)

##    def draw(self, drtype):
##        for i in range(len(self.list)):
##            self.drawlist.append(self.list[i].x)
##            self.drawlist.append(self.list[i].y)
##            self.drawlist.append(self.list[i].z)
##        glEnableClientState(GL_VERTEX_ARRAY)
##        glVertexPointer(3, GL_FLOAT, 0, self.drawlist)
##        if (drtype == 0) or (drtype == GL_TRIANGLES):
##            glDrawArrays(GL_TRIANGLES, 0, ((len(self.drawlist))/3))
##        elif (drtype == 1) or (drtype == GL_QUADS):
##            glDrawArrays(GL_QUADS, 0, (len(points))/4)
##        glDisableClientState(GL_VERTEX_ARRAY)
##
##    def setarray(self, other):
##        for i in range(1, (len(other) + 1), 3):
##            try:
##                self.list[i/3-1].x = other[i-3]
##                self.list[i/3-1].y = other[i-2]
##                self.list[i/3-1].z = other[i-1]
##            except(IndexError):
##                try: 
##                    self._arpoints[i-3] = Point()
##                except:
##                    self._arpoints = [0,]
##                self.list.append(self.arpoints[i-3])
##                self.list[i/3-1].x = other[i-3]
##                self.list[i/3-1].y = other[i-2]
##                self.list[i/3-1].z = other[i-1]

    def getFartherstPointInDirection(self, direction):
        print len(self.list)
        for i in range(len(self.list)):
            print i
            if self.list[i] * direction > self._highestPointInD:
                print str(self.list[i])
                self._highestPointInD = self.list[i] * direction
                self._wPoi = self.list[i]
        return self._wPoi

dann start ich des mal:
>>> pointlist = plist()
>>> pointlist
[]
>>> pointlist.np()
tja dann kommt der Fehler:
Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
pointlist.np()
File "C:\Users\Thomas\Desktop\Python\Projekte\kolissionsErkennung\classes.py", line 73, in np
self.list.append(p)
AttributeError: 'numpy.ndarray' object has no attribute 'append'
über die console funktioniert es jedoch:
>>> p1 = Point()
>>> pointlist.append(p1)
>>> pointlist
[<__main__.Point object at 0x036CA910>]
und mein zweites Problem:
auch das len() funktioniert nicht so wie gewollt:
>>> p2 = Point(1, -4, 5)
>>> pointlist.append(p2)
>>> d = Point(1,1,1)
>>> pointlist.getFartherstPointInDirection(d)
0
in der console funktioniert es aber....:
>>> len(pointlist)
2
kann mir bitte jemand helfen ?
Danke schon mal
:D
TheCryperLp
User
Beiträge: 6
Registriert: Freitag 23. August 2013, 12:13

snafu hat geschrieben:@TheCryperLp: Verstehe ich es richtig, dass du ein Numpy-Array als Liste benutzen willst und dich darüber wunderst, dass dieses Numpy-Array kein `.append()` unterstützt? :o
ja mit was fügt man des sonst hinzu ?
:D
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Ich weiß nicht, was dein Verständnis eines Arrays ist, aber Arrays haben für gewöhnlich eine feste Länge. Da kann man nichts anfügen. Du könntest höchstens ein Array mit einer bestimmten Größe und Dummywerten erstellen und diese Dummywerte dann später durch echte Werte ersetzen. Oder aber (und wesentlich sinnvoller), du nutzt für dein Vorhaben überhaupt kein Array, sondern einfach normale Python-Listen. Oder spricht da etwas gegen?
TheCryperLp
User
Beiträge: 6
Registriert: Freitag 23. August 2013, 12:13

snafu hat geschrieben:Ich weiß nicht, was dein Verständnis eines Arrays ist, aber Arrays haben für gewöhnlich eine feste Länge. Da kann man nichts anfügen. Du könntest höchstens ein Array mit einer bestimmten Größe und Dummywerten erstellen und diese Dummywerte dann später durch echte Werte ersetzen. Oder aber (und wesentlich sinnvoller), du nutzt für dein Vorhaben überhaupt kein Array, sondern einfach normale Python-Listen. Oder spricht da etwas gegen?
Ooops daran hatte ich nicht gedacht... aber wieso funktioniert des eig. In der console??
:D
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

In der Konsole bzw Python-Shell rufst du doch überhaupt kein `.np()` auf, sondern machst (zumindest in dem hier gezeigten Code) bloß ein `.append()`. Dies funktioniert deshalb, weil du von einer Python-Liste erbst und diese `.append()` kennt. Dein `.np()` fügt aber ja nicht der Python-Liste, sondern dem Numpy-Array etwas hinzu (bzw versucht es) und dies scheitert entsprechend.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Ich mache zunächst mal ein paar Anmerkungen zu deinem Code:

Zunächst solltet du dir die *-Importe abgewöhnen, die füllen dir nur den ganzen Namensraum. Häufig gibt es dabei Überschneidungen, so dass sich Namen überdecken und am Ende nicht sofort offensichtlich ist, woher welcher Namen kommt. Ein weiterer Nachteil ist, dass du im Code nicht sehen kannst, aus welchem Modul ein Name stammt. Man muss immer nachschauen.

``Point`` lässt sich viel einfacher mit numpy umsetzen als mit drei einzelnen Komponenten für x, y und z. ``numpy.matrix`` bietet sich dafür perfekt an. Zumindest sollten es aber keine einzelnen drei Variablen sein, sondern mindestens ein Tupel.

Das Ergebnis deiner add-Methode ist etwas unglücklich. Wenn man einen Punkt p und einen Punkt q addiert, dann erwartet man als Ergebnis einen Punkt. Bei dir Gibt es aber ein Tupel aus den drei Komponenten. Hier solltest du einen Punkt zurückliefern.

Auch solltest du dir die Methoden zur String-Formatierung anschauen, Strings mit + zusammensetzen ist nicht nur langsam, sondern vorallem auch sehr unübersichtlich.

Deine Fehlerbehandlung (in add) ist schlecht umgesetzt. Es ist eine ganze schlechte Idee eine Exception zu behandeln, dann eine Fehlermeldung mittels print zu schreiben und dann das Programm ganz normal weiterlaufen zu lassen. Dann wird es nämlich an einer andren Stelle krachen, da sich das Programm in einem inkonsistenten Zustand befindet. Wenn du einen Fehler nicht behandeln kannst, dann solltest du das auch nicht tun. Bei dir kommt dann noch hinzu, dass du als Fehlermeldung nur "TypeError" ausgibst. Du vernichtest also noch Information, welche bei der Fehlermeldung hilfreich sein könnte.

Und eine extrem schlechte Idee ist es, ein except zu verwenden, welches alle Exceptions abfängt. Das bedeutet nämlich tatsächlich, dass ALLE Ausnahmen abgefangen werden. Darunter fallen dann aber auch NameErrors, welche auf Programmierfehler hinweisen. Mit solch einer Ausnahmebehandlung machst du es extrem schwer Fehler zu finden.

Auch die Fehlermeldung ist unglücklich geschrieben. Wenn die Ausnahme auftritt ist nicht garantiert, dass überhaupt Elemente vom Typ Point verwendet werden (zumindest auf der rechten Seite des Operators). In deiner Fehlermeldung gehst du aber davon aus. Noch ungünstiger ist, dass du suggerierst, dass es die Typen Point1 und Point2 geben würde. Die Fehlermeldung lässt sich viel besser ausformulieren, wenn du die Repräsentation der Objekte verwendest:

Code: Alles auswählen

print "Can't subtract %r from %r" % (other, self)
Aber wie gesagt, hier solltest du gar keine Fehlerbehandlung machen, da du den Fehler offensichtlich nicht behandeln kannst.

Die Umsetzung von mul solltest du dir auch noch einmal überlegen. Hier gibt es durchaus mehrere Möglichkeiten: Skalarprodukt, Mutliplikation mit einem Skalar und komponentenweise Multiplikation.

Die str-Methode lässt sich viel einfacher umsetzen:

Code: Alles auswählen

return "(%f, %f, %f)" %(self.x, self.y, self.z)
Die neg-Methode ist auch wieder Problematisch. Zum einen existiert die spezielle Methode __neg__ bereits für solche Sachen, die solltest du daher auch verwenden. Weiter ist Problematisch, dass du das Objekt selbst veränderst. Hier möchtest du sicher lieber ein neues Point-Objekt zurückgeben. Weiter ist es total unnötig von 0 zu subtrahieren, das Minuszeichen kann auch einfach als unärer Operator verwendet werden:

Code: Alles auswählen

def __neg__(self):
    return Point(-self.x, -self.y, -self.z)
Die get-Methode hat auch wieder Schwachstellen. Wenn man auf Komponenten eines Objekts zugreifen will, dann ist __getitem__ eine gute Idee. Aber eigentlich ist get total überflüssig, da du hier nur auf x, y, und z zugreifst. In Python greift man von außen einfach darauf zu und schreibt sich nicht extra getter- und setter-Methoden. Der Grund ist ganz einfach: falls man so ein Verhalten doch mal braucht, dann verwendet man Properties. Weiter solltest du auf None nicht mit == testen, sondern mit ``is``.

``plist`` sollte besser ``PList`` oder noch besser ``Points`` oder ``PointList`` heißen. In Python sollten eigene Typen immer mit einem Großbuchstaben anfangen, schau dir mal PEP 8 an und probiere möglichst viel davon zu behalten.

Eine ganz schlechte Idee ist es von list zu erben, dies dann aber nicht zu verwenden. Wenn du von etwas erbst, dann bringt das auch jede Menge Konsequenzen mit sich und ist nicht nur ein Hinweis darauf, dass sich deine Klasse wie eine Liste verhält. Daher kommt auch dein Fehler. Einmal rufst du nämlich das append von plist auf (das ist der Funktionierende Aufruf) und einmal das append von self.list. Letzteres ist aber ein array, welches eine feste Länge hat. Das ist auch der Hauptunterschied zu Listen.

Auch ist ``list`` ein ganz schlechter Name. Zum einen verdeckt er den eingebauten Typen list zum anderen ist er total nichtssagend. Eine Name sollte immer beschreiben, was daran gebunden ist. list ist so generisch, da könnte jetzt wirklich alles drin stecken. Ähnlich nichtssagend sind wert oder wPoi.

Doppelte führende unterstriche dienen übrigens nur der Vermeidung von Namenskollisionen, einfache Unterstriche um einen Hinweise darauf zu geben, dass man ein Obejkt besser nicht anpackt, wenn man nicht genau weiß was man tut.

Über Listen kann man direkt iterieren, wenn man einen Index braucht, dann gibt es die enumerate-Funktion:

Code: Alles auswählen

for element in self.list:
    if element * direction > self._highest_point_in_d:
        ...
Das Leben ist wie ein Tennisball.
TheCryperLp
User
Beiträge: 6
Registriert: Freitag 23. August 2013, 12:13

EyDu hat geschrieben:Ich mache zunächst mal ein paar Anmerkungen zu deinem Code:

Zunächst solltet du dir die *-Importe abgewöhnen, die füllen dir nur den ganzen Namensraum. Häufig gibt es dabei Überschneidungen, so dass sich Namen überdecken und am Ende nicht sofort offensichtlich ist, woher welcher Namen kommt. Ein weiterer Nachteil ist, dass du im Code nicht sehen kannst, aus welchem Modul ein Name stammt. Man muss immer nachschauen.

``Point`` lässt sich viel einfacher mit numpy umsetzen als mit drei einzelnen Komponenten für x, y und z. ``numpy.matrix`` bietet sich dafür perfekt an. Zumindest sollten es aber keine einzelnen drei Variablen sein, sondern mindestens ein Tupel.

Das Ergebnis deiner add-Methode ist etwas unglücklich. Wenn man einen Punkt p und einen Punkt q addiert, dann erwartet man als Ergebnis einen Punkt. Bei dir Gibt es aber ein Tupel aus den drei Komponenten. Hier solltest du einen Punkt zurückliefern.

Auch solltest du dir die Methoden zur String-Formatierung anschauen, Strings mit + zusammensetzen ist nicht nur langsam, sondern vorallem auch sehr unübersichtlich.

Deine Fehlerbehandlung (in add) ist schlecht umgesetzt. Es ist eine ganze schlechte Idee eine Exception zu behandeln, dann eine Fehlermeldung mittels print zu schreiben und dann das Programm ganz normal weiterlaufen zu lassen. Dann wird es nämlich an einer andren Stelle krachen, da sich das Programm in einem inkonsistenten Zustand befindet. Wenn du einen Fehler nicht behandeln kannst, dann solltest du das auch nicht tun. Bei dir kommt dann noch hinzu, dass du als Fehlermeldung nur "TypeError" ausgibst. Du vernichtest also noch Information, welche bei der Fehlermeldung hilfreich sein könnte.

Und eine extrem schlechte Idee ist es, ein except zu verwenden, welches alle Exceptions abfängt. Das bedeutet nämlich tatsächlich, dass ALLE Ausnahmen abgefangen werden. Darunter fallen dann aber auch NameErrors, welche auf Programmierfehler hinweisen. Mit solch einer Ausnahmebehandlung machst du es extrem schwer Fehler zu finden.

Auch die Fehlermeldung ist unglücklich geschrieben. Wenn die Ausnahme auftritt ist nicht garantiert, dass überhaupt Elemente vom Typ Point verwendet werden (zumindest auf der rechten Seite des Operators). In deiner Fehlermeldung gehst du aber davon aus. Noch ungünstiger ist, dass du suggerierst, dass es die Typen Point1 und Point2 geben würde. Die Fehlermeldung lässt sich viel besser ausformulieren, wenn du die Repräsentation der Objekte verwendest:

Code: Alles auswählen

print "Can't subtract %r from %r" % (other, self)
Aber wie gesagt, hier solltest du gar keine Fehlerbehandlung machen, da du den Fehler offensichtlich nicht behandeln kannst.

Die Umsetzung von mul solltest du dir auch noch einmal überlegen. Hier gibt es durchaus mehrere Möglichkeiten: Skalarprodukt, Mutliplikation mit einem Skalar und komponentenweise Multiplikation.

Die str-Methode lässt sich viel einfacher umsetzen:

Code: Alles auswählen

return "(%f, %f, %f)" %(self.x, self.y, self.z)
Die neg-Methode ist auch wieder Problematisch. Zum einen existiert die spezielle Methode __neg__ bereits für solche Sachen, die solltest du daher auch verwenden. Weiter ist Problematisch, dass du das Objekt selbst veränderst. Hier möchtest du sicher lieber ein neues Point-Objekt zurückgeben. Weiter ist es total unnötig von 0 zu subtrahieren, das Minuszeichen kann auch einfach als unärer Operator verwendet werden:

Code: Alles auswählen

def __neg__(self):
    return Point(-self.x, -self.y, -self.z)
Die get-Methode hat auch wieder Schwachstellen. Wenn man auf Komponenten eines Objekts zugreifen will, dann ist __getitem__ eine gute Idee. Aber eigentlich ist get total überflüssig, da du hier nur auf x, y, und z zugreifst. In Python greift man von außen einfach darauf zu und schreibt sich nicht extra getter- und setter-Methoden. Der Grund ist ganz einfach: falls man so ein Verhalten doch mal braucht, dann verwendet man Properties. Weiter solltest du auf None nicht mit == testen, sondern mit ``is``.

``plist`` sollte besser ``PList`` oder noch besser ``Points`` oder ``PointList`` heißen. In Python sollten eigene Typen immer mit einem Großbuchstaben anfangen, schau dir mal PEP 8 an und probiere möglichst viel davon zu behalten.

Eine ganz schlechte Idee ist es von list zu erben, dies dann aber nicht zu verwenden. Wenn du von etwas erbst, dann bringt das auch jede Menge Konsequenzen mit sich und ist nicht nur ein Hinweis darauf, dass sich deine Klasse wie eine Liste verhält. Daher kommt auch dein Fehler. Einmal rufst du nämlich das append von plist auf (das ist der Funktionierende Aufruf) und einmal das append von self.list. Letzteres ist aber ein array, welches eine feste Länge hat. Das ist auch der Hauptunterschied zu Listen.

Auch ist ``list`` ein ganz schlechter Name. Zum einen verdeckt er den eingebauten Typen list zum anderen ist er total nichtssagend. Eine Name sollte immer beschreiben, was daran gebunden ist. list ist so generisch, da könnte jetzt wirklich alles drin stecken. Ähnlich nichtssagend sind wert oder wPoi.

Doppelte führende unterstriche dienen übrigens nur der Vermeidung von Namenskollisionen, einfache Unterstriche um einen Hinweise darauf zu geben, dass man ein Obejkt besser nicht anpackt, wenn man nicht genau weiß was man tut.

Über Listen kann man direkt iterieren, wenn man einen Index braucht, dann gibt es die enumerate-Funktion:

Code: Alles auswählen

for element in self.list:
    if element * direction > self._highest_point_in_d:
        ...
Ok danke aber wie kann ich des machen, dass wenn ich in die console p1 eingib dass er mir die x, y, z koordinaten zurückgibt und nicht wo des gespeichert ist??
:D
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

TheCryperLp hat geschrieben:wie kann ich des machen, dass wenn ich in die console p1 eingib dass er mir die x, y, z koordinaten zurückgibt und nicht wo des gespeichert ist??

Code: Alles auswählen

class Point(object):
    # [...]
    def __repr__(self):
        return 'Point(x={}, y={}, z={})'.format(self.x, self.y, self.z)
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

Um EyDus Liste zu vervollständigen:
Die Methode »getFartherstPointInDirection« enthält noch mehr Designfehler, nicht nur die Iteration über einen Index.
Du änderst Instanzattribute, und damit den Zustand in einer Methode, die »get« heißt und somit jedem Programmierer signalisiert, daß sie nebenwirkungsfrei ist. Das heißt, daß sie nur einmal aufgerufen werden kann und im schlimmsten Fall beim zweiten Mal falsche Werte liefert, ohne daß Du jemals den Fehler entdeckst. Deshalb müssen Funktionen, die Attribute ändern, immer eindeutig heißen (»set…«, »update…«, »add…«, usw.) und sollten keinen Rückgabewert haben. (Siehe z.B. »list.sort«).

Ansonsten, wenn Du schon numpy verwendest, dann nutze es auch:

Code: Alles auswählen

import numpy

def get_fartherst_point_in_direction(points, direction):
    distance = (points*direction).sum(1)
    max_distance_index = distance.argmax()
    return points[max_distance_index]

if __name__=='__main__':
    points = numpy.random.random((1000, 3))
    direction = [1, 0.5, -0.5]
    print get_fartherst_point_in_direction(points, direction)
Antworten