phultberg
phultberg

Reputation: 13

Using attributes from one class into another

In python, I want to create a coordinate system with two classes in separate scripts; lines and points where point class is just x,y and z coordinates and line class then have two of these points as attributes. My problem is that I don't understand how to write line class so it understands it is points it is getting and how to retrieve for example x in a point in line class. Point class looks like this:

class point:
    def __init__(self, x, y, z=0):
        self.x = float(x)
        self.y = float(y)
        self.z = float(z)

I am not certain how to write the line class but it looks something like this:

import point
import math
class line(point):
    def __init__(self, p1, p2):
        self.p1 = p1
        self.p2 = p2

    def length(self):
        return math.sqrt((self.p2.x-self.p1.x)+(self.p2.y-self.p1.y))

Where I should then be able to create objects either like

line = line((1,2), (3,4,5))

or like

p1 = point.point(1,2)
p2 = point.point(3,4,5)
line = line(p1,p2)

I also want to be able to create functions like the one in line class and to retrieve coordinates in something like

line.p2.x

or

line.p2[0]

giving me (in this case) the output of 3. I also don't want point to be a subclass since there can be points not belonging to a line. Perhaps there is already a good answer to how to implement line class in such a way but I haven't found or understood it. Most examples is either about subclasses or separate classes which doesn't send or share some attributes. Thanks in advance for the help.

Upvotes: 1

Views: 1068

Answers (2)

MatsLindh
MatsLindh

Reputation: 52930

First: classes should be title capitalized, so that the proper names would be Line and Point - that make them easy to separate from plain variables.

As you've mentioned, inheriting from Point isn't the way to go - since a Line isn't a point. But you're almost there with your example:

from point import Point
import math

class Line:
    def __init__(self, p1, p2):
        self.p1 = p1
        self.p2 = p2

    def length(self):
        return math.sqrt((self.p2.x-self.p1.x)+(self.p2.y-self.p1.y))

Line(Point(x1, y1), Point(x2, y2))  # should work

You can also use Python 3.6+'s typing support to say that you expect Point objects:

class Line:
    def __init__(self, p1: Point, p2: Point):
        self.p1 = p1
        self.p2 = p2

....

Upvotes: 1

chepner
chepner

Reputation: 532518

A tuple is not a point, and line.__init__ will not automatically know to make the conversion. While you could add logic to line.__init__ to detect the type of argument, I would recommend separate functions for creating lines from tuples and points. Which you choose as the "canonical" argument is up to you. Here's an example using point.

class Line:
    def __init__(self, p1: point, p2: point):
        self.p1 = p1
        self.p2 = p2

    @classmethod
    def from_tuples(cls, p1, p2):
        return cls(point(*p1), point(*p2))

line1 = Line.from_tuples((1,2), (3,4,5))
p1 = point(1,2)
p2 = point(3,4,5)
line = Line(p1,p2)

Based on how you want to use point, I would recommend a namedtuple, and again leave the responsibility to pass the correct type of argument to the caller.

Point = namedtuple('Point', 'x y z')

p1 = Point(1.0, 2.0)  # p.x == p[0] == 1

Upvotes: 1

Related Questions