John Kyle
John Kyle

Reputation: 117

Python - AttributeError

So for a line class I'm doing, I keep getting an error that says

AttributeError: Line instance has no attribute 'point0'

I'm declaring the line like this:

def __init__(self, point0, point1):
    self.x = point0
    self.y = point1

def __str__(self):
    return '%d %d' % (int(round(self.point0)), int(round(self.point1)))

And I get the x and y from my point class which should already be float values so I don't need to check for an error in my init method however I do check to see if point0 and point1 are floats in my rotate method:

def rotate(self, a):
        if not isinstance(a, float) or not isinstance(self.point0, float) or not isinstance(self.point1, float):
            raise Error("Parameter \"a\" illegal.")
        self.point0 = math.cos(a) * self.point0 - math.sin(a) * self.point1
        self.point1 = math.sin(a) * self.point0 + math.cos(a) * self.point1

So why does python keep saying that it has no attribute point0? I also tried changing my init method to look like this:

def __init__(self, point0, point1):
    self.point0 = point0
    self.point1 = point1

But when I do that the error says point0 has no attribute float. So why do I keep getting this error? Here's the code I'm using to test:

p0 = Point(0.0, 1.0)
p1 = Point(2.0, 3.0)
line = Line(p0,p1)
print line

Upvotes: 0

Views: 696

Answers (4)

Blarghedy
Blarghedy

Reputation: 47

I'm going to add another answer here, both because I lack the reputation to comment on the other answer and because I feel this answer is unrelated to my previous answer (which addressed a different problem than what you're seeing now).

So. That said, look at this line of code:

return '%d %d' % (int(round(self.point0)), int(round(self.point1)))

round is a function that takes a numeric argument. However, self.point0 and self.point1 are not numbers. They are points. If you want the numbers from them, you'll have to refer to those explicitly (i.e. self.point0.x).

Upvotes: 0

chepner
chepner

Reputation: 530823

A few overall points before displaying your corrected code. (Note that not much actually changed):

  1. Don't bother checking argument types. Python programmers are assumed to be responsible enough to read the documentation and pass values of the correct value.

  2. Your Line class was duplicating code that you had already defined in the Point class. The attributes of a line are Point instances, so you can use the methods you defined to implement the Line methods.

  3. There's no reason to round the point coordinates to integers when displaying them; show the actual floating-point values that define the point. Your Line.__str__ method can take advantage of the fact that you've defined Point.__str__.

And now, your much shorter and corrected code, with some interspersed comments.

import math


class Point:
    def __init__(self, x, y):
        '''x and y should be floats'''
        self.x = x
        self.y = y

    def rotate(self, a):
        '''Rotate the point around the origin by a radians'''
        self.x = math.cos(a) * self.x - math.sin(a) * self.y
        self.y = math.sin(a) * self.x + math.cos(a) * self.y
        # If you *were* going to check if a is a float, you
        # need to do it *before* you use it.

    def scale(self, f):
        '''Scale the point by f units'''  # you get the idea
        self.x = f * self.x
        self.y = f * self.y

    def translate(self, delta_x, delta_y):
        self.x = self.x + delta_x
        self.y = self.y + delta_y

    def __str__(self):
        # If you're storing floats, it's probably useful
        # to output them.
        return '(%f, %f)' % (self.x, self.y)


# Operations on a line all involve applying the same operations
# to each of its end points.
class Line:
    def __init__(self, point0, point1):
        self.point0 = point0
        self.point1 = point1

    def rotate(self, a):
        self.point0.rotate(a)
        self.point1.rotate(a)

    def scale(self, factor):
        self.point0.scale(factor)
        self.point1.scale(factor)
        # If for whatever reason you didn't want to use Point.scale
        # here, the code would be...
        # self.point0.x = f * self.point0.x
        # self.point0.y = f * self.point0.y
        # self.point1.x = f * self.point0.x
        # self.point1.y = f * self.point0.y

    def translate(self, delta_x, delta_y):
        self.point0.translate(delta_x, delta_y)
        self.point1.translate(delta_x, delta_y)

    def __str__(self):
        # You've already defined out to turn a Point into
        # a string, so you can take advantage of that here.
        return "%s -- %s" % (self.point0, self.point1)

Upvotes: 0

FatmaT
FatmaT

Reputation: 255

your class accept point0 and point1 parameters when you call it. If you want to get values of these parameters you should use self.x(for point0) and self.y(for point1) or another way;

class Line:
   def __init__(self, point0, point1):
       self.point0 = point0
       self.point1 = point1

I suggest you to read;

Python __init__ and self what do they do?

https://www.ibiblio.org/swaroopch/byteofpython/read/class-init.html

https://docs.python.org/2/tutorial/classes.html

Upvotes: 1

Blarghedy
Blarghedy

Reputation: 47

I'm curious... how much do you know about scope in Python?

In your class, you have a member variable named x and another named y. Your init function accepts an argument called point0 and another called point1. It saves point0 in the x member variable, and point1 in y. Then, in your rotate function, you attempt to access a variable called point0. Do you see the problem?

An important thing to understand when programming (and this is true in most programming languages, if not all of them) is that the name of an argument doesn't affect the name of that data elsewhere. I can pass a variable called foo into a function that takes an argument called bar. In that function, I have to refer to the data as bar because that's the name of the variable. Later, after I've called that function, the name of the variable is still foo, because only the variable inside the function is called bar. Does that make sense?

Upvotes: 1

Related Questions