Seite 1 von 1

Objektorientiertes Programmieren Vektor

Verfasst: Sonntag 21. Juni 2009, 15:25
von Sconine
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()

Verfasst: Sonntag 21. Juni 2009, 15:40
von 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.

Verfasst: Sonntag 21. Juni 2009, 15:45
von hendrikS
Eine Methode cross zum Berechnen des Kreuzproduktes sollte nicht fehlen.

Verfasst: Sonntag 21. Juni 2009, 15:49
von sma
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

Verfasst: Sonntag 21. Juni 2009, 16:03
von 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.

Verfasst: Sonntag 21. Juni 2009, 16:46
von jerch
Das Ganze nun noch n-dimensional und ein schönes __repr__ dazu. :wink:

Verfasst: Sonntag 21. Juni 2009, 17:36
von Sconine

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

Verfasst: Sonntag 21. Juni 2009, 17:39
von derdon
Du hast die Klasse Vec definiert. Der Name Vec3 wird nicht definiert.

Verfasst: Sonntag 21. Juni 2009, 17:41
von Sconine
Ups, das hab ich jetzt auch gesehen. Danke!!!

Verfasst: Sonntag 21. Juni 2009, 17:45
von Sconine
Was bedeutet eigentlich das @property?
Als ich es weggelassen habe, ging gar nix und als ich es dazugeschrieben habe, lief das Programm einwandfrei.

Verfasst: Sonntag 21. Juni 2009, 17:55
von EyDu
Sconine hat geschrieben:Was bedeutet eigentlich das @property?
http://docs.python.org/library/functions.html#property

Verfasst: Sonntag 21. Juni 2009, 17:55
von cofi
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.

Verfasst: Sonntag 21. Juni 2009, 20:01
von jerch
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 ;)