oo problem

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Tool69

    #1

    oo problem

    Hi,
    I've got a simple but difficult problem :

    Suppose I've got a Paper class, on wich I can draw i.e a rectangle, a
    circle or whatever.

    class Paper(...):
    def __init__(self, paperx, papery):
    self.paperx = paperx
    self.papery = papery
    ....
    def draw(self, Primitive_Objec t):
    ....
    class Rectangle( ): <--- a Primitive_Objec t
    ...

    Now, inside my Rectangle class, I need to recover the Paper instance
    who called it (because I need the paper sizes to calculate something).
    I now I can use a global variable, say " _paper" and then, inside my
    Paper.__init__( ) write something like this :

    global _paper
    _paper = [paperx,papery]

    But it has drawbacks : what if I've got several Paper instances ?

    I don't know if I'm clear enought,
    Thanks for your help :
    6TooL9

  • Nils Oliver Kröger

    #2
    Re: oo problem

    -----BEGIN PGP SIGNED MESSAGE-----
    Hash: SHA1

    Hi,

    many class libraries use a parent attribute for this purpose:

    class Rectangle (object):
    __init__(self, parent):
    #Use the parent as "private": nobody except your own #class should
    mess around with it ...
    self._parent = parent

    The parent of course needs to be an existing Paper instance.

    You might check whether the given value for parent is indeed a Paper
    instance in your Rectangle's __init__, otherwise you might get strange
    AttributeError exceptions when using the parent later.

    Hope that helps!

    Nils


    -----BEGIN PGP SIGNATURE-----
    Version: GnuPG v1.4.2.2 (GNU/Linux)
    Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

    iD8DBQFFe+SyRQe uB6ws8wERAuTOAK CPKe8m9BNP7Vf/aFpJSWTfOkF8pQC gvkxG
    +xmcU+UB7fT0fi8/Jz+o15E=
    =pW+u
    -----END PGP SIGNATURE-----

    Comment

    • Kay Schluehr

      #3
      Re: oo problem

      Tool69 schrieb:
      Hi,
      I've got a simple but difficult problem :
      >
      Suppose I've got a Paper class, on wich I can draw i.e a rectangle, a
      circle or whatever.
      >
      class Paper(...):
      def __init__(self, paperx, papery):
      self.paperx = paperx
      self.papery = papery
      ....
      def draw(self, Primitive_Objec t):
      ....
      class Rectangle( ): <--- a Primitive_Objec t
      ...
      >
      Now, inside my Rectangle class, I need to recover the Paper instance
      who called it (because I need the paper sizes to calculate something).
      You can simply pass a paper reference to a rectangle object. But better
      you pass only the information to the rectangle that is necessary,
      because you decouple the objects this way:

      class Rectangle:
      def __init__(self):
      self.paper_coor dinates = [0,0] # default value

      class Paper:
      ...
      def draw(self, shape):
      shape.paper_coo rdinates = self.x, self.y
      shape.draw()
      ...

      Comment

      • Tool69

        #4
        Re: oo problem

        Thanks for your answers,
        I though about the first solution too, but I've redundant code, say ie:
        p = Paper(100,200)
        p.draw( Rectangle(p,10, 20,50,60) ) <-- we're forced to write 'p' two
        times.

        But that maybe the best solution, as I cannot see anything else.

        For the second one, I need to make some calculus on the shape to be
        drawn, so if I write:

        shape.paper_coo rdinates = self.x, self.y
        shape.draw()

        It's too late, the calculus have already been done with the default
        values, right or not?

        Thanks,
        6TooL9

        Comment

        • James Stroud

          #5
          Re: oo problem

          Tool69 wrote:
          Hi,
          I've got a simple but difficult problem :
          >
          Suppose I've got a Paper class, on wich I can draw i.e a rectangle, a
          circle or whatever.
          >
          class Paper(...):
          def __init__(self, paperx, papery):
          self.paperx = paperx
          self.papery = papery
          ....
          def draw(self, Primitive_Objec t):
          ....
          class Rectangle( ): <--- a Primitive_Objec t
          ...
          >
          Now, inside my Rectangle class, I need to recover the Paper instance
          who called it (because I need the paper sizes to calculate something).
          I now I can use a global variable, say " _paper" and then, inside my
          Paper.__init__( ) write something like this :
          >
          global _paper
          _paper = [paperx,papery]
          >
          But it has drawbacks : what if I've got several Paper instances ?
          >
          I don't know if I'm clear enought,
          Thanks for your help :
          6TooL9
          >
          I think you may not be thinking about your problem in the most
          object-oriented way. For example, the Paper.draw() method will already
          have a reference to the "calling" Paper instance accessible via the name
          "self". E.g.:

          class Paper(...
          def draw(self, primitive):
          do_something_wi th(self.paperx, self.papery)
          # etc

          Now, if the draw() method were in the primitive and not the paper, then
          a reference to the paper should be kept in the primitive. But, as you
          will see below, this seems to make little sense (to me, at least).

          If you find that you need to access the primitive's "parent" paper
          attributes from within the primitive, then you might want to check
          whether you have structured your code in the most sensible manner.
          Conceptually, children shouldn't be overly concerned with the workings
          of their parents, lest they be a bit too presumptuous and risk a good
          scolding.

          The thought process I always go through is "why does this object need to
          have this particular reference?" Do primitives really need to know
          anything about the paper on which they are drawn?

          I try not to make objects overly reflexive. For example, should a
          primitive really be drawing itself? Perhaps something else should bring
          a primitive into existence based on the attributes contained in a
          primitive's data structure and the properties of the medium in which or
          on which it will exist.

          What if some creator had asked of you: "Embed Thyself unto the 3-D
          Manifold Known as the Universe." Your first requirement before any steps
          toward physical existence would, of course, be a reference to the
          Universe--so that you could see if you would actually fit.

          Perhaps it would be better for a 3rd party to manage the process of
          person creation, like, say, a mother? Children would then not be
          required to ponder the extent of the Universe before their own physical
          manifestation and could focus on things more meaningful to themselves,
          like whether they are hungry or need to go potty.

          By this thought process, I propose that it makes more sense to create a
          Drawing object that has references to both the primitives and the paper
          and then manage drawing through that object.

          class Drawing(object) :
          def __init__(self, paper, primitives):
          self._paper = paper
          self._primitive s = primitives

          my_primitives = [Square(5), Circle(10), DoubleEndedArro w(5,5,5,1,2,1,2 )]
          my_paper = Paper()
          my_drawing = Drawing(my_pape r, my_primitives)

          Now the paper can just worry about its paper specific attributes (which
          might be its dimensions, border, bond weight, etc), the primitives can
          worry about primitive specific attributes (size, line-width,
          fill-color), and the drawing can manage everything required to make a
          drawing (paper, primitives, color model, etc.).

          I think that this is the what you were getting at with your global
          "_paper" variable, except now "global" is the context of the Drawing class.

          James

          Comment

          • Tool69

            #6
            Re: oo problem

            Thanks James,

            It was a matter of choice : in my earlier version, all primitives know
            how to draw themselves, but they needed to have a parent and I found it
            was not good for aesthetic reasons.

            but I think I've been misunderstood. Let's take a concrete sample :

            I've got a Paper instance(-5,5,5,5) (the coordinates of lower-left and
            upper-right rectangle: xlowleft, ylowlef, xupright, yupright) of my
            paper.
            I want now to draw an x-axis on it with some ticks and maybe lables, I
            need to catch the xlowleft and xupright variables of the Paper inside
            my primitive, ok ?
            The problem lies inside my primitive, not on the draw method.
            Here's a simplified example, I need to retrieve paper.xll and
            paper.xur:

            class Graduate_x( primitive ):
            def __init__(self, orient = 'se', xorigin = 0, yorigin=0, xunit=
            1.0, yunit=1.0):
            primitive.__ini t__(self)
            for k in range( int(math.floor( ( paper.xll - xorigin)/xun)),
            int(math.floor( (paper.xur-xorigin)/yun)) ):
            ...something to construct my path

            Comment

            • Nils Oliver Kröger

              #7
              Re: oo problem

              -----BEGIN PGP SIGNED MESSAGE-----
              Hash: SHA1

              Tool69 wrote:
              It was a matter of choice : in my earlier version, all primitives know
              how to draw themselves, but they needed to have a parent and I found it
              was not good for aesthetic reasons.
              Why should a parent reference not be aesthetic? OOD is all about Objects
              and their relationships.

              I want now to draw an x-axis on it with some ticks and maybe lables, I
              need to catch the xlowleft and xupright variables of the Paper inside
              my primitive, ok ?
              This sentence describes the relationship between the paper and your
              Rectangle (to stick to your first example) as an association:

              The Rectangle needs to access information from the Paper. Moreover, the
              relationship could be named "Rectangle lies on Paper" this is perfect
              OOD in my opinion.

              -----BEGIN PGP SIGNATURE-----
              Version: GnuPG v1.4.2.2 (GNU/Linux)
              Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

              iD8DBQFFfGPmRQe uB6ws8wERAgBgAK CiNlNU5vuVmUQQW y/Trqv2/hfd2gCg39Sh
              WC2+yoWA+lpJ4PN Q1sfiFTU=
              =UIww
              -----END PGP SIGNATURE-----

              Comment

              • James Stroud

                #8
                Re: oo problem

                Tool69 wrote:
                Thanks James,
                >
                It was a matter of choice : in my earlier version, all primitives know
                how to draw themselves, but they needed to have a parent and I found it
                was not good for aesthetic reasons.
                >
                but I think I've been misunderstood. Let's take a concrete sample :
                >
                I've got a Paper instance(-5,5,5,5) (the coordinates of lower-left and
                upper-right rectangle: xlowleft, ylowlef, xupright, yupright) of my
                paper.
                I want now to draw an x-axis on it with some ticks and maybe lables, I
                need to catch the xlowleft and xupright variables of the Paper inside
                my primitive, ok ?
                The problem lies inside my primitive, not on the draw method.
                Here's a simplified example, I need to retrieve paper.xll and
                paper.xur:
                >
                class Graduate_x( primitive ):
                def __init__(self, orient = 'se', xorigin = 0, yorigin=0, xunit=
                1.0, yunit=1.0):
                primitive.__ini t__(self)
                for k in range( int(math.floor( ( paper.xll - xorigin)/xun)),
                int(math.floor( (paper.xur-xorigin)/yun)) ):
                ...something to construct my path
                >
                You can simply pass the paper to the __init__ method and even store a
                reference to the paper there if you have to re-construct the path later,
                say if the paper size changes or the origins of the primitive change. I
                wouldn't advise storing references to the primitives in the paper as
                well, because you would get circular references.

                Global variables are probably not the way to handle this. For OO, if you
                feel like you need a global variable, try to think up an object that can
                sensibly contain all the objects that would be global.

                James

                Comment

                • Tool69

                  #9
                  Re: oo problem


                  Dennis Lee Bieber a écrit :
                  On 10 Dec 2006 03:47:21 -0800, "Tool69" <kibleur.christ ophe@gmail.com>
                  declaimed the following in gmane.comp.pyth on.general:
                  >
                  Thanks for your answers,
                  I though about the first solution too, but I've redundant code, say ie:
                  p = Paper(100,200)
                  p.draw( Rectangle(p,10, 20,50,60) ) <-- we're forced to write 'p' two
                  times.
                  >
                  I'd suggest not passing an instance initialization to your "Paper"
                  draw() method...
                  >
                  p = Paper(100, 200)
                  p.add(Rectangle (10, 20, 50, 60))
                  p.add(OtherPrim itives())
                  p.draw()
                  >
                  where p.draw() (Paper.draw(sel f) really) does something like:
                  >
                  self.whatever_i s_needed_for_Pa per_itself
                  for prm = self.primitives : #list of stuff from p.add(...) calls
                  prm.draw(self) #pass current paper to the primitive
                  #which draws itself on the paper
                  #and can do whatever calculations
                  #(CLIPPING perhaps) needed
                  Thanks for all your comments and suggestions.
                  Denis, I would like to know how I can made a draw method for a
                  primitive without a Paper instance inside ...that's always the same
                  problem as only my Paper instance knows the Paper sizes !

                  Comment

                  • Tool69

                    #10
                    Re: oo problem


                    Dennis Lee Bieber a écrit :
                    >
                    Perhaps you missed that the loop (in Paper) that invokes each
                    primitive's draw() is passing itself (the Paper instance)...
                    >
                    Oops, sorry I missed it in fact.

                    But I still have a problem with my the primitives (some pathes I had to
                    build ):
                    i.e a mathematical ray is infinite, so I must draw a segment on screen
                    and need the paper sizes to calculate the segments starts and ends (
                    I've got a lot of objects like this ). I don't know how to build them
                    without passing a paper instance.
                    The actual implementation of some primitives uses :

                    def __init__(self, paper_instance, etc. ):
                    do something

                    But I as mentioned before, I'm not satisfied with it since I shall
                    write this do draw a Line :*
                    paper.draw( Line( paper, x1, y1, x2, y2) This is what I don't find
                    aesthetic : the repetition of "paper" calls.

                    Comment

                    • Bruno Desthuilliers

                      #11
                      Re: oo problem

                      Tool69 a écrit :
                      Hi,
                      I've got a simple but difficult problem :
                      >
                      Suppose I've got a Paper class, on wich I can draw i.e a rectangle, a
                      circle or whatever.
                      >
                      class Paper(...):
                      def __init__(self, paperx, papery):
                      self.paperx = paperx
                      self.papery = papery
                      ....
                      def draw(self, Primitive_Objec t):
                      ....
                      class Rectangle( ): <--- a Primitive_Objec t
                      ...
                      >
                      Now, inside my Rectangle class, I need to recover the Paper instance
                      who called it (because I need the paper sizes to calculate something).
                      I now I can use a global variable, say " _paper" and then, inside my
                      Paper.__init__( ) write something like this :
                      >
                      global _paper
                      _paper = [paperx,papery]
                      >
                      But it has drawbacks :
                      Indeed...
                      what if I've got several Paper instances ?
                      class Paper(...):
                      ....
                      def draw(self, drawable):
                      drawable.draw(s elf)

                      class Rectangle( ): <--- a drawable
                      ...
                      def draw(self, drawing_surface ):
                      ...

                      Now consider whether you really need Paper.draw...

                      HTH

                      Comment

                      • tool69

                        #12
                        Re: oo problem

                        Hi,
                        First, let me thanks you for all your clear comments.

                        >
                        This is, in my mind, both a usage and a design flaw.
                        >
                        You are creating (and throwing away) instances of drawable
                        objects to the draw method of a paper instance. But what does
                        paper.draw() actually do with the drawable object? Call a draw method
                        within it?
                        No, actually the paper instance is a subclass of a canvas from an
                        external module. And this one have a stroke() method.
                        In reading your comments, I think it's now clear that I must get back
                        and let any primitive have an inner draw() method ( a subclass of
                        Drawable object in our case).
                        If so, that is when you should pass the paper instance (or
                        just the part needed -- clipping rectangle perhaps?).
                        In fact, my approach was a bad one : in initialising the paper instance,
                        I was already clipping it.
                        If I wrote : p = Paper(-5,-5,5,5), all drawings made on that paper will
                        be clipped inside a rectangle with lower-left corner (-5,-5) and
                        upper-right corner (5,5).
                        Now, I think it's better to clip after all primitives have been added to
                        the paper.
                        >
                        The actual implementation of draw() for each primitive will have
                        to handle clipping to the boundaries of the Canvas object that is passed
                        to it.
                        >
                        You'll notice that the only place the primitive needs to know
                        about the canvas is in its specific draw method. And only at that time
                        is the canvas (paper) passed to it.
                        >
                        Instead of the concept;
                        >
                        Paper, draw a line from x to y
                        >
                        (and having to pass the "paper" to the initializer of the line
                        primitive), you have to think in terms of:
                        >
                        Line, draw yourself on this paper
                        >
                        Or, if you consider the last example above… Compare that to your
                        example:
                        >
                        -=-=-=-=-
                        paper.draw( Line( paper, x1, y1, x2, y2) )
                        -=-=-=-=-=-
                        >
                        Here, you are telling the paper to do the drawing, and passing
                        it a Line instance (and passing it the paper it is supposed to be drawn
                        on). Why? The paper isn't drawing the line on itself… While
                        >
                        -=-=-=-=-
                        Line(Point(x1, y1), Point(x2, y2)).draw(paper )
                        -=-=-=-=-
                        >
                        initializes a Line instance, then asks it to draw itself using paper as
                        the surface to be drawn upon.
                        Yes I was wrong, that's all clear now.
                        Thanks again, this was very helpfull.

                        6TooL9

                        Comment

                        Working...