In [3]:
class Point:
    """
    3-D Point
    """
    def __init__(self, x, y, z):
        self.x, self.y, self.z = x, y, z
        
    def __repr__(self):
        return "Point({}, {}, {})".format(self.x, self.y, self.z)
    
    def __eq__(self, other):
        return (self.x, self.y, self.z) == (other.x, other.y, other.z)

Unit Test


In [4]:
import unittest

class PointTests(unittest.TestCase):

    """Tests for Point."""

    def test_attributes(self):
        point = Point(1, 2, 3)
        self.assertEqual((point.x, point.y, point.z), (1, 2, 3))
        point.x = 4
        self.assertEqual(point.x, 4)

    def test_string_representation(self):
        point = Point(1, 2, 3)
        self.assertEqual(str(point), 'Point(1, 2, 3)')
        self.assertEqual(repr(point), 'Point(1, 2, 3)')
        point.y = 4
        self.assertEqual(str(point), 'Point(1, 4, 3)')
        self.assertEqual(repr(point), 'Point(1, 4, 3)')

    def test_equality_and_inequality(self):
        p1 = Point(1, 2, 3)
        p2 = Point(1, 2, 4)
        p3 = Point(1, 2, 3)
        self.assertNotEqual(Point(1, 2, 3), Point(1, 2, 4))
        self.assertEqual(Point(1, 2, 3), Point(1, 2, 3))
        self.assertFalse(Point(1, 2, 3) != Point(1, 2, 3))
        self.assertNotEqual(p1, p2)
        self.assertEqual(p1, p3)
        p3.x, p3.z = p3.z, p3.x
        self.assertNotEqual(p1, p3)
        self.assertTrue(p1 != p3)
        self.assertFalse(p1 == p3)

    # To test the Bonus part of this exercise, comment out the following line
    @unittest.expectedFailure
    def test_shifting(self):
        p1 = Point(1, 2, 3)
        p2 = Point(4, 5, 6)
        p3 = p2 + p1
        p4 = p3 - p1
        self.assertEqual((p3.x, p3.y, p3.z), (5, 7, 9))
        self.assertEqual((p4.x, p4.y, p4.z), (p2.x, p2.y, p2.z))

    # To test the Bonus part of this exercise, comment out the following line
    @unittest.expectedFailure
    def test_scale(self):
        p1 = Point(1, 2, 3)
        p2 = p1 * 2
        self.assertEqual((p2.x, p2.y, p2.z), (2, 4, 6))
        p3 = 3 * p1
        self.assertEqual((p3.x, p3.y, p3.z), (3, 6, 9))

    # To test the Bonus part of this exercise, comment out the following line
    @unittest.expectedFailure
    def test_iterable_point(self):
        point = Point(x=1, y=2, z=3)
        x, y, z = point
        self.assertEqual((x, y, z), (1, 2, 3))


if __name__ == "__main__":
    unittest.main(argv=['ignore-first-arg'], exit=False)


..xxx.
----------------------------------------------------------------------
Ran 6 tests in 0.004s

OK (expected failures=3)

Bonus1: allow point objects to added to and subtracted from each other.


In [5]:
class Point:
    """
    3-D Point
    """
    def __init__(self, x, y, z):
        self.x, self.y, self.z = x, y, z
        
    def __repr__(self):
        return "Point({}, {}, {})".format(self.x, self.y, self.z)
    
    def __eq__(self, other):
        return (self.x, self.y, self.z) == (other.x, other.y, other.z)
    
    def __add__(self, other):
        return Point(
            self.x + other.x,
            self.y + other.y,
            self.z + other.z
        )
    
    def __sub__(self, other):
        return Point(
            self.x - other.x,
            self.y - other.y,
            self.z - other.z
        )

In [6]:
import unittest

class PointTests(unittest.TestCase):

    """Tests for Point."""

    def test_attributes(self):
        point = Point(1, 2, 3)
        self.assertEqual((point.x, point.y, point.z), (1, 2, 3))
        point.x = 4
        self.assertEqual(point.x, 4)

    def test_string_representation(self):
        point = Point(1, 2, 3)
        self.assertEqual(str(point), 'Point(1, 2, 3)')
        self.assertEqual(repr(point), 'Point(1, 2, 3)')
        point.y = 4
        self.assertEqual(str(point), 'Point(1, 4, 3)')
        self.assertEqual(repr(point), 'Point(1, 4, 3)')

    def test_equality_and_inequality(self):
        p1 = Point(1, 2, 3)
        p2 = Point(1, 2, 4)
        p3 = Point(1, 2, 3)
        self.assertNotEqual(Point(1, 2, 3), Point(1, 2, 4))
        self.assertEqual(Point(1, 2, 3), Point(1, 2, 3))
        self.assertFalse(Point(1, 2, 3) != Point(1, 2, 3))
        self.assertNotEqual(p1, p2)
        self.assertEqual(p1, p3)
        p3.x, p3.z = p3.z, p3.x
        self.assertNotEqual(p1, p3)
        self.assertTrue(p1 != p3)
        self.assertFalse(p1 == p3)

    # To test the Bonus part of this exercise, comment out the following line
    # @unittest.expectedFailure
    def test_shifting(self):
        p1 = Point(1, 2, 3)
        p2 = Point(4, 5, 6)
        p3 = p2 + p1
        p4 = p3 - p1
        self.assertEqual((p3.x, p3.y, p3.z), (5, 7, 9))
        self.assertEqual((p4.x, p4.y, p4.z), (p2.x, p2.y, p2.z))

    # To test the Bonus part of this exercise, comment out the following line
    @unittest.expectedFailure
    def test_scale(self):
        p1 = Point(1, 2, 3)
        p2 = p1 * 2
        self.assertEqual((p2.x, p2.y, p2.z), (2, 4, 6))
        p3 = 3 * p1
        self.assertEqual((p3.x, p3.y, p3.z), (3, 6, 9))

    # To test the Bonus part of this exercise, comment out the following line
    @unittest.expectedFailure
    def test_iterable_point(self):
        point = Point(x=1, y=2, z=3)
        x, y, z = point
        self.assertEqual((x, y, z), (1, 2, 3))


if __name__ == "__main__":
    unittest.main(argv=['ignore-first-arg'], exit=False)


..xx..
----------------------------------------------------------------------
Ran 6 tests in 0.007s

OK (expected failures=2)

Bonus2: Allow point objects to work with scalar multiplication


In [7]:
class Point:
    """
    3-D Point
    """
    def __init__(self, x, y, z):
        self.x, self.y, self.z = x, y, z
        
    def __repr__(self):
        return "Point({}, {}, {})".format(self.x, self.y, self.z)
    
    def __eq__(self, other):
        return (self.x, self.y, self.z) == (other.x, other.y, other.z)
    
    def __add__(self, other):
        return Point(
            self.x + other.x,
            self.y + other.y,
            self.z + other.z
        )
    
    def __sub__(self, other):
        return Point(
            self.x - other.x,
            self.y - other.y,
            self.z - other.z
        )
    
    def __mul__(self, scalar):
        return Point(
            self.x * scalar,
            self.y * scalar, 
            self.z * scalar
        )
    
    def __rmul__(self, scalar):
        return self.__mul__(scalar)

Unit Test


In [8]:
import unittest

class PointTests(unittest.TestCase):

    """Tests for Point."""

    def test_attributes(self):
        point = Point(1, 2, 3)
        self.assertEqual((point.x, point.y, point.z), (1, 2, 3))
        point.x = 4
        self.assertEqual(point.x, 4)

    def test_string_representation(self):
        point = Point(1, 2, 3)
        self.assertEqual(str(point), 'Point(1, 2, 3)')
        self.assertEqual(repr(point), 'Point(1, 2, 3)')
        point.y = 4
        self.assertEqual(str(point), 'Point(1, 4, 3)')
        self.assertEqual(repr(point), 'Point(1, 4, 3)')

    def test_equality_and_inequality(self):
        p1 = Point(1, 2, 3)
        p2 = Point(1, 2, 4)
        p3 = Point(1, 2, 3)
        self.assertNotEqual(Point(1, 2, 3), Point(1, 2, 4))
        self.assertEqual(Point(1, 2, 3), Point(1, 2, 3))
        self.assertFalse(Point(1, 2, 3) != Point(1, 2, 3))
        self.assertNotEqual(p1, p2)
        self.assertEqual(p1, p3)
        p3.x, p3.z = p3.z, p3.x
        self.assertNotEqual(p1, p3)
        self.assertTrue(p1 != p3)
        self.assertFalse(p1 == p3)

    # To test the Bonus part of this exercise, comment out the following line
    # @unittest.expectedFailure
    def test_shifting(self):
        p1 = Point(1, 2, 3)
        p2 = Point(4, 5, 6)
        p3 = p2 + p1
        p4 = p3 - p1
        self.assertEqual((p3.x, p3.y, p3.z), (5, 7, 9))
        self.assertEqual((p4.x, p4.y, p4.z), (p2.x, p2.y, p2.z))

    # To test the Bonus part of this exercise, comment out the following line
    # @unittest.expectedFailure
    def test_scale(self):
        p1 = Point(1, 2, 3)
        p2 = p1 * 2
        self.assertEqual((p2.x, p2.y, p2.z), (2, 4, 6))
        p3 = 3 * p1
        self.assertEqual((p3.x, p3.y, p3.z), (3, 6, 9))

    # To test the Bonus part of this exercise, comment out the following line
    @unittest.expectedFailure
    def test_iterable_point(self):
        point = Point(x=1, y=2, z=3)
        x, y, z = point
        self.assertEqual((x, y, z), (1, 2, 3))


if __name__ == "__main__":
    unittest.main(argv=['ignore-first-arg'], exit=False)


..x...
----------------------------------------------------------------------
Ran 6 tests in 0.006s

OK (expected failures=1)

Bonus3: Allow points to work with multiple assignment (tuple unpacking).


In [3]:
class Point:
    """
    3-D Point
    """
    def __init__(self, x, y, z):
        self.x, self.y, self.z = x, y, z
        
    def __repr__(self):
        return "Point({}, {}, {})".format(self.x, self.y, self.z)
    
    def __eq__(self, other):
        return (self.x, self.y, self.z) == (other.x, other.y, other.z)
    
    def __add__(self, other):
        return Point(
            self.x + other.x,
            self.y + other.y,
            self.z + other.z
        )
    
    def __sub__(self, other):
        return Point(
            self.x - other.x,
            self.y - other.y,
            self.z - other.z
        )
    
    def __mul__(self, scalar):
        return Point(
            self.x * scalar,
            self.y * scalar, 
            self.z * scalar
        )
    
    def __rmul__(self, scalar):
        return self.__mul__(scalar)
    
    def __iter__(self):
#         yield self.x
#         yield self.y
#         yield self.z
        
        yield from (self.x, self.y, self.z)

Unit Test


In [4]:
import unittest

class PointTests(unittest.TestCase):

    """Tests for Point."""

    def test_attributes(self):
        point = Point(1, 2, 3)
        self.assertEqual((point.x, point.y, point.z), (1, 2, 3))
        point.x = 4
        self.assertEqual(point.x, 4)

    def test_string_representation(self):
        point = Point(1, 2, 3)
        self.assertEqual(str(point), 'Point(1, 2, 3)')
        self.assertEqual(repr(point), 'Point(1, 2, 3)')
        point.y = 4
        self.assertEqual(str(point), 'Point(1, 4, 3)')
        self.assertEqual(repr(point), 'Point(1, 4, 3)')

    def test_equality_and_inequality(self):
        p1 = Point(1, 2, 3)
        p2 = Point(1, 2, 4)
        p3 = Point(1, 2, 3)
        self.assertNotEqual(Point(1, 2, 3), Point(1, 2, 4))
        self.assertEqual(Point(1, 2, 3), Point(1, 2, 3))
        self.assertFalse(Point(1, 2, 3) != Point(1, 2, 3))
        self.assertNotEqual(p1, p2)
        self.assertEqual(p1, p3)
        p3.x, p3.z = p3.z, p3.x
        self.assertNotEqual(p1, p3)
        self.assertTrue(p1 != p3)
        self.assertFalse(p1 == p3)

    # To test the Bonus part of this exercise, comment out the following line
    # @unittest.expectedFailure
    def test_shifting(self):
        p1 = Point(1, 2, 3)
        p2 = Point(4, 5, 6)
        p3 = p2 + p1
        p4 = p3 - p1
        self.assertEqual((p3.x, p3.y, p3.z), (5, 7, 9))
        self.assertEqual((p4.x, p4.y, p4.z), (p2.x, p2.y, p2.z))

    # To test the Bonus part of this exercise, comment out the following line
    # @unittest.expectedFailure
    def test_scale(self):
        p1 = Point(1, 2, 3)
        p2 = p1 * 2
        self.assertEqual((p2.x, p2.y, p2.z), (2, 4, 6))
        p3 = 3 * p1
        self.assertEqual((p3.x, p3.y, p3.z), (3, 6, 9))

    # To test the Bonus part of this exercise, comment out the following line
    # @unittest.expectedFailure
    def test_iterable_point(self):
        point = Point(x=1, y=2, z=3)
        x, y, z = point
        self.assertEqual((x, y, z), (1, 2, 3))


if __name__ == "__main__":
    unittest.main(argv=['ignore-first-arg'], exit=False)


......
----------------------------------------------------------------------
Ran 6 tests in 0.003s

OK

Refactorting the Point class methods, now that the instances of Point class are iterable


In [15]:
class Point:
    """
    3-D Point
    """
    def __init__(self, x, y, z):
        self.x, self.y, self.z = x, y, z
        
    def __repr__(self):
        return "Point({}, {}, {})".format(self.x, self.y, self.z)

    
    def __eq__(self, other):
        x1, y1, z1 = self
        x2, y2, z2 = other
        
        return (x1, y1, z1) == (x2, y2, z2)
#         return (self.x, self.y, self.z) == (other.x, other.y, other.z)

    
    def __add__(self, other):
        x1, y1, z1 = self
        x2, y2, z2 = other
        
        return Point(
            x1 + x2,
            y1 + y2,
            z1 + z2
        )
    
    def __sub__(self, other):
        x1, y1, z1 = self
        x2, y2, z2 = other
        
        return Point(
            x1 - x2,
            y1 - y2,
            z1 - z2
        )
    
    def __mul__(self, scalar):
        x, y, z = self
        
        return Point(
            x * scalar,
            y * scalar,
            z * scalar
        )
    
    def __rmul__(self, scalar):
        return self.__mul__(scalar)
    
    def __iter__(self):
#         yield self.x
#         yield self.y
#         yield self.z
        
        yield from (self.x, self.y, self.z)

In [16]:
import unittest

class PointTests(unittest.TestCase):

    """Tests for Point."""

    def test_attributes(self):
        point = Point(1, 2, 3)
        self.assertEqual((point.x, point.y, point.z), (1, 2, 3))
        point.x = 4
        self.assertEqual(point.x, 4)

    def test_string_representation(self):
        point = Point(1, 2, 3)
        self.assertEqual(str(point), 'Point(1, 2, 3)')
        self.assertEqual(repr(point), 'Point(1, 2, 3)')
        point.y = 4
        self.assertEqual(str(point), 'Point(1, 4, 3)')
        self.assertEqual(repr(point), 'Point(1, 4, 3)')

    def test_equality_and_inequality(self):
        p1 = Point(1, 2, 3)
        p2 = Point(1, 2, 4)
        p3 = Point(1, 2, 3)
        self.assertNotEqual(Point(1, 2, 3), Point(1, 2, 4))
        self.assertEqual(Point(1, 2, 3), Point(1, 2, 3))
        self.assertFalse(Point(1, 2, 3) != Point(1, 2, 3))
        self.assertNotEqual(p1, p2)
        self.assertEqual(p1, p3)
        p3.x, p3.z = p3.z, p3.x
        self.assertNotEqual(p1, p3)
        self.assertTrue(p1 != p3)
        self.assertFalse(p1 == p3)

    # To test the Bonus part of this exercise, comment out the following line
    # @unittest.expectedFailure
    def test_shifting(self):
        p1 = Point(1, 2, 3)
        p2 = Point(4, 5, 6)
        p3 = p2 + p1
        p4 = p3 - p1
        self.assertEqual((p3.x, p3.y, p3.z), (5, 7, 9))
        self.assertEqual((p4.x, p4.y, p4.z), (p2.x, p2.y, p2.z))

    # To test the Bonus part of this exercise, comment out the following line
    # @unittest.expectedFailure
    def test_scale(self):
        p1 = Point(1, 2, 3)
        p2 = p1 * 2
        self.assertEqual((p2.x, p2.y, p2.z), (2, 4, 6))
        p3 = 3 * p1
        self.assertEqual((p3.x, p3.y, p3.z), (3, 6, 9))

    # To test the Bonus part of this exercise, comment out the following line
    # @unittest.expectedFailure
    def test_iterable_point(self):
        point = Point(x=1, y=2, z=3)
        x, y, z = point
        self.assertEqual((x, y, z), (1, 2, 3))


if __name__ == "__main__":
    unittest.main(argv=['ignore-first-arg'], exit=False)


......
----------------------------------------------------------------------
Ran 6 tests in 0.002s

OK

In [ ]: