Point
from collections import namedtuple
import math
BasePoint = namedtuple('BasePoint', 'x y z')
class Point(BasePoint):
"""Three-dimensional point."""
def distance(self, other):
"""Calculate the distance between two points."""
a1 = self[0]
b1 = self[1]
c1 = self[2]
a2 = other[0]
b2 = other[1]
c2 = other[2]
return math.sqrt((a1-a2)**2+(b1-b2)**2+(c1-c2)**2)
def shift(self, other):
"""Return new copy of our point, shifted by other."""
a = self[0] + other[0]
b = self[1] + other[1]
c = self[2] + other[2]
new_point = Point(a, b, c)
return new_point
def scale(self, value):
"""Scale Point by the given numeric value."""
new_point = Point(self[0] * value, self[1] * value, self[2] * value)
return new_point
if __name__ == "__main__":
p1 = Point(1, 2, 3)
p2 = Point(4, 5, 6)
assert p2.shift(p1) == p1.shift(p2) == Point(5, 7, 9)
assert p1.scale(2) == Point(2, 4, 6)
assert p1.distance(p2) == p2.distance(p1) == 5.196152422706632
print("Tests passed.")
Use tuple unpacking to shorten code in
distanceandshift: “Readability counts.” and “Complex is better than complicated.”Split logic-heavy
distancereturn line into two lines (using unpacking again): “Readability counts.”Remove unnecessary variables that are immediately returned: “Simple is better than complex.” and “Beautiful is better than ugly.”
Use ability of
namedtupleto reference named attributes to refactorscalefunction: “Explicit is better than implicit.”Rewrite
scaleline, swapping order of arithmetic to be more readable: “Readability counts.”Change
shiftandscaleinto more Pythonic+and*operators: “Complex is better than complicated.”
class Point(BasePoint):
"""Three-dimensional point."""
def distance(self, other):
"""Calculate the distance between two points."""
a1, b1, c1 = self
a2, b2, c2 = other
x, y, z = (a1 - a2), (b1 - b2), (c1 - c2)
return math.sqrt(x**2 + y**2 + z**2)
def __add__(self, other):
"""Return new copy of our point, shifted by other."""
a1, b1, c1 = self
a2, b2, c2 = other
return Point((a1+a2), (b1+b2), (c1+c2))
def __mul__(self, scalar):
"""Scale Point by the given numeric value."""
return Point(scalar*self.x, scalar*self.y, scalar*self.z)
def __rmul__(self, value):
"""Scale Point by the given numeric value."""
return self.__mul__(value)
Our new tests:
if __name__ == "__main__":
p1 = Point(1, 2, 3)
p2 = Point(4, 5, 6)
assert p2 + p1 == p1 + p2 == Point(5, 7, 9)
assert p1 * 2 == 2 * p1 == Point(2, 4, 6)
assert p1.distance(p2) == p2.distance(p1) == 5.196152422706632
print("Tests passed.")