TypeError:' Vector'对象不可迭代

时间:2017-05-12 14:07:29

标签: python vector typeerror

我试图计算两条线的交点,但经常得到" TypeError:' Vector'对象不可迭代" 我试图寻找答案但失败了。我该如何解决这个问题,请问?

这里是代码:

from decimal import Decimal, getcontext

from vector import Vector

getcontext().prec = 30


class Line(object):

    NO_NONZERO_ELTS_FOUND_MSG = 'No nonzero elements found'

    def __init__(self, normal_vector=None, constant_term=None):
        self.dimension = 2

        if not normal_vector:
            all_zeros = ['0']*self.dimension
            normal_vector = Vector(all_zeros)
        self.normal_vector = normal_vector

        if not constant_term:
            constant_term = Decimal('0')
        self.constant_term = Decimal(constant_term)

        self.set_basepoint()

    def __eq__(self, ell):
        if self.normal_vector.is_zero():
            if not ell.normal_vector.is_zero():
                return False
            else:
                diff = self.constant_term - ell.constant_term
                return MyDecimal(diff).is_near_zero()
        elif ell.normal_vector.is_zero():
            return False

        if not self.is_parallel_to(ell):
            return False

        x0 = self.basepoint
        y0 = ell.basepoint
        basepoint_difference = x0.minus(y0)

        n = self.normal_vector
        return basepoint_difference.is_orthogonal_to(n)

    def is_parallel_to(self, ell):
        n1 = self.normal_vector
        n2 = ell.normal_vector
        return n1.is_parallel_to(n2)

    def set_basepoint(self):
        try:
            n = self.normal_vector
            c = self.constant_term
            basepoint_coords = ['0']*self.dimension

            initial_index = Line.first_nonzero_index(n)
            initial_coefficient = n[initial_index]

            basepoint_coords[initial_index] = c/initial_coefficient
            self.basepoint = Vector(basepoint_coords)

        except Exception as e:
            if str(e) == Line.NO_NONZERO_ELTS_FOUND_MSG:
                self.basepoint = None
            else:
                raise e

    def intersection_with(self, ell):
        try:
            A, B = self.normal_vector.coordinates
            C, D = ell.normal_vector.coordinates
            k1 = self.constant_term
            k2 = ell.constant_term

            x_numerator = D*k1 - B*k2
            y_numerator = -C*k1 + A*k2
            one_over_denom = Decimal('1')/(A*D - B*C)

            return Vector([x_numerator, y_numerator]).times_scalar(one_over_denom)

        except ZeroDivisionError:
            if self == ell:
                return self
            else:
                return None

    def __str__(self):

        num_decimal_places = 3

        def write_coefficient(coefficient, is_initial_term=False):
            coefficient = round(coefficient, num_decimal_places)
            if coefficient % 1 == 0:
                coefficient = int(coefficient)

            output = ''

            if coefficient < 0:
                output += '-'
            if coefficient > 0 and not is_initial_term:
                output += '+'

            if not is_initial_term:
                output += ' '

            if abs(coefficient) != 1:
                output += '{}'.format(abs(coefficient))

            return output

        n = self.normal_vector

        try:
            initial_index = Line.first_nonzero_index(n)
            terms = [write_coefficient(n[i], is_initial_term=(i==initial_index)) + 'x_{}'.format(i+1)
                     for i in range(self.dimension) if round(n[i], num_decimal_places) != 0]
            output = ' '.join(terms)

        except Exception as e:
            if str(e) == self.NO_NONZERO_ELTS_FOUND_MSG:
                output = '0'
            else:
                raise e

        constant = round(self.constant_term, num_decimal_places)
        if constant % 1 == 0:
            constant = int(constant)
        output += ' = {}'.format(constant)

        return output


    @staticmethod
    def first_nonzero_index(iterable):
        for k, item in enumerate(iterable):
            if not MyDecimal(item).is_near_zero():
                return k
        raise Exception(Line.NO_NONZERO_ELTS_FOUND_MSG)


class MyDecimal(Decimal):
    def is_near_zero(self, eps=1e-10):
        return abs(self) < eps

ell1 = Line(normal_vector = Vector(['4.046', '2.836']), constant_term = '1.21')
ell2 = Line(normal_vector = Vector(['10.115', '7.09']), constant_term = '3.025')
print 'intersection 1:', ell1.intersection_with(ell2)

ell1 = Line(normal_vector = Vector(['7.204', '3.182']), constant_term = '8.68')
ell2 = Line(normal_vector = Vector(['8.172', '4.114']), constant_term = '9.883')
print 'intersection 2:', ell1.intersection_with(ell2)

ell1 = Line(normal_vector = Vector(['1.182', '5.562']), constant_term ='6.744')
ell2 = Line(normal_vector = Vector(['1.773', '8.343']), constant_term = '9.525')
print 'intersection 3:', ell1.intersection_with(ell2)

=============================================== ==============

这里出现错误消息:

Traceback (most recent call last):
  File "/Users/Tristan/Desktop/line.py", line 146, in <module>
    ell1 = Line(normal_vector = Vector(['4.046', '2.836']), constant_term = '1.21')
  File "/Users/Tristan/Desktop/line.py", line 24, in __init__
    self.set_basepoint()
  File "/Users/Tristan/Desktop/line.py", line 67, in set_basepoint
    raise e
TypeError: 'Vector' object is not iterable
[Finished in 0.0s with exit code 1]
[shell_cmd: python -u "/Users/Tristan/Desktop/line.py"]
[dir: /Users/Tristan/Desktop]
[path: /usr/bin:/bin:/usr/sbin:/sbin]

=============================================== ==============

,这里是vector.py:

中的代码
from math import sqrt, acos, pi
from decimal import Decimal, getcontext

getcontext().prec = 30

class Vector(object):

    CANNOT_NORMALIZE_ZERO_VECTOR_MSG = 'cannot nomalize the zero vector.'
    CANNOT_COMPUTE_ANGLE_WITH_ZERO_VECTOR_MSG = 'Cannot compute an angle\
                                             with the zero vector.'
    NO_UNIQUE_PARALLEL_COMPONENT_MSG = 'there is no unique parallel\
                                     commponent.'
    NO_UNIQUE_ORTHOGONAL_COMPONENT_MSG = 'there is no unique orthogonal\
                                     commponent.'

    def __init__(self, coordinates):
        try:
            if not coordinates:
                raise ValueError
            self.coordinates = tuple([Decimal(x) for x in coordinates])
            self.dimension = len(self.coordinates)

        except ValueError:
            raise ValueError('The coordinates must be nonempty')

        except TypeError:
            raise TypeError('The coordinates must be an iterable')


    def __str__(self):
        return 'Vector: {}'.format(self.coordinates)

    def __eq__(self, v):
        return self.coordinates == v.coordinates

    def plus(self, v):
        new_coordinates = [x + y for x,y in zip(self.coordinates, v.coordinates)]
        return Vector(new_coordinates)

    def minus(self, v):
        new_coordinates = [x - y for x,y in zip(self.coordinates, v.coordinates)]
        return Vector(new_coordinates)

    def times_scalar(self, c):
        new_coordinates =[Decimal(c)*x for x in self.coordinates]
        return Vector(new_coordinates)

    def magnitude(self):
        coordinates_squared = [x**2 for x in self.coordinates]
        return Decimal(sum(coordinates_squared)).sqrt()

    def normalized(self):
        try:
            magnitude = self.magnitude()
            return self.times_scalar(Decimal('1.0')/Decimal(magnitude))
        except ZeroDivisionError:
            raise Exception(self.CANNOT_NORMALIZE_ZERO_VECTOR_MSG)

    def dot(self, v):
        return sum([x*y for x, y in zip(self.coordinates, v.coordinates)])

    def angle_with(self, v, in_degrees = False):
        try:
            u1 = self.normalized()
            u2 = v.normalized()
            angle_in_radians = Decimal(acos(u1.dot(u2)))

            if in_degrees:
                degrees_per_radian = Decimal('180.0')/Decimal(pi)
                return angle_in_radians * degrees_per_radian
            else:
                return angle_in_radians

        except Exception as e:
            if str(e) == self.CANNOT_NORMALIZE_ZERO_VECTOR_MSG:
                raise Exception(self.CANNOT_COMPUTE_ANGLE_WITH_ZERO_VECTOR_MSG)
            else:
                raise e

    def is_orthogonal_to(self, v, tolerance = 1e-10):
        return abs(self.dot(v)) < tolerance

    def is_parallel_to(self, v):
        return (self.is_zero() 
                or v.is_zero() or 
                self.angle_with(v) == 0 or 
                self.angle_with(v) == pi)

    def is_zero(self, tolerance = 1e-10):
        return self.magnitude() < tolerance

    def projection(self, v):
        try:
            unit_v = v.normalized()
            return (unit_v).times_scalar(self.dot(unit_v))
        except Exception as e:
            if str(e) == self.CANNOT_NORMALIZE_ZERO_VECTOR_MSG:
                raise Exception(self.NO_UNIQUE_PARALLEL_COMPONENT_MSG)
            else:
                raise e

    def orthogonal(self, v):
        try:
            return self.minus(self.projection(v))
        except Exception as e:
            if str(e) == self.NO_UNIQUE_PARALLEL_COMPONENT_MSG:
                raise Exception(self.NO_UNIQUE_ORTHOGONAL_COMPONENT_MSG)
            else:
                raise e

    def decompose(self, v):
        return str(self.projection(v)) + '+' + str(self.orthogonal(v))

    def cross_products(self, v):
        try:
            x_1, y_1, z_1 = self.coordinates
            x_2, y_2, z_2 = v.coordinates
            new_coordinates = [y_1*z_2 - y_2*z_1,
                -(x_1*z_2 - x_2*z_1), x_1*y_2 - x_2*y_1]
            return Vector(new_coordinates)

        except ValueError as e:
            msg = str(e)
            if msg == 'need more than 2 values to unpack':
                self_embedded_in_R3 = Vector(self.coordinates + ('0',))
                v_embedded_in_R3 = Vector(v.coordinates + ('0',))
                return self_embedded_in_R3.cross_products(v_embedded_in_R3)
            elif (msg == 'too many values to unpack' or
                msg == 'need more than 1 value to unpack'):
                raise Exception('only defined in two 3-dimensions')
            else:
                raise e

    def area_of_parallelogram(self, v):
        return (self.cross_products(v)).magnitude()

    def area_of_triangle(self, v):
        return self.area_of_parallelogram(v)/Decimal('2.0')

3 个答案:

答案 0 :(得分:3)

错误来自set_basepoint函数中的以下行:

TypeError: 'Vector' object is not iterable
> test.py(136)first_nonzero_index()
    135     def first_nonzero_index(iterable):
--> 136         for k, item in enumerate(iterable):
    137             if not MyDecimal(item).is_near_zero():

ipdb> up
> test.py(57)set_basepoint()
     56 
---> 57         initial_index = Line.first_nonzero_index(n)
     58         initial_coefficient = n[initial_index]

表示行引发异常为initial_index = Line.first_nonzero_index(n)

由于set_basepoint中过于宽泛的try / except块,隐藏了包含错误的行,我已将其注释掉以实现上述目标。

我不确定在那里想要什么,也许Line.first_nonzero_index(n.coordinates)而不会破坏。

first_nonzero_index中的代码正在for k, item in enumerate(iterable):,而iterableVector,这不是可迭代的,因此是错误。

通常,尽量减少try / except块,以免隐藏实际引发异常的代码。

同样在异常处理中检查str(e)相等是不好的做法,如果异常的字符串表示发生更改,则会中断。而是在异常类上使用isinstance

答案 1 :(得分:0)

    def set_basepoint(self):
    try:
        n = self.normal_vector
        # print(n)  # Vector: (Decimal('4.046'), Decimal('2.836'))
        c = self.constant_term
        basepoint_coords = ['0']*self.dimension

        initial_index = Line.first_nonzero_index(n.coordinates)
        # print(initial_index)  # 0

        initial_coefficient = n.coordinates[initial_index]
        # print(initial_coefficient)  # 4.046
        basepoint_coords[initial_index] = c/initial_coefficient
        self.basepoint = Vector(basepoint_coords)

    except Exception as e:
        if str(e) == Line.NO_NONZERO_ELTS_FOUND_MSG:
            self.basepoint = None
        else:
            raise e

解决这个问题,我们应该首先认真学习Vector类。

答案 2 :(得分:0)

由于以下原因,向量类型不可迭代

 def __str__(self):
        return 'Vector: {}'.format(self.coordinates)

str方法实际上存储的是字符串而不是元组。

在调用first_nonzero_index()和Line.first_nonzero_index(n.coordinates)而不是Line.first_nonzero_index(n.coordinates)的所有实例中,修复程序都使用initial_coefficient = n.coordinates[initial_index]而不是initial_coefficient = n[initial_index]。此外,还有另一个错误

在线课程

在str方法中:

try:
    initial_index = Line.first_nonzero_index(n.coordinates)
   terms = [write_coefficient(n[i], is_initial_term=(i==initial_index))+'x_{}'.format(i+1)
       for i in range(self.dimension) if round(n.coordinates[i], num_decimal_places) != 0]
            output = ' '.join(terms)

向量类也不可索引,请替换每个 n n.coordinates