HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Class Vector with Python 3

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
withclassvectorpython

Problem

Here is a class vector in python 3, for n-dimmensional vectors. Please suggest ways to improve the code as well as fix bugs and errors.

The only rule is not using: numpy, sympy, scipy and so on. Only math, cmath, Rational, Decimal, ... Python 3 default packages..

This code is only for learning to make classes with python 3. I want comments to improve my python learning. For example, a way to improve the __init()__ constructor, and so on.

```
# /usr/bin/env python3
# -- coding: utf-8 --
'''
Created on Wed May 7 21:21:21 2014

@author: tobal
'''

from math import sqrt, acos, degrees, radians, cos, sin, fsum, hypot, atan2

class Vector(tuple):

'''"Class to calculate the usual operations with vectors in bi and
tridimensional coordinates. Too with n-dimmensinal.'''
# __slots__=('V') #It's not possible because V is a variable list of param.
def __new__(cls, *V):
'''The new method, we initialize the coordinates of a vector.
You can initialize a vector for example: V = Vector() or
V = Vector(a,b) or V = Vector(v1, v2, ..., vn)'''
if not V:
V = (0, 0)
elif len(V) == 1:
raise ValueError('A vector must have at least 2 coordinates.')
return tuple.__new__(cls, V)

def __add__(self, V):
'''The operator sum overloaded. You can add vectors writing V + W,
where V and W are two vectors.'''
if len(self) != len(V):
raise IndexError('Vectors must have same dimmensions.')
else:
added = tuple(a + b for a, b in zip(self, V))
return Vector(*added)

__radd__ = __add__

def __sub__(self, V):
'''The operator subtraction overloaded. You can subtract vectors writing
V - W, where V and W are two vectors.'''
if len(self) != len(V):
raise IndexError('Vectors must have same dimmensions.')
else:
subtracted = tuple(a - b for a, b in zip(self, V))
return Vector

Solution

-
def __sub__(self, V):
    '''The operator subtraction overloaded. You can subtract points writing
    V - W, where V and W are two vectors.'''
    if len(self) != len(V):
        raise IndexError('Vectors must have same dimmensions.')
    else:
        subtracted = tuple(a - b for a, b in zip(self, V))
        return Vector(*subtracted)

__rsub__ = __sub__


This implementation of __rsub__ will create wrong results:

>>> import Vector
>>> v = Vector.Vector(1, 1)
>>> (0, 0) - v
(1, 1)


__rsub__ is called when no working __sub__ implementation is found for the left hand side of an operator. The arguments are then in reverse order with respect to the way __sub__ is called.

-
In general, when your operator implementation cannot deal with the type of the operand, return NotImplemented (not NotImplementedError). Python will then allow the __r*__ operator of the operand to be executed, allowing for more extensibility. For example, if you make a Matrix implementation at some point in the future, it might implement multiplication of vectors from the left by implementing __rmul__, if your __mul__ implementation returns NotImplemented when encountering an unknown type.

-
Your support of operands is in general not consistent, but I’m not sure whether that is relevant to your actual question – you might be aware of this. However, addition and subtraction can work with tuples as operands, while true division can only work with scalars.

-
Using type(1) seems not good to me. If using isinstance at all, you should use the types such as numbers.Number.

-
Your implementation of the __i*__ operators looks as if you accidentially took them for integer operators. Instead, they are supposed to be the implementations of += et al., working with the same operands as +, for example. Please refer to the python documentation on Special Method Names for details of the semantics expected.

-
I have not gone through any method below norm, because I know much of this not certain enough off the top of my head, I however have some more general remarks.

-
Refactor your exceptions out, to allow for reuse and consistent error messages. Example:

@staticmethod
    def _dimension_mismatch(d1, d2):
        raise IndexError(
            "Vectors must have same dimensionality (got {} and {})".format(
                d1, d2))


(alternatively, use a global function instead of @staticmethod)

-
There is no point in having constructs such as:

if a:
    raise Something()
else:
    do_something()


Throwing an exception will disrupt the control flow, so it doesn’t matter whether you have an else branch or just continue your code like this:

if a:
    raise Something()
do_something()


The latter improves readability by requiring less indentation depth.

Code Snippets

def __sub__(self, V):
    '''The operator subtraction overloaded. You can subtract points writing
    V - W, where V and W are two vectors.'''
    if len(self) != len(V):
        raise IndexError('Vectors must have same dimmensions.')
    else:
        subtracted = tuple(a - b for a, b in zip(self, V))
        return Vector(*subtracted)

__rsub__ = __sub__
>>> import Vector
>>> v = Vector.Vector(1, 1)
>>> (0, 0) - v
(1, 1)
@staticmethod
    def _dimension_mismatch(d1, d2):
        raise IndexError(
            "Vectors must have same dimensionality (got {} and {})".format(
                d1, d2))
if a:
    raise Something()
else:
    do_something()
if a:
    raise Something()
do_something()

Context

StackExchange Code Review Q#49454, answer score: 3

Revisions (0)

No revisions yet.