Objektorientiertes Programmieren Vektor

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
Sconine
User
Beiträge: 49
Registriert: Montag 1. Juni 2009, 11:00

Hallo zusammen,

gibt es wieder Verbesserungsvorschläge? :)

Code: Alles auswählen

class Vec3:

    """class for 3-dimensional vectors"""



    def __init__(self, x, y, z):

        """create object with given attributes"""

        self.x = x
        self.y = y
        self.z = z
    

    def __str__(self):

        """return nice representation for printing"""

        return str((self.x, self.y, self.z))

        

    def __eq__(self, other):

        """returns True if both vectors are identical"""

        if (self.x==other.x) & (self.y==other.y) & (self.z==other.z):
            return True
        else:
            return False

    

    def __ne__(self, other):

        """returns True if vectors are not identical"""

        return not self.__eq__(other)

        

    def __abs__(self):

        """returns the euclidian norm of the vector"""

        return (self.x**2 + self.y**2 + self.z**2)**.5

        

    def __add__(self,other):

        """add two Vec3 objects and return its results as a new Vec3"""

        x = self.x + other.x
        y = self.y + other.y
        z = self.z + other.z
        return Vec3(x,y,z)



    def __sub__(self,other):

        """subtract two Vec3 objects and return its results as a new Vec3"""

        x = self.x - other.x
        y = self.y - other.y
        z = self.z - other.z
        return Vec3(x,y,z)



    def __mul__(self, other):

        """multiply a Vec3 object with a scalar."""

        x = self.x * other
        y = self.y * other
        z = self.z * other
        return Vec3(x,y,z)

            

    def dot(self, other):

        """return dot product"""

        return self.x*other.x + self.y*other.y + self.z*other.z

                

   

def test():
    vec1=Vec3(1,2,3)
    vec2=Vec3(4,5,6)

    print vec1
    print abs(vec1)
    print vec1==vec1
    print vec1==vec2
    print vec1+vec2
    print vec1-vec2
    print vec1*2
    print vec1.dot(vec2)



if __name__=='__main__':
    test()
BlackJack

@Sconine: Beim Vergleich verwendest Du die bitweise AND-Verknüpfung (``&``) statt der logischen (``and``). Und wenn der Ausdruck bei dem ``if`` schon wahr oder falsch ist, kann man auch direkt *den* zurückgeben:

Code: Alles auswählen

        return self.x == other.x and self.y == other.y and self.z == other.z
Man könnte auch Tupel aus den Koordinaten machen und die dann vergleichen:

Code: Alles auswählen

        return (self.x, self.y, self.z) == (other.x, other.y, other.z)
In der `__init__()` würde ich den Argumenten eine 0 als Default-Wert geben.
Benutzeravatar
hendrikS
User
Beiträge: 420
Registriert: Mittwoch 24. Dezember 2008, 22:44
Wohnort: Leipzig

Eine Methode cross zum Berechnen des Kreuzproduktes sollte nicht fehlen.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Ich würde es so machen:

Code: Alles auswählen

import math

class Vec(object):
    def __init__(self, x, y, z):
        self.x, self.y, self.z = x, y, z
    
    @property
    def as_tuple(self):
        return self.x, self.y, self.z
        
    def __str__(self):
        return str(self.as_tuple)
    
    def __eq__(self, other):
        return self.as_tuple == other.as_tuple
    
    def __abs__(self):
        return math.sqrt(self.dot(self))
    
    def __neg__(self):
        return Vec(-self.x, -self.y, -self.z)

    def __add__(self, other):
        return Vec(self.x + other.x, self.y + other.y, self.z + other.z)
    
    def __sub__(self, other):
        return self + -other
    
    def __mul__(self, other):
        return Vec(self.x * other, self.y * other, self.z * other)
    
    def dot(self, other):
        return self.x * other.x + self.y * other.y + self.z * other.z
Bei den Kommentaren würde ich außerdem vollständige Sätze (Groß beginnend und mit . endend) benutzen. Auf den Fehler mit den `&` wurde schon hingewiesen. Was IMHO gar nicht geht, ist das explizite "return True/False". Das `__ne__` ist unnötig.

Stefan
BlackJack

@sma: Das `__ne__()` ist nicht unnötig:

Code: Alles auswählen

In [57]: class A(object):
   ....:     def __init__(self, a):
   ....:             self.a = a
   ....:     def __eq__(self, o):
   ....:             return self.a == o.a
   ....:

In [58]: a, b = A(5), A(5)

In [59]: a == b
Out[59]: True

In [60]: a != b
Out[60]: True
Edit: Oh, und wenn man diese Tests überschreibt, sollte man auch `__hash__()` überschreiben.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Das Ganze nun noch n-dimensional und ein schönes __repr__ dazu. :wink:
Sconine
User
Beiträge: 49
Registriert: Montag 1. Juni 2009, 11:00

Code: Alles auswählen

import math 

class Vec(object): 
    def __init__(self, x, y, z): 
        self.x, self.y, self.z = x, y, z 
    
    
    def as_tuple(self): 
        return self.x, self.y, self.z 
        
    def __str__(self): 
        return str(self.as_tuple) 
    
    def __eq__(self, other): 
        return self.as_tuple == other.as_tuple 
    
    def __abs__(self): 
        return math.sqrt(self.dot(self)) 
    
    def __neg__(self): 
        return Vec3(-self.x, -self.y, -self.z) 

    def __add__(self, other): 
        return Vec3(self.x + other.x, self.y + other.y, self.z + other.z) 
    
    def __sub__(self, other): 
        return self + -other 
    
    def __mul__(self, other): 
        return Vec3(self.x * other, self.y * other, self.z * other) 
    
    def dot(self, other): 
        return self.x * other.x + self.y * other.y + self.z * other.z

    def __ne__(self, other):
        return not self.__eq__(other)

def test():

    vec1 = Vec3(1,2,3)
    vec2 = Vec3(4,5,6)
    
    print vec1
    print abs(vec1)
    print vec1==vec1
    print vec1==vec2
    print vec1+vec2
    print vec1-vec2
    print vec1*2
    print vec1.dot(vec2)

    
if __name__=='__main__':
    test()
Warum kennt er Vec3 nicht? Das habe ich doch beim def test definiert.

Code: Alles auswählen

Traceback (most recent call last):
  File "C:\Python25\Eigene\VECTOR.py", line 54, in <module>
    test()
  File "C:\Python25\Eigene\VECTOR.py", line 40, in test
    vec1 = Vec3(1,2,3)
NameError: global name 'Vec3' is not defined
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Du hast die Klasse Vec definiert. Der Name Vec3 wird nicht definiert.
Sconine
User
Beiträge: 49
Registriert: Montag 1. Juni 2009, 11:00

Ups, das hab ich jetzt auch gesehen. Danke!!!
Sconine
User
Beiträge: 49
Registriert: Montag 1. Juni 2009, 11:00

Was bedeutet eigentlich das @property?
Als ich es weggelassen habe, ging gar nix und als ich es dazugeschrieben habe, lief das Programm einwandfrei.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Sconine hat geschrieben:Was bedeutet eigentlich das @property?
http://docs.python.org/library/functions.html#property
Das Leben ist wie ein Tennisball.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Der Grund für "ging gar nix" ist folgendes

Code: Alles auswählen

def __eq__(self, other):
    return self.as_tuple == other.as_tuple
Damit definierst du eine Methode als Datenattribut (jaaa eigentlich als `property`), d.h. diese Methode wird immer beim Aufruf des Attributs aufgerufen und enthält den Rückgabewert der Methode.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Im n-ten:

Code: Alles auswählen

import math
from operator import add, mul, neg

class VecN(object):
    def __init__(self, *args):
        self.values = map(float, args)

    @property
    def dimension(self):
        return len(self.values)

    def __str__(self):
        return str(self.values)

    def __eq__(self, other):
        return self.values == other.values

    def __ne__(self, other):
        return not self.__eq__(other)

    def __abs__(self):
        return math.sqrt(self.dot(self))

    def __neg__(self):
        return VecN(*map(neg, self.values))

    def __add__(self, other):
        if self.dimension == other.dimension:
            return VecN(*map(add, self.values, other.values))
        else:
            raise ValueError("vectors have different dimensions")

    def __sub__(self, other):
        return self + -other

    def __mul__(self, other):
        return VecN(*(i*other for i in self.values))

    def __div__(self, other):
        return self.__mul__(1/float(other))

    def dot(self, other):
        if self.dimension == other.dimension:
            return sum(map(mul, self.values, other.values))
        else:
            raise ValueError("vectors have different dimensions")

    def __repr__(self):
        return "<VecN: %d %s>" % (self.dimension, self.values)

    def __hash__(self):
        return hash(str(self.values))
Wäre sicher besser, die Klasse gleich von list abzuleiten. Viel Spaß beim Kreuzprodukt ;)
Antworten