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

In [8]:
p1 = Point(1, 2, 3)

In [9]:
p1


Out[9]:
Point(1, 2, 3)

In [10]:
p2 = Point(1, 2, 3)

In [11]:
p1 == p2


Out[11]:
True

In [12]:
p2.x = 4

In [13]:
p1 == p2


Out[13]:
False

In [14]:
p2


Out[14]:
Point(4, 2, 3)

Unit Test


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-argument'], exit=False)


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

OK (expected failures=3)

Bonus1: Point objects to be added and subtracted from each other


In [17]:
class Point:
    """
    A class representing a 3-D point.
    """
    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z
        
    def __repr__(self):
        return "Point({}, {}, {})".format(self.x, self.y, self.z)
    
    def __eq__(self, other):
        return self.x == other.x and self.y == other.y and self.z == 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 [18]:
p1 = Point(1, 2, 3)

In [19]:
p2 = Point(4, 5, 6)

In [20]:
p1 + p2


Out[20]:
Point(5, 7, 9)

In [21]:
p3 = p2 - p1

In [22]:
p3


Out[22]:
Point(3, 3, 3)

Unit Test


In [23]:
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-argument'], exit=False)


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

OK (expected failures=2)

Bonus2: Point objects to be scaled up and down by numbers.


In [24]:
class Point:
    """
    A class representing a 3-D point.
    """
    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z
        
    def __repr__(self):
        return "Point({}, {}, {})".format(self.x, self.y, self.z)
    
    def __eq__(self, other):
        return self.x == other.x and self.y == other.y and self.z == 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
        )

In [25]:
p1 = Point(1, 2, 3)

In [26]:
p2 = p1 * 2

In [27]:
p2


Out[27]:
Point(2, 4, 6)

Unit Test


In [28]:
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-argument'], exit=False)


..xE..
======================================================================
ERROR: test_scale (__main__.PointTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "<ipython-input-28-d0ef50562dd3>", line 51, in test_scale
    p3 = 3 * p1
TypeError: unsupported operand type(s) for *: 'int' and 'Point'

----------------------------------------------------------------------
Ran 6 tests in 0.004s

FAILED (errors=1, expected failures=1)

Unit Test Case Failed: Do modification


In [2]:
class Point:
    """
    A class representing a 3-D point.
    """
    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z
        
    def __repr__(self):
        return "Point({}, {}, {})".format(self.x, self.y, self.z)
    
    def __eq__(self, other):
        return self.x == other.x and self.y == other.y and self.z == 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 Point(
            self.x * scalar,
            self.y * scalar,
            self.z * scalar
        )

In [30]:
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-argument'], exit=False)


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

OK (expected failures=1)

Bonus3: allow Point objects to be unpacked using multiple assignment like this ✔️:

>>> p1 = Point(1, 2, 3)

>>> x, y, z = p1

>>> (x, y, z)

(1, 2, 3)


In [3]:
p1 = Point(1, 2, 3)
x, y, z = p1
x, y, z


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-3-50b6cdc6d6a5> in <module>()
      1 p1 = Point(1, 2, 3)
----> 2 x, y, z = p1
      3 x, y, z

TypeError: 'Point' object is not iterable

In [6]:
class Point:
    """
    A class representing a 3-D point.
    """
    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z
        
    def __repr__(self):
        return "Point({}, {}, {})".format(self.x, self.y, self.z)
    
    def __eq__(self, other):
        return self.x == other.x and self.y == other.y and self.z == 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 Point(
            self.x * scalar,
            self.y * scalar,
            self.z * scalar
        )
        
    def __iter__(self):
        return iter((self.x, self.y, self.z))

In [7]:
p1 = Point(1, 2, 3)
x, y, z = p1
x, y, z


Out[7]:
(1, 2, 3)

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-argument'], exit=False)


......
----------------------------------------------------------------------
Ran 6 tests in 0.009s

OK

In [ ]: