<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Example of performing Vector mathmatical function using Python List structures
Vector methods to be created
Step1:  Other vector operations that could be done
Step2:  List Comprehensions are Powerful tools in Python
Expect to see them throughout code one has to maintain but also understand they are not always the optimal solution
When an iteration is needed to build a composite value, list comprehensions are considered the most readable or understandable way to achieve this. Loops may be used instead if one wants the "side effect" of an interation while functional tools may be used if optimization and code speed is important.
For instance, the above examples could also have been performed with an annoymous lambda or reduce, like
<ASSISTANT_TASK:>
Python Code:
class vector_math:
    '''
    This is the base class for vector math - which allows for initialization with two vectors.
    '''
    
    def __init__(self, vectors = [[1,2,2],[3,4,3]]):
        self.vect1 = vectors[0]
        self.vect2 = vectors[1]
        
    def set_vects(self, vectors):
        self.vect1 = vectors[0]
        self.vect2 = vectors[1]
    
    def sum_vects(self):
        return [x + y for x, y in zip(self.vect1, self.vect2)]
    
    def sub_vects(self):
        # default should be [-2,-2,-1]
        return [x - y for x, y in zip(self.vect1, self.vect2)]
        # Can expand out to for x, y in zip: ... to show what it and sum do
    
    def multi_vects(self):
        #default should be [3,8,6]
        return [x * y for x, y in zip(self.vect1, self.vect2)]
    
    def multi_scalar(self, scalar, vect):
        return [e * scalar for e in vect]
        # Show difference between just element * number and using tuple from zip()
        
    def multi_scalar_l(self, scalar, vect):
        return lambda e: e * scalar, vect
        
    def mean_vects(self):
        mean_vect = self.sum_vects()
        return self.multi_scalar(1/len(mean_vect), mean_vect)
        
    def dot_product(self):
        return sum(self.multi_vects())
    
vect = vector_math()
sum_vect = vect.sum_vects()
print("Sum of vectors = {}".format(sum_vect))
print("Subtraction of vectors = {}".format(vect.sub_vects()))
print("Product of vectors = {}".format(vect.multi_vects()))
print("Product of Sum of vectors and 2 = {}\n".format(vect.multi_scalar(2, sum_vect)))
# Yep can still use character returns and others in format
print("Average of vectors = {}".format(["{:.2f}".format(e) for e in vect.mean_vects()]))
# Now there are other ways to reduce the decimal places but this was just to show a nested format call
# TODO: Consider adding timeit to show difference between calling multi_scalar directly and calling mean_vect:
#print("Average of vectors through calling scalar = {}".format(
#        ["{:.2f}".format(e) for e in vect.multi_scalar(1/len(sum_vect), sum_vect)]))
print("The Dot Product is {}".format(vect.dot_product()))
Explanation: Example of performing Vector mathmatical function using Python List structures
Vector methods to be created:
* Sum vectors
  * Add vector elements of same sized vectors
  * Return resulting vector
* Subtract vectors
  * Subtract vector elements of same sized vectors
  * Return resulting vector
* Product of vectors
  * Product of components of vectors
  * Return resulting vector
* Product of vector and scalar
  * Return scalar product of each element of vector
* Mean of vectors
  * Sum Vector method / number of elements for each element (or 1/len scalar multiply)
* Dot Product
  * Sum of component wise products
  * Multiply vectors
  * Sum vectors
  * Return resulting vector
Teaching notes delete when finished
Remember to explain that in the real world numpy and other libraries would be used to do this
For teaching list methods
Particuliarly allows for a number of list comprehensions to be explained
Basic Class definition and issues
Start with just calling a definition directly (which will Error with a not found)
Show how adding self.function_name() works and explain
Move into using decorators
Start with a vector with a small number of elements
So students can do calculations in their heads and follow along
End of explanation
from math import sqrt
# Using the vect variables showing without functions
sum_of_squares = sum([x * y for x, y in zip(vect.vect1, vect.vect1)])
magnitude = sqrt(sum_of_squares)
distance = sqrt(sum([(x - y) ** 2 for x, y in zip(vect.vect1, vect.vect2)]))
print("Sum of Squares is {}".format(sum_of_squares))
print("Magnitude is {:.2f}".format(magnitude))
print("Distance is {}".format(distance))
Explanation: Other vector operations that could be done
End of explanation
import dis
import time
# For instruction - shows disassemble of methods and performs quick time check
vect = [2,3,3,3,4,5,6,6,4,3,2,1,3,4,5,6,4,3,2,1,3,4,5,6,4,3,2]
t1 = time.time()
print("list comp")
dis.dis(compile("[e * 2 for e in vect]", '<stdin>', 'exec'))
d_l = time.time() - t1
print(d_l)
t2 = time.time()
print("\n\n\nlambda")
dis.dis(compile("lambda e: e * 2, vect", '<stdin>', 'exec'))
d_lam = time.time() - t2
print(d_lam)
Explanation: List Comprehensions are Powerful tools in Python
Expect to see them throughout code one has to maintain but also understand they are not always the optimal solution
When an iteration is needed to build a composite value, list comprehensions are considered the most readable or understandable way to achieve this. Loops may be used instead if one wants the "side effect" of an interation while functional tools may be used if optimization and code speed is important.
For instance, the above examples could also have been performed with an annoymous lambda or reduce, like:
def multi_scalar(self, vect, scalar):
    return lambda e: e * scalar, vect
In this case, the lambda would be faster by a minimal amount and actually have one less function call - which are expensive in Python. This is not always true as the need for an increasing amount of functional methods can change both the speed and amount of function call required. code example is below
End of explanation
<END_TASK>