A problem with some OO code.

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

    #1

    A problem with some OO code.

    Help me please, because I really don't get it. I think it's some stupid
    mistake I make, but I just can't find it. I have been thinking about it
    for three days so far and I still haven't found any solution.

    My code can be downloaded from here:
    http://www.tprimke.net/konto/PyObject-problem.tar.bz2. There are some
    scripts for GNU/Linux system (bash to be precise).

    All you need to know is that there are four classes. (Of course, you
    may generate all the documentation by typing just "./make_docs". All
    you need is Python with Epydoc installed.)

    In the PyObject.py there are two classes: Object and OManager. When
    Object wants to know if some link is safe (in another words: it wants
    to know if some another object exists), it calls the proper method of
    its objects' manager (the OManager instance). Details are not important
    here, so I'll just say, that if the link is safe, the objects' manager
    calls the proper method of the object, that sent him request. This
    method of the object just stores the information about that link (that
    it's safe), in the so-called private field (the fields used to store
    the information about the links are called __ls_existing_l inks and
    __ls_demanded_l inks).

    And now the tests. In the test.py file this is a class called Obj. That
    class is just an Object. This is also a class called System1 - this
    class is used only to create a more complex system composed of many
    objects and one objects' manager.

    You can run all the tests by just typing "./test" in console (or a
    terminal emulator). I'm still getting the same error:

    --------------------------------------------------
    Traceback (most recent call last):
    File "test.py", line 142, in test04CreateSys tems
    system1 = System1()
    File "test.py", line 81, in __init__
    self.objA.deman dNewLink( 'B' )
    File "/home/tpj/opt/Praca/Programy/PyObject/workdir/PyObject.py",
    line 503, in demandNewLink
    s_object )
    File "/home/tpj/opt/Praca/Programy/PyObject/workdir/PyObject.py",
    line 800, in _makeNewLink
    o_srcobj._makeL inkSafe( s_target )
    File "/home/tpj/opt/Praca/Programy/PyObject/workdir/PyObject.py",
    line 608, in _makeLinkSafe
    self.__makeLink Safe( s_object )
    File "/home/tpj/opt/Praca/Programy/PyObject/workdir/PyObject.py",
    line 582, in __makeLinkSafe
    i = self.__ls_deman ded_links.index ( s_object )
    AttributeError: 'Obj' object has no attribute
    '_Object__ls_de manded_links'
    --------------------------------------------------

    Perhaps I'll explain what's going on there. First, the objects' manager
    is created, and then also some objects are created. After doing that,
    the object called "objA" demands a new link to the other object, called
    "objB" (this is the line 81 in the error message above). As the result,
    the "demandNewL ink" method of the object "objA" is called. This method
    calls the "_makeNewLi nk" method of the objects' manager, and this
    method calls the "_makeLinkS afe" method of the object, that demanded a
    new link. The last method, called "__makeNewL ink" (so this is a
    so-called private method), is called then. This last method is supposed
    to check if the link was really demanded and then make it "safe" by
    placing the information about this link in the proper dictionary
    (__ls_existing_ links).

    All these methods are the methods of the Object class (defined in
    PyObject.py), not of the Obj class (defined in test.py). According to
    my knowledge about the OO programming Python should be able to realize,
    that the so-called private fields, that are being referred from these
    Object class methods, are the private fields of the *Obj class
    instance*, not of the *Object class one*.

    I even wrote a simple program to test the usage of the so-called
    private fields in Python classes:

    --------------------------------------------------
    class A( object ):
    def __init__( self ):
    self.__a = 1
    def _add( self ):
    print "self.__a =", self.__a
    self.__a += 1
    def print_a( self ):
    print self.__a

    class B( A ):
    def __init__( self ):
    A.__init__( self )
    self.__b = 2
    def print_b( self ):
    print self.__b

    def test():
    o = B()
    o.print_a()
    o.print_b()
    o._add()
    o.print_a()
    o.print_b()
    --------------------------------------------------

    The code works just as I thought it should work: all is fine here. The
    B class instance (the b object) is able to refer to the so-called
    private field of the A class (through a A-class method, that was
    inherited by the class B).

    Why I can't do the same thing in test.py and in PyObject.py?

    I just don't get it.

    (And sorry for the subject of this topic. I really had no better
    idea...)

  • Diez B. Roggisch

    #2
    Re: A problem with some OO code.

    > AttributeError: 'Obj' object has no attribute[color=blue]
    > '_Object__ls_de manded_links'
    > --------------------------------------------------
    >
    > Perhaps I'll explain what's going on there. First, the objects' manager
    > is created, and then also some objects are created. After doing that,
    > the object called "objA" demands a new link to the other object, called
    > "objB" (this is the line 81 in the error message above). As the result,
    > the "demandNewL ink" method of the object "objA" is called. This method
    > calls the "_makeNewLi nk" method of the objects' manager, and this
    > method calls the "_makeLinkS afe" method of the object, that demanded a
    > new link. The last method, called "__makeNewL ink" (so this is a
    > so-called private method), is called then. This last method is supposed
    > to check if the link was really demanded and then make it "safe" by
    > placing the information about this link in the proper dictionary
    > (__ls_existing_ links).
    >
    > All these methods are the methods of the Object class (defined in
    > PyObject.py), not of the Obj class (defined in test.py). According to
    > my knowledge about the OO programming Python should be able to realize,
    > that the so-called private fields, that are being referred from these
    > Object class methods, are the private fields of the *Obj class
    > instance*, not of the *Object class one*.[/color]

    I didn't find any place where you create your __ls_demanded_l inks-list.
    So - how do you expevct it to be found, __-semantics or not?

    But I _did_ find a self.__ls_deman dedLinks. So I guess you got confused
    in your variable names.


    After changing that, I got some other errors.

    So basically this boils down to some simple spelling errors. You migt
    want to think about using pychecker or pylint or both, and a
    auto-completion-capable editor like eric or (x)emacs.

    Diez

    Comment

    • Steven D'Aprano

      #3
      Re: A problem with some OO code.

      On Sat, 04 Feb 2006 04:21:50 -0800, TPJ wrote:
      [color=blue]
      > Help me please, because I really don't get it. I think it's some stupid
      > mistake I make, but I just can't find it. I have been thinking about it
      > for three days so far and I still haven't found any solution.
      >
      > My code can be downloaded from here:
      > http://www.tprimke.net/konto/PyObject-problem.tar.bz2. There are some
      > scripts for GNU/Linux system (bash to be precise).[/color]

      Hint: when asking strangers to help you, at THEIR time and expense, with
      no offer to recompense them for their efforts, it is up to YOU to make
      their job as easy as possible.

      That means don't expect people to download some untrusted, potentially
      dangerous, piece of code from a stranger on Usenet, go to the trouble of
      extracting it from an archive, and then debug it for you.

      You need to simplify the code as much as possible, cutting away everything
      you can, to the SMALLEST amount of code that still experiences the problem.

      I've made some comments based on the information in your post. If they
      don't help, you will need to spend some time creating a short example that
      has the same problem. There is very little point in showing us test code
      that works -- your problem isn't with code that works, it is with code
      that doesn't work.

      [color=blue]
      > All you need to know is that there are four classes.[/color]

      No, I'm sure we need to know much more than that.

      [color=blue]
      > (Of course, you
      > may generate all the documentation by typing just "./make_docs". All
      > you need is Python with Epydoc installed.)[/color]

      Oh right, well just let me rush off and install Epydoc just for you, okay?


      [color=blue]
      > In the PyObject.py there are two classes: Object and OManager. When
      > Object wants to know if some link is safe (in another words: it wants
      > to know if some another object exists),[/color]

      What is a link in your application? What do you mean "another object"?
      Like an int or a string?

      This is the normal Python idiom for testing whether an object exists
      (strictly speaking, whether a name is bound to an object).

      try:
      some_object
      except NameError:
      print "some_objec t does not exist"

      Is that what you mean?


      [color=blue]
      > it calls the proper method of
      > its objects' manager (the OManager instance). Details are not important
      > here,[/color]

      I bet the details are absolutely vital.

      [color=blue]
      > so I'll just say, that if the link is safe, the objects' manager
      > calls the proper method of the object, that sent him request. This
      > method of the object just stores the information about that link (that
      > it's safe), in the so-called private field (the fields used to store
      > the information about the links are called __ls_existing_l inks and
      > __ls_demanded_l inks).[/color]

      This is a terribly involved way of doing it, and I'm not even sure what
      "it" is that you are trying to do. Are you trying to do some sort of
      dispatch mechanism?

      I see you have a line "i = self.__ls_deman ded_links.index ( s_object )". It
      looks like you are storing your data in a chunk of text, and then running
      index on that text to find the bit you want to work with. If you wanted to
      do that much work, just write your script in bash and be done with it!
      Python has lists and dicts and other advanced data structures. Use them.
      You will be glad.


      [color=blue]
      > And now the tests. In the test.py file this is a class called Obj. That
      > class is just an Object.[/color]

      So Obj is an alias for Object? What's an Object? Is it the same as the
      Python built-in type "object"?

      But later on you say:

      "All these methods are the methods of the Object class (defined in
      PyObject.py), not of the Obj class (defined in test.py)."

      So Object and Obj are not the same.


      [color=blue]
      > This is also a class called System1 - this
      > class is used only to create a more complex system composed of many
      > objects and one objects' manager.
      >
      > You can run all the tests by just typing "./test" in console (or a
      > terminal emulator). I'm still getting the same error:
      >
      > --------------------------------------------------
      > Traceback (most recent call last):
      > File "test.py", line 142, in test04CreateSys tems
      > system1 = System1()
      > File "test.py", line 81, in __init__
      > self.objA.deman dNewLink( 'B' )
      > File "/home/tpj/opt/Praca/Programy/PyObject/workdir/PyObject.py",
      > line 503, in demandNewLink
      > s_object )
      > File "/home/tpj/opt/Praca/Programy/PyObject/workdir/PyObject.py",
      > line 800, in _makeNewLink
      > o_srcobj._makeL inkSafe( s_target )
      > File "/home/tpj/opt/Praca/Programy/PyObject/workdir/PyObject.py",
      > line 608, in _makeLinkSafe
      > self.__makeLink Safe( s_object )
      > File "/home/tpj/opt/Praca/Programy/PyObject/workdir/PyObject.py",
      > line 582, in __makeLinkSafe
      > i = self.__ls_deman ded_links.index ( s_object )
      > AttributeError: 'Obj' object has no attribute
      > '_Object__ls_de manded_links'[/color]

      [snip]
      [color=blue]
      > Perhaps I'll explain what's going on there. First, the objects' manager
      > is created, and then also some objects are created. After doing that,
      > the object called "objA" demands a new link to the other object, called
      > "objB" (this is the line 81 in the error message above).[/color]

      Your description does not match what line 81 actually says. It says:

      self.objA.deman dNewLink('B')

      self (an instance of System1, not Obj or Object) grabs the attribute
      called "objA", and calls its method demandNewLink with an argument of
      the string 'B', not objB an instance of Obj or Object.

      (Aside: generic names like "Obj" or "Object" are poor practice unless they
      genuinely are generic. A good name should be self-documenting if possible,
      but more importantly, names which are easy to confuse like Obj and Object
      should be avoided.)

      If you want to work with Object instances, why not just use them instead
      of passing around strings that represent them?


      [color=blue]
      > As the result,
      > the "demandNewL ink" method of the object "objA" is called. This method
      > calls the "_makeNewLi nk" method of the objects' manager, and this
      > method calls the "_makeLinkS afe" method of the object, that demanded a
      > new link. The last method, called "__makeNewL ink" (so this is a
      > so-called private method), is called then.[/color]

      This seems like a very brittle way to code.
      [color=blue]
      > This last method is supposed
      > to check if the link was really demanded and then make it "safe" by
      > placing the information about this link in the proper dictionary
      > (__ls_existing_ links).[/color]

      Huh? Do you mean that there is a way for links (whatever they are) to be
      requested without calling demandNewLink? How would this happen?

      [color=blue]
      > All these methods are the methods of the Object class (defined in
      > PyObject.py), not of the Obj class (defined in test.py). According to
      > my knowledge about the OO programming Python should be able to realize,
      > that the so-called private fields, that are being referred from these
      > Object class methods, are the private fields of the *Obj class
      > instance*, not of the *Object class one*.[/color]

      Some serious confusion here.

      What are fields? Do you mean attributes? I'm going to assume that you do.

      Would it help if I told you that Python doesn't have private attributes?
      It *simulates* private attributes using name mangling.

      Thus:

      class Parrot:
      __plumage = "red"

      actually creates a class attribute "_Parrot__pluma ge". If you know the
      name of the class, you can bypass Python's "private attributes".

      PLEASE don't bother to tell us how Python sucks because it doesn't have
      "real private attributes", we've heard the arguments (and the abuse) fifty
      times before.

      Now, the consequences:

      When Python does a lookup, it looks in the appropriate namespace for a
      name. Except for special rules relating to inheritance, Python doesn't
      magically look up attributes in another object's namespace just because
      that attribute was defined as a private attribute elsewhere. See below for
      the consequences.


      [color=blue]
      > I even wrote a simple program to test the usage of the so-called
      > private fields in Python classes:[/color]

      Good. Now how about getting a simple program that demonstrates your
      problem?

      [color=blue]
      > class A( object ):
      > def __init__( self ):
      > self.__a = 1
      > def _add( self ):
      > print "self.__a =", self.__a
      > self.__a += 1
      > def print_a( self ):
      > print self.__a[/color]

      Do you enjoy all this make-work, writing tedious methods to get or set or
      print attributes? I suggest you ditch all the private attributes and just
      make them public. You've already spent three days hitting your head
      against a brick wall because of excessive data-hiding. Was it worth it?
      Python is a language that encourages the attitude "We're all adults here"
      -- getters/setters are discouraged.


      [color=blue]
      > class B( A ):
      > def __init__( self ):
      > A.__init__( self )
      > self.__b = 2
      > def print_b( self ):
      > print self.__b
      >
      > def test():
      > o = B()
      > o.print_a()
      > o.print_b()
      > o._add()
      > o.print_a()
      > o.print_b()[/color]

      I don't think this is showing what you think it is showing. Private vs
      public attributes just get in the way: they work *exactly* the same in
      Python except for name mangling. This is the problem bit:

      class B( A ):
      def __init__( self ):
      A.__init__( self ) ### LOOK HERE

      You aren't creating an A instance here, you are calling A.__init__ with a
      first argument of "self", which is a B instance. __init__ does not create
      instances, it runs AFTER the instance is already created.

      Perhaps you already know that. But I don't think you understand the
      consequences of this, when using so-called private attributes:

      The call to A.__init__ creates an attribute __a to self. Remember, self is
      an instance of B (not A). Apply the name-mangling rules, which are applied
      at compile time: the code in A's method mangles __a to _A__a. So
      A.__init__ creates an attribute _A__a in B's namespace. So B has two
      attributes, _A__a and _B__b.

      That means that B methods that access self.__b will work, because the name
      mangling rules work *with you*, and self.__b is mangled to self._B__b. But
      B methods that access self.__a will NOT work, because it is mangled to
      self._B__a, and that attribute does not exist.

      (However, that is not your problem.)

      [color=blue]
      > The code works just as I thought it should work: all is fine here.[/color]

      Except it is brittle and hard to maintain.
      [color=blue]
      > The
      > B class instance (the b object) is able to refer to the so-called
      > private field of the A class (through a A-class method, that was
      > inherited by the class B).
      >
      > Why I can't do the same thing in test.py and in PyObject.py?[/color]

      Here is your exception again:
      [color=blue]
      > line 582, in __makeLinkSafe
      > i = self.__ls_deman ded_links.index ( s_object )
      > AttributeError: 'Obj' object has no attribute
      > '_Object__ls_de manded_links'[/color]

      This is not making sense to me. If self is an instance of Obj, the
      name-mangling rules will convert self.__ls_deman ded_links to
      self._Obj__ls_d emanded_links. The only thing I can guess is that somehow,
      somewhere, you have tried to manually set the class of an object.

      Something like this perhaps?
      [color=blue][color=green][color=darkred]
      >>> class Obj:[/color][/color][/color]
      .... __bar = "nothing"
      ....[color=blue][color=green][color=darkred]
      >>> class Object(Obj):[/color][/color][/color]
      .... __foo = "something"
      .... def foo(self):
      .... print self.__foo
      .... def bar(self):
      .... print self.__bar
      ....[color=blue][color=green][color=darkred]
      >>> x = Object()
      >>> x.__class__.__n ame__ = "Obj"
      >>> x.foo()[/color][/color][/color]
      something[color=blue][color=green][color=darkred]
      >>> x.bar()[/color][/color][/color]
      Traceback (most recent call last):
      File "<stdin>", line 1, in ?
      File "<stdin>", line 6, in bar
      AttributeError: Obj instance has no attribute '_Object__bar'

      That's the only way I can think of to get such an unusual error.



      --
      Steven.

      Comment

      • TPJ

        #4
        Re: A problem with some OO code.

        Thank you VERY much!

        These other errors are not so serious. I think I'll fix them soon. The
        most important thing is that now I'm ready to work on that code again.
        Life is beautiful again!

        Damn, I knew it is some very stupid mistake. I must learn how to use
        that pylint, instead of asking people on the web such a stupid
        questions.

        (The sad thing is that I'm the only one developer, who works on that
        code. I think I had just stuck before I sent the first message in this
        topic.)

        Comment

        • TPJ

          #5
          Re: A problem with some OO code.

          At first I'd like to thank you for such a long answer.
          [color=blue]
          > (...)
          > You need to simplify the code as much as possible, cutting away everything
          > you can, to the SMALLEST amount of code that still experiences the problem.[/color]

          I understand your POV and I really appereciate your reply, but I doubt
          that I could simplify my code to make it small *enough* to fit in one
          post and not look too long.

          BTW: is there some safety way to show long piece of code on a
          group like comp.lang.pytho n? Uploading my code to my website was the
          first (and the only one...) idea I had.
          [color=blue]
          > (...)
          > There is very little point in showing us test code
          > that works -- your problem isn't with code that works, it is with code
          > that doesn't work.[/color]

          You see - that's one of my problems. I'm working on my PyObject module
          (it is intended to be a base for more complex systems). For now
          there are no other modules, that use PyObject. So the test.py module,
          that consists of some test for my module, is the *only* piece of code
          that I could show you. That's all the story.
          [color=blue][color=green]
          > > All you need to know is that there are four classes.[/color]
          >
          > No, I'm sure we need to know much more than that.[/color]

          Yes, you're right. But I tried to explain my problem as easily as
          possible. And (as I thought) only four classes were involved.
          [color=blue][color=green]
          > > (Of course, you
          > > may generate all the documentation by typing just "./make_docs". All
          > > you need is Python with Epydoc installed.)[/color]
          >
          > Oh right, well just let me rush off and install Epydoc just for you, okay?[/color]

          It was not my intention to ask you to install anything for me. I just
          thought, that someone might be interested to read some documentation
          about the module, that causes the problem. I think it's easier to read
          documentation of more complex system, than just code.

          Perhaps it's about my English (I'm still studying) - a language easy
          to learn, but difficult to master. By "you may" I meant "you might, if
          you'd like to (for some reasons)", not "you are expected to do it".
          [color=blue][color=green]
          > > In the PyObject.py there are two classes: Object and OManager. When
          > > Object wants to know if some link is safe (in another words: it wants
          > > to know if some another object exists),[/color]
          >
          > What is a link in your application? What do you mean "another object"?
          > Like an int or a string?[/color]

          1) In OO vocabulary, class is something like template for an object.
          But I think the word "object" has something different meaning in
          Python. In general I don't use the word "object" in the same meaning,
          that it is used by Python. I try to use words in the same way, that
          they
          are used in OO.
          Sometimes I use the word "class" to talk about template (for an
          object), and the word "instance" to talk about an object of some class,
          but the only reason I do it is to distinguish between OO-object and
          Python-object.

          2) Link is something like address (like a post address). My module -
          in general - is just a template of a system of objects, that are able
          to communicate with each other. All that an object needs to communicate
          with an another object, is the name of that another object - it's
          adress
          (my assumption is that the names of the objects will be unique).
          "Link" to an another object is just the name of that object.
          [color=blue][color=green]
          > > it calls the proper method of
          > > its objects' manager (the OManager instance). Details are not important
          > > here,[/color]
          >
          > I bet the details are absolutely vital.[/color]

          Yes, they are - were. But I didn't want to describe my code in details
          in my post. I suspected, that there's some stupid mistake somewhere in
          my code. The truth is, all I wanted was someone else to take a look at
          this code.

          (BTW - I was right. My problem was caused by a spelling mistake, and
          someone found it. And it made me feel very stupid, but I think I
          deserved
          it.)
          [color=blue][color=green]
          > > so I'll just say, that if the link is safe, the objects' manager
          > > calls the proper method of the object, that sent him request. This
          > > method of the object just stores the information about that link (that
          > > it's safe), in the so-called private field (the fields used to store
          > > the information about the links are called __ls_existing_l inks and
          > > __ls_demanded_l inks).[/color]
          >
          > This is a terribly involved way of doing it, and I'm not even sure what
          > "it" is that you are trying to do. Are you trying to do some sort of
          > dispatch mechanism?[/color]

          My idea is as follows:
          1) There's one objects' manager, that manages all the objects in some
          system.
          2) Every object has its unique name, and is registered with the
          objects' manager.
          3) When an object-sender wants to send a message to some
          object-receiver, all that the object-sender has to do is to tell the
          objects' manager, what's the name of the object-receiver.

          The only problem is that the object-sender has no idea if the
          object-receiver exists.

          A situation, when object-receiver doesn't exist, shouldn't happen, but
          as long as code is written by people, such a mistake can be done.
          Therefore I developed a mechanism, that may prevent such a situation.

          Every object-sender must create a link to the object-receiver. A link
          is just the name (id) of the object-receiver. There's only one
          OO-object in the system, that knows, if the object-receiver exists.
          It's the objects' manager. So the object-sender "asks" its objects'
          manager, if the link from that object-sender to the object-receiver is
          "safe" (in another words: if the object-receiver exists). If the
          object-receiver exists, the objects' manager just informs the
          object-sender (that might be also called the object-requester), that
          the link is safe (and can be used).

          But if the object-receiver doesn't exist, the objects' manager doesn't
          inform the object-requester about anything.

          Now, there are two different scenarios, that might happen:

          a) The object-receiver will be created - this is the desired
          situation. When the object-receiver will be registered with the
          objects' manager, the objects' manager will inform the
          object-requester, that the object-receiver exists and the link is
          safe.

          b) The object-receiver won't be created. Because the object-requester
          tracks all the demanded links, it knows, that not all of these links
          are safe - and therefore it knows, that it's not ready to work. In the
          final version of the module, the objects' manager will be able to
          check, if there are any objects, that aren't ready to work. In such a
          case the whole system just won't work (and it'll explain the
          developer why).

          It's not so complicated, and I suppose it will help me to create less
          error-prone code in the future.
          [color=blue]
          > I see you have a line "i = self.__ls_deman ded_links.index ( s_object )". It
          > looks like you are storing your data in a chunk of text, and then running
          > index on that text to find the bit you want to work with. If you wanted to
          > do that much work, just write your script in bash and be done with it!
          > Python has lists and dicts and other advanced data structures. Use them.
          > You will be glad.[/color]

          The reason, why a list was used in this case, is now obsolete and it
          will probably change in the future.

          But, in general, you're right. The dictionary would be much better in
          this case even in the previous version of my module.

          And... I know how great are lists, dicts and tuples. That's the reason
          I threw out Java, C++ and (in most cases) C, and fell in love with
          Python. In my personal opinion the adventure with Python begins in the
          moment, when you realize, how easy are lists, dicts and tuples to use.
          (Yes, I know, there are also sets, but I don't use them at all. So
          far...)
          [color=blue]
          > So Obj is an alias for Object? What's an Object? Is it the same as the
          > Python built-in type "object"?
          >
          > But later on you say:
          >
          > "All these methods are the methods of the Object class (defined in
          > PyObject.py), not of the Obj class (defined in test.py)."
          >
          > So Object and Obj are not the same.[/color]

          No. I think that the declaration of the Obj class will explain
          everything:

          class Obj( Object ):
          ...

          So the Obj class is an *extension* of the Object class. Therefore I
          wrote that "Obj is just an Object". I (mis?)used the vocabulary from
          OO: something may *be* a kind of something else (inheritance), or it
          may *has* something else (composition). But I'm not sure about those
          words; I have read many books in Polish, not in English.
          [color=blue][color=green]
          > > --------------------------------------------------
          > > Traceback (most recent call last):
          > > File "test.py", line 142, in test04CreateSys tems
          > > system1 = System1()
          > > File "test.py", line 81, in __init__
          > > self.objA.deman dNewLink( 'B' )
          > > File "/home/tpj/opt/Praca/Programy/PyObject/workdir/PyObject.py",
          > > line 503, in demandNewLink
          > > s_object )
          > > File "/home/tpj/opt/Praca/Programy/PyObject/workdir/PyObject.py",
          > > line 800, in _makeNewLink
          > > o_srcobj._makeL inkSafe( s_target )
          > > File "/home/tpj/opt/Praca/Programy/PyObject/workdir/PyObject.py",
          > > line 608, in _makeLinkSafe
          > > self.__makeLink Safe( s_object )
          > > File "/home/tpj/opt/Praca/Programy/PyObject/workdir/PyObject.py",
          > > line 582, in __makeLinkSafe
          > > i = self.__ls_deman ded_links.index ( s_object )
          > > AttributeError: 'Obj' object has no attribute
          > > '_Object__ls_de manded_links'[/color]
          >
          > [snip]
          >[color=green]
          > > Perhaps I'll explain what's going on there. First, the objects' manager
          > > is created, and then also some objects are created. After doing that,
          > > the object called "objA" demands a new link to the other object, called
          > > "objB" (this is the line 81 in the error message above).[/color]
          >
          > Your description does not match what line 81 actually says. It says:
          >
          > self.objA.deman dNewLink('B')
          >
          > self (an instance of System1, not Obj or Object) grabs the attribute
          > called "objA", and calls its method demandNewLink with an argument of
          > the string 'B', not objB an instance of Obj or Object.[/color]

          It's a typo, it should be 'B' instead of "objB".

          In fact, the reference to the object "B" is self.objB - I think that's
          the reason for this mistake.
          [color=blue]
          > If you want to work with Object instances, why not just use them instead
          > of passing around strings that represent them?[/color]

          Well, I *don't* want to work with any instances, therefore I intend to
          give all the objects unique names.
          [color=blue]
          > (...)
          > Huh? Do you mean that there is a way for links (whatever they are) to be
          > requested without calling demandNewLink? How would this happen?[/color]

          Well - it's Python, so *anything* can be done with any so-called
          private attributes. Therefore such a possibility exists.

          But it's not intended to be used in such a way. In "normal" use it's
          impossible to request a link without calling demandNewLink method.

          Perhaps my explanation wasn't too clear.
          [color=blue][color=green]
          > > All these methods are the methods of the Object class (defined in
          > > PyObject.py), not of the Obj class (defined in test.py). According to
          > > my knowledge about the OO programming Python should be able to realize,
          > > that the so-called private fields, that are being referred from these
          > > Object class methods, are the private fields of the *Obj class
          > > instance*, not of the *Object class one*.[/color]
          >
          > Some serious confusion here.
          >
          > What are fields? Do you mean attributes? I'm going to assume that you do.
          >
          > Would it help if I told you that Python doesn't have private attributes?
          > It *simulates* private attributes using name mangling.[/color]

          1) "Fields" - yes, I think I should have written attributes. Sorry for
          that, my problem is that the only books about OO that I have read were
          in Polish, so my vocabulary might be incorrect.

          In general, every object has methods (functions, procedures, etc.) and
          - I think - attributes (variables).

          2) I know that Python has no private *anything*, and therefore I
          called it "so-called private".
          [color=blue]
          > (...)
          > PLEASE don't bother to tell us how Python sucks because it doesn't have
          > "real private attributes", we've heard the arguments (and the abuse) fifty
          > times before.[/color]

          Python's not sucks, I find it the best programming language in the
          world. It suits all my needs.

          Believe me or not, but I have argued for Python to be (one of) the
          best language(s) to write OO applications. Since I have started coding
          in
          Python, I found that the idea of private, protected and public
          attributes/methods may be as well the matter of *convention*, as real
          *mechanism*.

          Anyway, I don't find Python inferior to any other OO language just
          because Python have no *real* private methods/attributes.

          So, I think, we're both on the same side.
          [color=blue]
          > (...)
          >
          > Good. Now how about getting a simple program that demonstrates your
          > problem?
          >
          > (...)
          >
          > Do you enjoy all this make-work, writing tedious methods to get or set or
          > print attributes? I suggest you ditch all the private attributes and just
          > make them public. You've already spent three days hitting your head
          > against a brick wall because of excessive data-hiding. Was it worth it?
          > Python is a language that encourages the attitude "We're all adults here"
          > -- getters/setters are discouraged.[/color]

          Maybe I'll make it clear: I wrote this simple example to show *myself*,
          that I'm not out of my mind. It was supposed to be *very* simple. I
          just
          wanted to check, if I'll be able to change the so-called private
          attribute declared in the A class by calling a method declared in
          another class. That's all. I think that if I hadn't done it, I would
          have started to doubt, that 2 + 2 = 4.

          Why I did such a obvious test? Because I thought that it was my
          problem in the PyObject module: the need to change a so-called private
          attribute declared in the class Object by calling a method of another
          class (an instance of another class, to be precise).
          [color=blue]
          > (...)
          >
          > The call to A.__init__ creates an attribute __a to self. Remember, self is
          > an instance of B (not A). Apply the name-mangling rules, which are applied
          > at compile time: the code in A's method mangles __a to _A__a. So
          > A.__init__ creates an attribute _A__a in B's namespace. So B has two
          > attributes, _A__a and _B__b.
          >
          > (...)
          >
          > (However, that is not your problem.)[/color]

          So it works just as it's supposed to work.

          All right, now I'm OK. My madness has gone.
          [color=blue]
          > (...)
          >
          > Here is your exception again:
          >
          > (...)[/color]

          Well, I decided to cut out all the rest - because (I think) it has
          nothing to do with my code - and therefore with my problem.

          Once again - thank you for such a long and thorough answer. Once again
          - sorry for some mistakes that I made in my first message, especially
          for those "fields" (I feel really silly now). I wrote the first
          message in the state of madness, after spending *three* days on
          analysis of my code, without any progress. I was very frustrated, and
          my explanations could be incomprehensibl e.

          Comment

          • Erik Max Francis

            #6
            Re: A problem with some OO code.

            TPJ wrote:
            [color=blue]
            > I understand your POV and I really appereciate your reply, but I doubt
            > that I could simplify my code to make it small *enough* to fit in one
            > post and not look too long.[/color]

            The pont of the exercise of taking non-working code and trying to cut
            away parts that aren't part of the problem is to isolate where the
            problem is. This is especially true in dynamic languages like Python,
            where problems usually consist of something not being what you expected
            it to be, but it's true in all other languages as well.

            Even if it means creating a standalone program that's a simplified
            version of the particular logic that's failing, this is good. It makes
            it easy for others to find where the problem is without having to tangle
            through your other (working) code.

            But in my view this is only the side benefit. The _real_ benefit is
            that a very significant fraction of the time, going through this
            exercise will actually help _you_ figure out your problem on your own.
            Taking a tangle of code that isn't working for reasons you don't
            understand and then pulling out threads to see where the problem is so
            you can show it to someone else to get help will usually allow _you_ to
            see where the problem was in the process.

            --
            Erik Max Francis && max@alcyone.com && http://www.alcyone.com/max/
            San Jose, CA, USA && 37 20 N 121 53 W && AIM erikmaxfrancis
            God said: "Let Newton be"; and all was light.
            -- Alexander Pope

            Comment

            • Terry Hancock

              #7
              Re: A problem with some OO code.

              On 4 Feb 2006 09:51:22 -0800
              "TPJ" <tprimke@interi a.pl> wrote:[color=blue]
              > 1) In OO vocabulary, class is something like template for
              > an object. But I think the word "object" has something
              > different meaning in Python. In general I don't use the
              > word "object" in the same meaning, that it is used by
              > Python. I try to use words in the same way, that they
              > are used in OO.
              > Sometimes I use the word "class" to talk about template
              > (for an object), and the word "instance" to talk about an
              > object of some class, but the only reason I do it is to
              > distinguish between OO-object and Python-object.[/color]

              "Object" in fact means *exactly* the same thing in Python
              that it does in any other OOP language. The only issue is
              that *anything*, even simple things like integers, are
              *objects* in Python. So, saying "object" (versus something
              else) doesn't mean much that we didn't already know -- if
              the program can manipulate it, then it's an "object".

              Saying a "class instance" or just "instance" for short is a
              way of specifically saying that it is a *user defined
              object* that we are talking about, created from a "class"
              (of course the "class" is *also* an object, and you can even
              make objects that make classes -- I think that's what a
              "metaclass" is, though I get fuzzy past that point). Usually
              the point, though, is to draw attention to what class it is
              an instance of.

              A class *is* probably describable as a "template" for an
              object, although the word "template" has a technical
              meaning, too, IIRC, which might not be totally consistent
              with that. More to the point, though, classes are "instance
              factories" in Python. It's almost as if a class is nothing
              more than a special category of functions that return
              instances.

              I don't know if I've helped at all, but I hope so. ;-)

              Cheers,
              Terry

              --
              Terry Hancock (hancock@Anansi Spaceworks.com)
              Anansi Spaceworks http://www.AnansiSpaceworks.com

              Comment

              Working...