Python Learning

# Define the method distance, inside the class Point, which determines distance between two points.
# Use formula distance = sqrt( (x1-x2)**2 + (y1-y2)**2 + (z1 -z2)**2 ).
# Create two Point objects p2 = Point(4, 5, 6), p3 = Point(-2, -1, 4) and 
# determine distance of p2 from p3 using defined distance method.
# Print the distance value.

class Point_1:
    def __init__(self,x1,y1,z1):
        self.x1=x1
        self.y1=y1
        self.z1=z1
    def __str__(self):
                   
        return ('x1'+'='+str(self.x1)+',''y1'+'='+str(self.y1)+',''z1'+'='+str(self.z1))
class Point_2:
    def __init__(self,x2,y2,z2):
        self.x2=x2
        self.y2=y2
        self.z2=z2
    def __str__(self):
        return ('x2'+'='+str(self.x2)+',''y2'+'='+str(self.y2)+',''z2'+'='+str(self.z2))
        

    def distance(p2,p3):  
       
        d = math.sqrt(math.pow(x2 - x1, 2) +
                math.pow(y2 - y1, 2) +
                math.pow(z2 - z1, 2)* 1.0) 
        print(d) 
  

    
        
p2=Point_1(4,5,6)
p3=Point_2(-2,-1,4)
print(p2)
print(p3)
print(distance(p2,p3))


Can somebody tell me what is issue with this code.
I have to pass tow 3 d cordinates and print distance between them.
O/P i am getting is like -

x1=4,y1=5,z1=6
x2=-2,y2=-1,z2=4

NameError Traceback (most recent call last)
in
41 print(p2)
42 print(p3)
—> 43 print(distance(p2,p3))

in distance(p2, p3)
29 def distance(p2,p3):
30
—> 31 d = math.sqrt(math.pow(x2 - x1, 2) +
32 math.pow(y2 - y1, 2) +
33 math.pow(z2 - z1, 2)* 1.0)

NameError: name ‘x2’ is not defined

Hi. Welcome.

  1. What output do you expect?
  2. What kind of output are you getting?

Also note your original post is hard to read. Press Ctrl + Shift + c when posting code. And remember to add indents to your functions and classes. This will help others understand your issue and to respond appropriately. :slight_smile:

O/P i am getting is as below-
x1=4,y1=5,z1=6
x2=-2,y2=-1,z2=4

NameError Traceback (most recent call last)
in
41 print(p2)
42 print(p3)
—> 43 print(distance(p2,p3))

in distance(p2, p3)
29 def distance(p2,p3):
30
—> 31 d = math.sqrt(math.pow(x2 - x1, 2) +
32 math.pow(y2 - y1, 2) +
33 math.pow(z2 - z1, 2)* 1.0)

NameError: name ‘x2’ is not defined

Thanks.

After a quick look, I suspect you might have a NameError when calling distance().

First, if you are unsure how libraries work, e.g. math.sqrt, you can make your own sqrt() function.

def sqrt(x):
    """Return the square root."""
    return x ** 0.5

distances() expects two Point instances. To get xs, ys and zs from these classes, you can unpack their attributes.

def distance(p1, p2):
    """Return the distance between two 3D Points."""

    x1, y1, z1 = p1.x1, p1.y1, p1.z1
    x2, y2, z2 = p2.x2, p2.y2, p2.z2
    
    d = sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2 + (z2 - z1) ** 2) 
    print(d) 
    return d

See you have Points p1 and p2, but how do you get their x, y, z values? The dot operator is your friend. It allows you to access values in an attribute on an instance of a class. In other words:

>>> p = Point(1, 2, 3)
>>> p.x
1
>>> (p.y, p.z)
(2, 3)

Note: this last example will not work until you create the Point class (see below)

After getting your answer, you can take a moment to revise some things.

First, you may notice the code in Point_1 and Point_2 are nearly identical. One has names ending in 1 and the other with names ending in 2. Aside from that, they are the same class. So you can save yourself a lot of typing. Just delete one of these classes and rename the other, removing these ending bits. Example:

class Point:
    """A 3D point in space."""
    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z     

Now you can make as many point instances as you wish (here’s where you can number them):

p1 = Point(0, 0, 0)
p2 = Point(1, 0, -1)
p3 = Point(1, 2, 3)

And do whatever you want with their attributes:

>>> p1.x + p2.x + p3.x
2
>>> p1.x + p2.y + p3.z
3

The class allows you to reuse code. Although the assigned instance names are uniquely separate, the attribute names are shared. :slight_smile:

1 Like

Hi there!

First off, I think you need to read the question you are trying to answer a little more carefully. It asks you to create two objects of class Point. That is not what you have done. Instead you have created two new classes that are pretty much the same except for the attribute names, and then created an object of each class. So to start with, don’t do that. Go back to the class Point, which I presume came out of an earlier exercise.

Moving on, you defined a new method “distance” in your Point_2 class as the question asked for, but it’s not going to work. Just take a moment to look at your “distance” and the “__init__” and “__str__” before it. What do “__init__” and “__str__” have that “distance” doesn’t? And I don’t mean the leading and trailing underscores!

The answer is “self”. A method always[*] takes an instance of its class as its first parameter, and by convention we call it “self”. You’ve called it “p2”, which is potentially confusing both because you are breaking the convention and because you later call one of your actual Point objects “p2”. That might be the Point object you call “distance” through or it might not; expecting one and getting the others will cause you endless grief. Similarly, calling the second parameter “p3” is the sort of thing that will cause confusion later on. I would call it “p”, “pt”, “point” or maybe even “other”; pick something that makes sense to you.

Inside your “distance” method is a great example of that sort of confusion, this time caused by creating the Point_1 and Point_2 classes. Let’s start with asking what is “x2”? Without any dots in the name, it has to be a local or global variable. You don’t create a local variable called “x2” before you use it in that big square root calculation, and you don’t have a global variable called “x2” either, so Python would give you another NameError if it got that far. In fact the only things in your program called “x2” are a parameter to Point_2.__init__() and the attribute that parameter is written to. You have used “x2” because it’s that parameter you want. Unfortunately you can’t have it; the parameter went away long ago. So what you actually should want is the attribute you saved that parameter in, which is also called “x2”. Confusing, see? To get the attribute, you need to say which instance (object) you want to take the attribute of. In this case that’s the first parameter to your “distance” method, what you called “p2” and what you should rename “self”. In other words, instead of “x2” you should write “self.x2”. “y2” and “z2” need the same treatment too.

(When you go back to using the Point class, you’ll probably find that the attribute is just called “x”, so you’ll type “self.x” instead.)

In a similar way, “x1”, “y1” and “z1” don’t refer to anything real. For them, you want the attributes of the other parameter to “distance”, what you called “p3”.

[*] Well, almost always. Don’t worry about the exceptions now.

2 Likes

i don’t see where you have import the math module there.

Thank you very much.
being a newbie, i am still struggling with concepts a bit.
Your suggestions helped in resolving it.

Thank you very much.

If you need clarification with what has been posted, let us know :slight_smile: