Adding an interface to existing classes

Discussion in 'Python' started by Spencer Pearson, Dec 22, 2011.

  1. I'm writing a geometry package, with Points and Lines and Circles and
    so on, and eventually I want to be able to draw these things on the
    screen. I have two options so far for how to accomplish this, but
    neither of them sits quite right with me, and I'd like the opinion of
    comp.lang.python's wizened elders.

    Option 1. Subclassing.
    The most Pythonic way would seem to be writing subclasses for the
    things I want to display, adding a ".draw(...)" method to each one,
    like this:
    class DrawablePoint( geometry.Point ):
    class draw( self, ... ):
    ...

    When the time comes to draw things, I'll have some list of objects I
    want drawn, and say
    for x in to_draw:
    x.draw(...)

    I see a problem with this, though. The intersection of two lines is
    (usually) an object of type Point. Since DrawableLine inherits from
    Line, this means that unless I redefine the "intersect" method in
    DrawableLine, the intersection of two DrawableLines will be a Point
    object, not a DrawablePoint. I don't want to saddle the user with the
    burden of converting every method output into its corresponding
    Drawable subclass, and I don't want to redefine every method to return
    an instance of said subclass. I see no other options if I continue
    down the subclassing path. Am I missing something?




    Option 2. A "draw" function, with a function dictionary.
    This feels weird, but is fairly simple to write, use, and extend. We
    have a module with a "draw_functions" dictionary that maps types onto
    functions, and a "draw" function that just looks up the proper type in
    the dictionary and calls the corresponding function. If you create
    your own object, you can just add a new entry to the dictionary. The
    implementation is simple enough to outline here:

    In file "geometry/gui.py":
    def draw_point(...):
    ...
    def draw_line(...):
    ...
    draw_functions = {geometry.Point: draw_point, geometry.Line:
    draw_line, ...}
    def draw( x, *args, **kwargs ):
    for type, callback in draw_functions.iteritems():
    if isinstance(x, type):
    callback(x, *args, **kwargs)
    else:
    raise TypeError("don't know how to draw things of type "
    "{0}".format(type(x)))


    In the file that uses this:
    # Drawing a predefined type of object:
    geometry.gui.draw(some_point, ...)
    # Here we define a new kind of object and tell the package how to draw
    it.
    class MyObject(GeometricObject):
    ...
    def draw_my_object(...):
    ...
    geometry.gui.draw_functions[MyObject] = draw_my_object
    # And now we draw it.
    geometry.gui.draw(MyObject(...), ...)


    If I feel fancy, I might use a decorator for adding entries to
    draw_functions, but this is basically how it'd work.




    The second way feels kludgey to me, but I'm leaning towards it because
    it seems like so much less work and I'm out of ideas. Can anyone help,
    explaining either a different way to do it or why one of these isn't
    as bad as I think?

    Thanks for your time!
    -Spencer
    Spencer Pearson, Dec 22, 2011
    #1
    1. Advertising

  2. Spencer Pearson

    Terry Reedy Guest

    On 12/22/2011 3:21 AM, Spencer Pearson wrote:
    > I'm writing a geometry package, with Points and Lines and Circles and
    > so on, and eventually I want to be able to draw these things on the
    > screen. I have two options so far for how to accomplish this, but
    > neither of them sits quite right with me, and I'd like the opinion of
    > comp.lang.python's wizened elders.
    >
    > Option 1. Subclassing.
    > The most Pythonic way would seem to be writing subclasses for the
    > things I want to display, adding a ".draw(...)" method to each one,
    > like this:


    > Option 2. A "draw" function, with a function dictionary.


    Option 3? Add a draw method to existing classes, rather than subclassing?

    --
    Terry Jan Reedy
    Terry Reedy, Dec 22, 2011
    #2
    1. Advertising

  3. On Dec 23, 9:13 am, Terry Reedy <> wrote:
    > On 12/22/2011 3:21 AM, Spencer Pearson wrote:
    >
    > > I'm writing a geometry package, with Points and Lines and Circles and
    > > so on, and eventually I want to be able to draw these things on the
    > > screen. I have two options so far for how to accomplish this, but
    > > neither of them sits quite right with me, and I'd like the opinion of
    > > comp.lang.python's wizened elders.

    >
    > > Option 1. Subclassing.
    > > The most Pythonic way would seem to be writing subclasses for the
    > > things I want to display, adding a ".draw(...)" method to each one,
    > > like this:
    > > Option 2. A "draw" function, with a function dictionary.

    >
    > Option 3? Add a draw method to existing classes, rather than subclassing?
    >
    > --
    > Terry Jan Reedy


    Thanks for the response! Do you mean something like this?
    class Point(GeometricObject):
    def intersect(self, other):
    ...
    def union(self, other):
    ...
    def draw(self, ...):
    ...

    I'd like to avoid this, because... well, what I want is a geometry
    package, and it seems to me that whistles and bells like GUI support
    ought to be confined to subpackages. I'd look at this and think, "the
    rest of the Point class deals with fundamental geometric reality.
    What's this GUI method doing mixed in with my beautiful mathematical
    purity?" Is this the wrong attitude to take?

    Or did you mean this?
    In file "geometry/gui.py":
    def draw_point(point, ...):
    ...
    Point.draw = draw_point

    I've never modified an existing class before, and I fear the
    unfamiliar. If that's what you meant... it's really an acceptable
    thing to do? It seems like somebody might see "some_point.draw(...)"
    and be confused by the method's absence in the Point class definition.

    (A hybrid approach would be to say "draw = geometry.gui.draw_point"
    inside the body of the Point class, setting the attribute there
    instead of in gui.py, but that makes me uneasy for the same reason as
    putting the function's full definition in the class.)

    Thanks again,
    -Spencer
    Spencer Pearson, Dec 24, 2011
    #3
  4. Spencer Pearson

    Ian Kelly Guest

    On Thu, Dec 22, 2011 at 1:21 AM, Spencer Pearson
    <> wrote:
    > I see a problem with this, though. The intersection of two lines is
    > (usually) an object of type Point. Since DrawableLine inherits from
    > Line, this means that unless I redefine the "intersect" method in
    > DrawableLine, the intersection of two DrawableLines will be a Point
    > object, not a DrawablePoint. I don't want to saddle the user with the
    > burden of converting every method output into its corresponding
    > Drawable subclass, and I don't want to redefine every method to return
    > an instance of said subclass. I see no other options if I continue
    > down the subclassing path. Am I missing something?


    You could solve this with a factory. Instead of having
    Line.intersection() create a Point directly, have it call
    self.factory.create_point(). In the drawing module, replace the
    factory for the subclasses with one that creates drawable classes
    instead.


    > Option 2. A "draw" function, with a function dictionary.
    > This feels weird, but is fairly simple to write, use, and extend. We
    > have a module with a "draw_functions" dictionary that maps types onto
    > functions, and a "draw" function that just looks up the proper type in
    > the dictionary and calls the corresponding function. If you create
    > your own object, you can just add a new entry to the dictionary. The
    > implementation is simple enough to outline here:


    This will also work, but inheritance complicates things a little. Do
    you do a type equality check or an isinstance() check when looking up
    the type in the dictionary? If the former, then somebody who
    subclasses geometry.Line to create a GroovyLine subclass must add an
    entry for GroovyLine to the dictionary, even if the drawing code is
    the same. The drawing code is not inherited.

    But if you do an isinstance() check, then you need to be very careful
    about how you check it. If somebody creates a WavyLine subclass and
    registers a different drawing method, then you need to make sure the
    isinstance() check for the WavyLine implementation happens before the
    regular Line implementation, or the wrong drawing code may get invoked
    for WavyLine. Probably the easiest way to do this correctly is to
    follow the MRO that Python has conveniently already built for you.
    Something like:

    def draw(x, *args, **kwargs ):
    for class_ in type(x).__mro__:
    if class_ in draw_functions:
    draw_functions[class_](*args, **kwargs)
    break
    else:
    raise TypeError("don't know how to draw things of type "
    "{0}".format(type(x)))

    Cheers,
    Ian
    Ian Kelly, Dec 25, 2011
    #4
  5. Spencer Pearson

    Rick Johnson Guest

    On Dec 22, 2:21 am, Spencer Pearson <> wrote:
    > I'm writing a geometry package, with Points and Lines and Circles and
    > so on, and eventually I want to be able to draw these things on the
    > screen.


    ....which is the main reason for creating a geometry package in the
    first place!. I mean, imaginary points and lines are great if you are
    a theoretical mathematician, but for the rest of us earthlings,
    plotted pixels are the "in thang" now-a-days.

    > I have two options so far for how to accomplish this, but
    > neither of them sits quite right with me, and I'd like the opinion of
    > comp.lang.python's wizened elders.
    >
    > Option 1. Subclassing.
    > The most Pythonic way would seem to be writing subclasses for the
    > things I want to display, adding a ".draw(...)" method to each one,
    > like this:
    > class DrawablePoint( geometry.Point ):
    >     class draw( self, ... ):
    >         ...


    "DrawablePoint"? I suppose there is an "ImaginaryPoint" somewhere in
    this API? Geez

    > When the time comes to draw things, I'll have some list of objects I
    > want drawn, and say
    > for x in to_draw:
    >     x.draw(...)


    Seems reasonable. Not the fastest approach, but a good start for a
    very high level interface.

    > I see a problem with this, though. The intersection of two lines is
    > (usually) an object of type Point. Since DrawableLine inherits from
    > Line,


    Why the hell is "Drawable" inheriting from Line? I would think that a
    "Line" would be "Drawable" object and NOT vice-versa? Am i wrong?

    > this means that unless I redefine the "intersect" method in
    > DrawableLine, the intersection of two DrawableLines will be a Point
    > object, not a DrawablePoint.


    OMFG!

    > I don't want to saddle the user with the
    > burden of converting every method output into its corresponding
    > Drawable subclass, and I don't want to redefine every method to return
    > an instance of said subclass. I see no other options if I continue
    > down the subclassing path. Am I missing something?


    Yes, a proper object hierarchy and API it seems @_@.

    Spencer, i would re-think this entire project from the beginning. You
    are trying to make an object out of everything. You don't need to make
    an object of EVERYTHING. Ask yourself, what are the most basic objects
    of a geometry library, and then report back to us your findings.

    PS: I prefer option1 for these things as the OOP paradigm fits nicely.
    I just hate to have modules of loose functions just lying about.
    Rick Johnson, Dec 25, 2011
    #5
  6. Spencer Pearson

    Terry Reedy Guest

    On 12/24/2011 6:49 PM, Spencer Pearson wrote:
    > On Dec 23, 9:13 am, Terry Reedy<> wrote:
    >> On 12/22/2011 3:21 AM, Spencer Pearson wrote:
    >>
    >>> I'm writing a geometry package, with Points and Lines and Circles and
    >>> so on, and eventually I want to be able to draw these things on the
    >>> screen. I have two options so far for how to accomplish this, but
    >>> neither of them sits quite right with me, and I'd like the opinion of
    >>> comp.lang.python's wizened elders.

    >>
    >>> Option 1. Subclassing.
    >>> The most Pythonic way would seem to be writing subclasses for the
    >>> things I want to display, adding a ".draw(...)" method to each one,
    >>> like this:


    There are people who would advocate a Drawable base class with a virtual
    or abstract .draw method and that DrawablePoint, etc, inherit from
    Drawable and Point.

    >>> Option 2. A "draw" function, with a function dictionary.

    >>
    >> Option 3? Add a draw method to existing classes, rather than subclassing?


    > Thanks for the response! Do you mean something like this?
    > class Point(GeometricObject):
    > def intersect(self, other):
    > ...


    I am interpreting this to mean that you have a world coordinate system
    for instances that have location and size.

    > def union(self, other):
    > ...
    > def draw(self, ...):
    > ...


    Yes. I would consider that Option 0, the default, unless you have good
    reason to choose another. I would certainly include it on a list of options.

    > I'd like to avoid this, because... well, what I want is a geometry
    > package, and it seems to me that whistles and bells like GUI support
    > ought to be confined to subpackages. I'd look at this and think, "the
    > rest of the Point class deals with fundamental geometric reality.
    > What's this GUI method doing mixed in with my beautiful mathematical
    > purity?"


    By default, all Python objects have a text representation method. I do
    not see that giving all concrete geometric objects (with a location and
    size) a visual representation is much different. I would use drawing
    functions that accept the coordinates and distances of your geometry
    world and translate to low-level pixel functions for a particular gui
    system. I agree that your geometrical objects should not know about
    pixels, screens, windows, and aspect ratios.

    > Is this the wrong attitude to take?


    It depends on *your* goal and values.

    > Or did you mean this?
    > In file "geometry/gui.py":
    > def draw_point(point, ...):
    > ...
    > Point.draw = draw_point
    >
    > I've never modified an existing class before, and I fear the
    > unfamiliar. If that's what you meant... it's really an acceptable
    > thing to do?


    Yes, in my opinion. The advantage of this is putting all the draw
    methods together, and possibly having more than one one set. On the
    other hand, one needs to know the data attributes of each class to
    understand its draw method.

    > It seems like somebody might see "some_point.draw(...)"
    > and be confused by the method's absence in the Point class definition.


    With either suboption, you should put an abstract .draw method in the
    GeometricObject base class.

    I would look at various game, graph, geometry, and gui packages handle
    drawing for more ideas.

    --
    Terry Jan Reedy
    Terry Reedy, Dec 25, 2011
    #6
  7. On Sat, 24 Dec 2011 17:24:14 -0800, Rick Johnson wrote:

    >> class DrawablePoint( geometry.Point ):
    >>     class draw( self, ... ):
    >>         ...

    >
    > "DrawablePoint"? I suppose there is an "ImaginaryPoint" somewhere in
    > this API? Geez


    No, but there's an abstract Point, which presumably refers to the
    geometric concept (hence the module, geometry) without concerning itself
    with such things as pixels, raster and vector output devices, screen
    resolutions, and all the other stuff which is needed for drawing points
    but not needed for working with points.


    [...]
    >> I see a problem with this, though. The intersection of two lines is
    >> (usually) an object of type Point. Since DrawableLine inherits from
    >> Line,

    >
    > Why the hell is "Drawable" inheriting from Line? I would think that a
    > "Line" would be "Drawable" object and NOT vice-versa? Am i wrong?


    Probably. I think there's a case for Drawable to be an abstract mixin
    class, so that DrawableLine inherits from both Line and Drawable.


    >> this means that unless I redefine the "intersect" method in
    >> DrawableLine, the intersection of two DrawableLines will be a Point
    >> object, not a DrawablePoint.


    Not if you define intersect in Point correctly in the first place.

    class Point: # An abstract class.
    def intersect(self, other):
    blah; blah; blah
    return Point(x, y) # No, wrong, bad!!! Don't do this.

    Instead:

    return self.__class__(x, y) # Better.


    > Spencer, i would re-think this entire project from the beginning. You
    > are trying to make an object out of everything. You don't need to make
    > an object of EVERYTHING.


    Very true.



    --
    Steven
    Steven D'Aprano, Dec 25, 2011
    #7
  8. On Sun, Dec 25, 2011 at 11:10 PM, Steven D'Aprano
    <> wrote:
    > class Point:  # An abstract class.
    >    def intersect(self, other):
    >        blah; blah; blah
    >        return Point(x, y)  # No, wrong, bad!!! Don't do this.
    >
    > Instead:
    >
    >        return self.__class__(x, y)  # Better.


    This would work if you were dealing with the intersection of two
    points, but how do you use that sort of trick for different classes?

    ChrisA
    Chris Angelico, Dec 25, 2011
    #8
  9. On Sun, 25 Dec 2011 23:32:41 +1100, Chris Angelico wrote:

    > On Sun, Dec 25, 2011 at 11:10 PM, Steven D'Aprano
    > <> wrote:
    >> class Point:  # An abstract class.
    >>    def intersect(self, other):
    >>        blah; blah; blah
    >>        return Point(x, y)  # No, wrong, bad!!! Don't do this.
    >>
    >> Instead:
    >>
    >>        return self.__class__(x, y)  # Better.

    >
    > This would work if you were dealing with the intersection of two points,
    > but how do you use that sort of trick for different classes?


    There's nothing in the above that assumes that other has the same type as
    self. It's just that the type of other is ignored, and the type of self
    always wins. I find that a nice, clear rule: x.intersection(y) always
    returns a point with the same type as x.

    If you want a more complicated rule, you have to code it yourself:


    def intersection(self, other):
    if issubclass(type(other), type(self)):
    kind = type(other)
    elif issubclass(type(self), type(other)):
    kind = AbstractPoint
    elif other.__class__ is UserPoint:
    kind = UserPoint
    elif today is Tuesday:
    kind = BelgiumPoint
    else:
    kind = self.__class__
    return kind(x, y)


    --
    Steven
    Steven D'Aprano, Dec 25, 2011
    #9
  10. On Mon, Dec 26, 2011 at 12:27 AM, Steven D'Aprano
    <> wrote:
    > There's nothing in the above that assumes that other has the same type as
    > self. It's just that the type of other is ignored, and the type of self
    > always wins. I find that a nice, clear rule: x.intersection(y) always
    > returns a point with the same type as x.


    The intersection of DrawableLine and DrawableLine is DrawablePoint.
    That's not the same type as either of the inputs. Same if you seek the
    intersection of two planes, which is a line - or two spheres, which is
    a circle (with possible failure if they don't intersect).

    ChrisA
    Chris Angelico, Dec 25, 2011
    #10
  11. On Mon, 26 Dec 2011 00:37:22 +1100, Chris Angelico wrote:

    > On Mon, Dec 26, 2011 at 12:27 AM, Steven D'Aprano
    > <> wrote:
    >> There's nothing in the above that assumes that other has the same type
    >> as self. It's just that the type of other is ignored, and the type of
    >> self always wins. I find that a nice, clear rule: x.intersection(y)
    >> always returns a point with the same type as x.

    >
    > The intersection of DrawableLine and DrawableLine is DrawablePoint.
    > That's not the same type as either of the inputs. Same if you seek the
    > intersection of two planes, which is a line - or two spheres, which is a
    > circle (with possible failure if they don't intersect).


    class Line:
    intersection_kind = Point
    def intersection(self, other):
    blah()
    return self.intersection_kind(a, b)

    class DrawableLine(Line):
    intersection_kind = DrawablePoint




    --
    Steven
    Steven D'Aprano, Dec 25, 2011
    #11
  12. On Mon, Dec 26, 2011 at 12:46 AM, Steven D'Aprano
    <> wrote:
    > class DrawableLine(Line):
    >    intersection_kind = DrawablePoint


    Ha! That works. I was sure there'd be some simple way to do it!

    ChrisA
    Chris Angelico, Dec 25, 2011
    #12
  13. (I'm sorry for my delayed response -- I've been travelling and not had
    reliable Internet access.)

    On 2011-12-25, Ian Kelly <> wrote:
    > On Thu, Dec 22, 2011 at 1:21 AM, Spencer Pearson
    ><> wrote:
    >> I see a problem with this, though. The intersection of two lines is
    >> (usually) an object of type Point. Since DrawableLine inherits from
    >> Line, this means that unless I redefine the "intersect" method in
    >> DrawableLine, the intersection of two DrawableLines will be a Point
    >> object, not a DrawablePoint. I don't want to saddle the user with the
    >> burden of converting every method output into its corresponding
    >> Drawable subclass, and I don't want to redefine every method to return
    >> an instance of said subclass. I see no other options if I continue
    >> down the subclassing path. Am I missing something?

    >
    > You could solve this with a factory. Instead of having
    > Line.intersection() create a Point directly, have it call
    > self.factory.create_point(). In the drawing module, replace the
    > factory for the subclasses with one that creates drawable classes
    > instead.


    Oh, that's a neat idea. Yes, I think that does exactly what I want!
    Thanks very much!

    > This will also work, but inheritance complicates things a
    > little. ...
    > ... Probably the easiest way to do this correctly is to follow the
    > MRO that Python has conveniently already built for you. Something
    > like:
    >
    > def draw(x, *args, **kwargs ):
    > for class_ in type(x).__mro__:
    > if class_ in draw_functions:
    > draw_functions[class_](*args, **kwargs)
    > break
    > else:
    > raise TypeError("don't know how to draw things of type "
    > "{0}".format(type(x)))


    You're right, you're right. My implementation was sloppy. I think I'll
    go with your factory solution, but thanks for the fixed version of
    draw() -- I've never seen __mro__ before, and it seems to be just the
    tool for this job!

    -Spencer
    Spencer Pearson, Jan 5, 2012
    #13
  14. On Dec 25 2011, 2:58 pm, Terry Reedy <> wrote:
    > On 12/24/2011 6:49 PM,SpencerPearsonwrote:
    >
    > > On Dec 23, 9:13 am, Terry Reedy<>  wrote:
    > >> On 12/22/2011 3:21 AM,SpencerPearsonwrote:

    >
    > >>> I'm writing a geometry package, with Points and Lines and Circles and
    > >>> so on, and eventually I want to be able to draw these things on the
    > >>> screen. I have two options so far for how to accomplish this, but
    > >>> neither of them sits quite right with me, and I'd like the opinion of
    > >>> comp.lang.python's wizened elders.

    >
    > >>> Option 1. Subclassing.
    > >>> The most Pythonic way would seem to be writing subclasses for the
    > >>> things I want to display, adding a ".draw(...)" method to each one,
    > >>> like this:

    >
    > There are people who would advocate a Drawable base class with a virtual
    > or abstract .draw method and that DrawablePoint, etc, inherit from
    > Drawable and Point.
    >
    > >>> Option 2. A "draw" function, with a function dictionary.

    >
    > >> Option 3? Add a draw method to existing classes, rather than subclassing?

    > > Thanks for the response! Do you mean something like this?
    > > class Point(GeometricObject):
    > >      def intersect(self, other):
    > >          ...

    >
    > I am interpreting this to mean that you have a world coordinate system
    > for instances that have location and size.
    >
    > >      def union(self, other):
    > >          ...
    > >      def draw(self, ...):
    > >          ...

    >
    > Yes. I would consider that Option 0, the default, unless you have good
    > reason to choose another. I would certainly include it on a list of options.
    >
    > > I'd like to avoid this, because... well, what I want is a geometry
    > > package, and it seems to me that whistles and bells like GUI support
    > > ought to be confined to subpackages. I'd look at this and think, "the
    > > rest of the Point class deals with fundamental geometric reality.
    > > What's this GUI method doing mixed in with my beautiful mathematical
    > > purity?"

    >
    > By default, all Python objects have a text representation method. I do
    > not see that giving all concrete geometric objects (with a location and
    > size) a visual representation is much different. I would use drawing
    > functions that accept the coordinates and distances of your geometry
    > world and translate to low-level pixel functions for a particular gui
    > system. I agree that your geometrical objects should not know about
    > pixels, screens, windows, and aspect ratios.
    >
    >  > Is this the wrong attitude to take?
    >
    > It depends on *your* goal and values.
    >
    > > Or did you mean this?
    > > In file "geometry/gui.py":
    > > def draw_point(point, ...):
    > >      ...
    > > Point.draw = draw_point

    >
    > > I've never modified an existing class before, and I fear the
    > > unfamiliar. If that's what you meant... it's really an acceptable
    > > thing to do?

    >
    > Yes, in my opinion. The advantage of this is putting all the draw
    > methods together, and possibly having more than one one set. On the
    > other hand, one needs to know the data attributes of each class to
    > understand its draw method.
    >
    > > It seems like somebody might see "some_point.draw(...)"
    > > and be confused by the method's absence in the Point class definition.

    >
    > With either suboption, you should put an abstract .draw method in the
    > GeometricObject base class.
    >
    > I would look at various game, graph, geometry, and gui packages handle
    > drawing for more ideas.
    >
    > --
    > Terry Jan Reedy


    (I'm sorry for my delayed response -- I've been travelling and not had
    reliable Internet access.)

    On 2011-12-25, Terry Reedy <> wrote:
    > There are people who would advocate a Drawable base class with a virtual
    > or abstract .draw method and that DrawablePoint, etc, inherit from
    > Drawable and Point.


    Yes... yes, that makes sense to me.

    > By default, all Python objects have a text representation method. I do
    > not see that giving all concrete geometric objects (with a location and
    > size) a visual representation is much different. I would use drawing
    > functions that accept the coordinates and distances of your geometry
    > world and translate to low-level pixel functions for a particular gui
    > system. I agree that your geometrical objects should not know about
    > pixels, screens, windows, and aspect ratios.


    Ha! Oh, I've been being silly. I was going to claim that since there
    is no standard Python GUI, I ought not chain myself to any one of the
    candidates. Then I learned that Tkinter comes standard with Python.
    Oops.

    All right, now that I know that, the comparison to having a text
    representation seems very reasonable. I'll definitely reconsider
    making the draw() method a requirement for all GeometricObjects.

    >> I've never modified an existing class before, and I fear the
    >> unfamiliar. If that's what you meant... it's really an acceptable
    >> thing to do?

    >
    > Yes, in my opinion. The advantage of this is putting all the draw
    > methods together, and possibly having more than one one set. On the
    > other hand, one needs to know the data attributes of each class to
    > understand its draw method.
    >
    >> It seems like somebody might see "some_point.draw(...)"
    >> and be confused by the method's absence in the Point class definition.

    >
    > With either suboption, you should put an abstract .draw method in the
    > GeometricObject base class.


    Sure, sure. I'm comfortable with this way of doing things now. Thanks
    so much for all your help!

    -Spencer
    Spencer Pearson, Jan 5, 2012
    #14
  15. (I'm sorry for my delayed response -- I've been travelling and not had
    reliable Internet access.)

    >> Spencer, i would re-think this entire project from the
    >> beginning. You are trying to make an object out of everything. You
    >> don't need to make an object of EVERYTHING.

    >
    > Very true.


    I'm not sure I understand. Surely you're not both saying that I
    shouldn't write a Point class? Here's an expression I'd like very
    much to be able to type:

    sphere1.intersect(sphere2).rotated(angle, axis)

    If I represented points with something already defined, maybe a tuple
    or a numpy array, then that would risk that the spheres were tangent,
    that their intersection was not a Circle (a GeometricObject, with a
    ..rotated method), but a point (a tuple, without one).

    On 2011-12-25, Steven D'Aprano <>
    wrote:
    > class Line:
    > intersection_kind = Point
    > def intersection(self, other):
    > blah()
    > return self.intersection_kind(a, b)
    >
    > class DrawableLine(Line):
    > intersection_kind = DrawablePoint


    If I objected that the intersection of two Lines might, once in a blue
    moon, be a Line (because they're the same line), this seems like it
    would edge towards the factory solution that Ian Kelly suggested
    (i.e. not "return self.intersection_kind(...)", but "return
    self.factory.create_point(...)" or something similar). Is that so?

    -Spencer
    Spencer Pearson, Jan 5, 2012
    #15
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Marco
    Replies:
    3
    Views:
    329
    Marco
    Oct 12, 2003
  2. golem
    Replies:
    13
    Views:
    762
    Nigel Wade
    Feb 17, 2006
  3. nrm
    Replies:
    3
    Views:
    512
  4. Replies:
    0
    Views:
    171
  5. Phat G5 (G3)

    Adding new methods to existing classes

    Phat G5 (G3), Aug 27, 2007, in forum: Javascript
    Replies:
    18
    Views:
    180
    David Golightly
    Aug 28, 2007
Loading...

Share This Page