Overrida __contains__ så att jag får True
Jag har skapat en subklass vid namnet Point och en superklass vid namnet Triangel. Klassen Point har tre attribut som är: punkt1, punkt2 och punkt 3. Triangeln har tre egna attribut som jag döpt till P1, P2 och P3 och utgörs av objekt skapade av typen Punkt.
p1 = Point(1, 1, 1)
p2 = Point(2, 2, 2)
p3 = Point(3, 3, 3)
triangles = [
Triangle(p1, p2, p3),
Triangle(p1, p3, p2),
Triangle(p2, p1, p3),
Triangle(p2, p3, p1)
]
# Try to find triangle in list
print(Triangle(p1, p2, p3) in triangles)
print(Triangle(p3, p1, p2) not in triangles)
Jag vill att följande skall ge mig True i båda fallen, men får enbart True på det sista fallet. Jag har sökt på google och sett att jag behöver overrida __contains__. Försökte med
def __contains__(self, other):
x = False
if self.Triangle in other.Triangle:
x = True
return x
till ingen nytta.
Någon som kan hjälpa mig?
Jag behöver nog se hela koden för att förstå.
from Point import Point
import math
# A class for a Triangle in 3D - should use Point class and Heron's formula
# NOTE: No IO here, this is just the logical concept.
# To test, run Ex2TestPointTriangle
class Triangle:
def __init__(self, P1: Point, P2: Point, P3: Point):
self.P1 = P1 #P1 är då en point med tre punkter
self.P2 = P2
self.P3 = P3
def area(self): #calculate distance between the three points
d1 = self.P1.distance(self.P2)
d2 = self.P2.distance(self.P3)
d3 = self.P3.distance(self.P1)
s = d1 + d2 + d3
s = s/2
a = math.sqrt(s *(s-d1) * (s-d2) * (s-d3))
return a
def __contains__(self, other):
x = False
if self.Triangle in other.Triangle:
x = True
return x
# package exercises.ex2usemoreclasses
import math
from multipledispatch import dispatch
# A class for points in 3D. Should be considered immutable, no mutating methods
# NOTE: No IO here, this is just the logical concept.
# To test, run Ex2TestPointTriangle
class Point:
def __init__(self, *args):
if len(args) == 3:
self.point1 = args[0]
self.point2 = args[1]
self.point3 = args[2]
elif len(args) == 1:
self.copy(args[0])
else:
raise ValueError("Wrong value.")
def distance(self, other):
point1_difference = self.point1 - other.point1
point2_difference = self.point2 - other.point2
point3_difference = self.point3 - other.point3
distance = math.sqrt(math.pow(point1_difference, 2) + math.pow(point2_difference, 2) + math.pow(point3_difference, 2))
return distance
def copy(self, other):
self.point1 = other.point1
self.point2 = other.point2
self.point3 = other.point3
# package exercises.ex2usemoreclasses
from Point import Point
from Triangle import Triangle
# This is a test of Classes (objects of) Point and Triangle
#
# See
# - usemoreclasses
def test_point_triangle():
# All should print true as usual
# Point
p = Point(1, 2, 3)
d = Point(1,2,3)
print(p.distance(d))
print(p.distance(Point(p)) == 0)
print(Point(0, 0, 0).distance(Point(1, 0, 0)) == 1)
# Triangle uses Points!
t = Triangle(Point(0, 0, 0), Point(0, 1, 0), Point(1, 0, 0))
print(abs(t.area() - 0.5) < 0.000001) # Area should be 0.5
# Test data
p1 = Point(1, 1, 1)
p2 = Point(2, 2, 2)
p3 = Point(3, 3, 3)
triangles = [
Triangle(p1, p2, p3),
Triangle(p1, p3, p2),
Triangle(p2, p1, p3),
Triangle(p2, p3, p1)
]
# Try to find triangle in list
print(Triangle(p1, p2, p3) in triangles)
print(Triangle(p3, p1, p2) not in triangles)
if __name__ == "__main__":
Den är lite lång, men det är tre olika klasser som du ser. Jag försökte skriva över __contains__ som du ser, för att anpassa den för detta scenario, men misslyckades. Koden beter sig annars som den bör på resten av grejerna
I print(Triangle(p1, p2, p3) in triangles) kontrollerar du om en nyskapad Triangle finns i listan triangles. Det är två fel: För det första så är triangeln nyskapad (Triangle(p1, p2, p3) är ett nytt objekt) och därmed kan det aldrig finnas i listan. För det andra så är triangles en Python-lista och den klassen implementerar en __contains__ som kontrollerar identiteten på objektet.
Ex
t1 = Triangle(p1,p2,p3)
triangles.append(t1)
t1 in triangles # är sant
Triangle(p1,p2,p3) in triangles # är falskt
Om du vill kontrollera om en triangel mellan tre punkter finns i listan triangles så kan du göra på två sätt
a) Ärv pythons list-objekt till en ny klass och ersätt (override) metoden __contains__. I den kontrollerar du om listan innehåller en triangel med de tre punkterna.
class MyList(list):
def __init__(self,arg):
super(list, self).__init__()
self.arg = arg
def __contains__(this, other):
# Loopa igeenom elementen i den här listan
for x in this:
# Kontrollera om elementen är lika (inte samma)
# Förutsätter att elementets klass (Triangle)
# implementerar __eq__
if x == other:
return True
return False
b) Skapa en egen klass som implementerar en lista och innehåller en __contains__ som gör samma sak som ovan.
Vilket du väljer är en smaksak.
Notera att när du kontrollerar om de tre punktera är de samma så måste du kontrollera innehållet i punkten, inte punktens identitet. Du kan alltså inte kontrollera enklass.p1 == enannanklass.p1 för den kontrollerar att p1 i de båda instanserna pekar på samma objekt och det vill du nog inte i allmänhet. Du kan uppnå det med att implementera metoden __eq__som kontrollerar innehållet i punkterna snarare än deras identitet..
ex:
def __eq__ (self, p):
return p.point1==self.point1 and p.point2==self.point2 and p.point3==self.point3
Det här borde leda dig vidare men återkom hit annars så får du mer hjälp