Jake From State Farm
Jake From State Farm

Reputation: 57

Python: AttributeError: 'Point' object has no attribute 'x'

Traceback (most recent call last):
line 56, in <module>
    distanceToOne = point1.Distance(pointUser)
line 22, in Distance
    distance = math.sqrt((self.__x - toPoint.x)**2 +(self.__y - toPoint.y)**2 +(self.__z - toPoint.z)**2)
AttributeError: 'Point' object has no attribute 'x'

For some reason I keep getting the above error message whenever I get to: distanceToOne = point1.Distance(pointUser) after grabbing my three points to calculate the distance from.

Here is a better view if needed: http://pastie.org/private/vige6oaphkwestdemr5uw

Thanks in advance for your help!

import math
class Point(object):
    def __init__(self, x = 0, y = 0, z = 0, description = 'TBD'):
        self.__x = x
        self.__y = y
        self.__z = z
        self.__description = description

    def SetPoint(self, coords):
        self.__x = coords[0]
        self.__y = coords[1]
        self.__z = coords[2]

    def GetPoint(self):
        return [self.__x, self.__y, self.__z]
    PointCoords = property(GetPoint, SetPoint)

    def Distance(self, toPoint):
        toPoint.PointCoords[0]
        toPoint.PointCoords[1]
        toPoint.PointCoords[2]
        return math.sqrt(
            (self.__x - toPoint.x)**2 +
            (self.__y - toPoint.y)**2 +
            (self.__z - toPoint.z)**2)

    def SetDescription(self, description):
        self.__description = description

    def GetDescription(self):
        return self.__description
    PointDescription = property(GetDescription, SetDescription)

if __name__ == "__main__":
    print "Program 9: Demonstrate how to define a class"

    point2 = Point()
    point1 = Point(10, 54, 788, 'Ploto')
    point2.PointCoords = 77, 2, 205
    point2.PointDescription = 'Mars'
    doAnother = "y"
    while(doAnother == "y"):
        pointX = raw_input("Enter a X Number: ")
        pointY = raw_input("Enter a Y Number: ")
        pointZ = raw_input("Enter a Z Number: ")

        # Constructor - Represent the user's location
        pointUser = Point(pointX, pointY, pointZ, 'Sun')

        distanceToOne = point1.Distance(pointUser)
        distanceToTwo = point2.Distance(pointUser)

        # Comparing the two distances between the two to see which one is the closest
        if (distanceToOne > distanceToTwo):
            closest = point2
        else:
            closest = point1
            print ('You are closest to',closest.PointDescription(), 'which is located at ',closest.PointCoords())
        doAnother = raw_input("Do another (y/n)? ").lower()
    print ('Good Bye!')

Upvotes: 4

Views: 16727

Answers (5)

Julien Spronck
Julien Spronck

Reputation: 15433

In the return line of Distance(), __x instead of x (same for y and z), since the instances of the Point class do not have x, y z attributes but they do have __x, __y, __z attributes. ​

def Distance(self, toPoint):
    toPoint.PointCoords[0]
    toPoint.PointCoords[1]
    toPoint.PointCoords[2]
    return math.sqrt(
        (self.__x - toPoint.__x)**2 +
        (self.__y - toPoint.__y)**2 +
        (self.__z - toPoint.__z)**2)

Upvotes: 1

wim
wim

Reputation: 362944

The actual error is due to accessing toPoint.x, which doesn't exist because you have never defined it.

On a related note, prepending attributes with double underscores activates pythons name mangling feature. The actual attributes will still be publicly accessible at my_point._Point__x, my_point._Point__y, etc from outside the class.

As a matter of style, there does not seem to be any reason to use name mangling in this case. The intended use-case of this feature is to avoid clashes with inherited classes, it's not really about trying to make "private" variables (for that, the convention is to use a single underscore to indicate when an attribute is implementation detail).

In your case, I think you should just name (and access) the attributes normally x, y, etc. In python we don't normally write getters and setters for class members unless there is a special requirement to do so, because Python is not Java.

Upvotes: 2

mhawke
mhawke

Reputation: 87094

Another way to do it is to unpack toPoint.PointCoords into local variables like this:

def Distance(self, toPoint):
    x, y, z = toPoint.PointCoords
    return math.sqrt(
        (self.__x - x)**2 +
        (self.__y - y)**2 +
        (self.__z - z)**2)

Upvotes: 0

Alexander
Alexander

Reputation: 109606

This example uses the namedtuple class from collections. I've also re-written the class to implement it (it should still work with your existing program).

Also note that python generally does not use setters or getters. In fact. you set the description directly in your program (as you should) rather than having used your setter function.

import math
from collections import namedtuple

point = namedtuple('point', ['x', 'y', 'z'])

class Point(object):
    def __init__(self, x=0, y=0, z=0, description='TBD'):
        self.point = point(x, y, z)
        self.__description = description

    def __repr__(self):
        return str(self.point)

    def set_point(self, coords):
        self.point = point(coords)

    def get_point(self):
        p = self.point
        return p.x, p.y, p.z

    def distance(self, toPoint):
        p = toPoint.point
        return math.sqrt(
            (self.point.x - p.x)**2 +
            (self.point.y - p.y)**2 +
            (self.point.z - p.z)**2)

    def set_description(self, description):
        # Python generally does not use getters/setters.
        self.description = description

    def get_description(self):
        # Python generally does not use getters/setters.
        return self.description

Upvotes: 0

srgerg
srgerg

Reputation: 19329

You could make the x, y and z attributes of your Point class publicly accessible. If you want the client to be able to read but not write to them, you can use a property. For example:

class Point(object):
    def __init__(self, x = 0, y = 0, z = 0, description = 'TBD'):
        self.__x = x
        self.__y = y
        self.__z = z
        self.__description = description

    @property
    def x(self):
        return self.__x

    @property
    def y(self):
        return self.__y

    @property
    def z(self):
        return self.__z

    ...

You can then access x, y and z without the leading underscores and your Distance function should work.

>>> p = Point(1, 2, 3, 'Dummy')
>>> p.x
1
>>> p.y
2
>>> p.z
3
>>> p.x = 3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute

Upvotes: 0

Related Questions