Using mypackage.vector
¶
Importing¶
First things first, if we try to import mypackage
from the examples folder, it will fail because Python cannot find it inside examples
.
import mypackage
--------------------------------------------------------------------------- ModuleNotFoundError Traceback (most recent call last) Cell In[1], line 1 ----> 1 import mypackage ModuleNotFoundError: No module named 'mypackage'
We need to tell Python to search in the parent folder. To do it we just add '..'
to the current path.
from sys import path
from os.path import abspath
# Tell python to search for the files and modules starting from the working directory
module_path = abspath("..")
if module_path not in path:
path.append(module_path)
Now it works:
from mypackage import Vector
# We could also import directly from the subpackage:
# from mypackage.vector import Vector
Note: If we don't want to be telling Python where to search for our library, we can install it (in editable mode) in our conda environment using
pip install -e .
Vector methods¶
Magic methods in Python are the special methods that start and end with the double underscores. They are also called dunder methods. Magic methods are not meant to be invoked directly by you, but the invocation happens internally from the class on a certain action. For example, when you add two numbers using the + operator, internally, the __add__()
method will be called.
Let's try some of the methods defined in our class.
Representation¶
The __repr__
method is called whenever we output an instance of our Vector class. For example:
vector = Vector(1, 2)
vector # same as repr(vector)
Vector(1, 2)
Print¶
Printing our vector calls the __str__
method inside the vector class, which outputs a string (have a look at the f-strings cheat sheet):
print(f"{vector = !s}")
vector = (1, 2)
where !s
means to print the result of vector in its string representation.
Addition¶
We can sum two vectors with the __add__
method
vector_1 = Vector(1, 2)
vector_2 = Vector(3, 4)
print(f"{vector_1 + vector_2 = !s}")
vector_1 + vector_2 = (4, 6)
Multiplication¶
We can multiply vectors with vectors with the __mul__
method
vector_1 = Vector(1, 2)
vector_2 = Vector(3, 4)
print(f"{vector_1 * vector_2 = }")
vector_1 * vector_2 = 11
and also a vector times a constant (in this order):
vector = Vector(1, 2)
constant = 3
print(f"{vector * constant = !s}")
vector * constant = (3, 6)
But if we multiply a constant times a vector, we get an error because we didn't define a __rmul__
method (reverse mutiplication).
constant * vector
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[9], line 1 ----> 1 constant * vector TypeError: unsupported operand type(s) for *: 'int' and 'Vector'
Equality¶
We can assert two vectors are equal using the ==
sign, which in the background calls the magic method __eq__
:
Vector(1, 1) == Vector(1, 1)
True
Vector(1, 1) == Vector(2, 1)
False
Norm of the vector¶
Even though norm
was defined as a method, since it doesn't take any inputs, we added the @property
decorator to treat it as an attribute. That means that we obtain the norm by typing vector.norm
instead of vector.norm()
.
Vector(1, 1).norm
1.4142135623730951
Projection¶
And finally we can take the projection of a vector. If no subspace is given, the projection is done along the first component. As you can see, a warning pops up for the forgetful
vector = Vector(1, 1)
vector_projection = vector.projection()
print(f"{vector_projection = !s}\n")
vector_projection = (1, 0)
/var/folders/fg/9xcyj6451md237pczr54fr6c0000gn/T/ipykernel_85478/1694763335.py:2: UserWarning: No subspace given: the vector is projected onto the first component! vector_projection = vector.projection()
On the other hand, if the optional argument subspace
is given, we project the vector along that subspace:
vector = Vector(1, 1)
vector.projection(Vector(1, 2))
Vector(0.5999999999999999, 1.1999999999999997)