``````

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)

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)

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)

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)

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 [ ]:

``````