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.