Deprecating reload() ???

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

    #46
    Re: Deprecating reload() ???

    [color=blue][color=green]
    >> In general, I don't think that disabling immutable object sharing
    >> would be worth the effort. Consider the meaning of module level
    >> integers. In my experience they are generally constants and are
    >> infrequently changed once set. Probably the only thing worth
    >> tracking down during a super reload would be function, class and
    >> method definitions.[/color][/color]

    Dave> If you reload a module M1, and it has an attribute M1.x, which was
    Dave> changed from '1' to '2', we want to change also any references
    Dave> that may have been created with statements like 'x = M1.x', or
    Dave> 'from M1 import *' If we don't do this, reload() will continue to
    Dave> baffle and frustrate new users. Typically, they think they have
    Dave> just one variable 'x'

    Like I said, I think that sort of change will be relatively rare. Just tell
    your users, "don't do that".

    Dave> I'm having trouble understanding the benefit of using shared
    Dave> objects for simple numbers and strings.

    Can you say "space and time savings"? Ints are 12 bytes, strings are 24
    bytes (plus the storage for the string), None is 8 bytes. It adds up. More
    importantly, small ints, interned strings and None would constantly be
    created and freed. The performance savings of sharing them are probably
    much more important.

    Finally, from a semantic viewpoint, knowing that None is defined by the
    language to be a singleton object allows the more efficient "is" operator to
    be used when testing objects against None for equality. If you allowed many
    copies of that object that wouldn't work.

    Dave> We should at least have a special 'debug' mode in which the hidden
    Dave> sharing of objects is disabled for selected modules.

    It might help with your problem but would change the semantics of the
    language.

    Skip

    Comment

    • David MacQuigg

      #47
      Re: Deprecating reload() ???

      On Mon, 15 Mar 2004 11:33:04 -0600, Jeff Epler <jepler@unpytho nic.net>
      wrote:
      [color=blue]
      >This is guaranteed to work:
      > x = None
      > y = None
      > assert x is y
      >by the following text in the language manual:
      > None
      > This type has a single value. There is a single object with
      > this value. This object is accessed through the built-in
      > name None. It is used to signify the absence of a value in
      > many situations, e.g., it is returned from functions that
      > don't explicitly return anything. Its truth value is false.
      >There are reams of code that rely on the object identity of None, so a
      >special debug mode where "x = <some literal>" makes x refer to something
      >that has a refcount of 1 will break code.
      >
      >The 'is' guarantee applies to at least these built-in values:
      > None Ellipsis NotImplemented True False[/color]

      This certainly complicates things. I *wish* they had not made this
      "single object" statement. Why should how things are stored
      internally matter to the user? We could have just as easily worked
      with x == y, but now, as you say, it may be too late.

      The same problem occurs with strings (some strings at least):[color=blue][color=green][color=darkred]
      >>> x = 'abcdefghighklm nop'
      >>> y = 'abcdefghighklm nop'
      >>> x is y[/color][/color][/color]
      True[color=blue][color=green][color=darkred]
      >>> x = 'abc xyz'
      >>> y = 'abc xyz'
      >>> x is y[/color][/color][/color]
      False

      Since there is no simple way for the user to distinguish these cases,
      it looks like we might break some code if the storage of equal objects
      changes. The change would have to be for "debug" mode only, and for
      only the modules the user specifically imports in debug mode. We
      would need a big, bold warning that you should not use 'is'
      comparisons in cases like the above, at least for any objects from
      modules that are imported in debug mode.
      [color=blue]
      >The only problem I can see with reload() is that it doesn't do what you
      >want. But on the other hand, what reload() does is perfectly well
      >defined, and at least the avenues I've seen explored for "enhancing" it
      >look, well, like train wreck.[/color]

      It's worse than just a misunderstandin g. It's a serious limitation on
      what we can do with editing a running program. I don't agree that
      what it does now is well defined (at least not in the documentation).
      The discussion in Learning Python is totally misleading. We should at
      least update the description of the reload function in the Python
      Library Reference. See the thread "Reload Confusion" for some
      suggested text.

      -- Dave

      Comment

      • David MacQuigg

        #48
        Re: Deprecating reload() ???

        On Mon, 15 Mar 2004 12:28:50 -0600, Skip Montanaro <skip@pobox.com >
        wrote:
        [color=blue][color=green][color=darkred]
        > >> In general, I don't think that disabling immutable object sharing
        > >> would be worth the effort. Consider the meaning of module level
        > >> integers. In my experience they are generally constants and are
        > >> infrequently changed once set. Probably the only thing worth
        > >> tracking down during a super reload would be function, class and
        > >> method definitions.[/color][/color]
        >
        > Dave> If you reload a module M1, and it has an attribute M1.x, which was
        > Dave> changed from '1' to '2', we want to change also any references
        > Dave> that may have been created with statements like 'x = M1.x', or
        > Dave> 'from M1 import *' If we don't do this, reload() will continue to
        > Dave> baffle and frustrate new users. Typically, they think they have
        > Dave> just one variable 'x'
        >
        >Like I said, I think that sort of change will be relatively rare.[/color]

        I think wanting to change numbers in a reloaded module is very common.
        [color=blue]
        >Just tell your users, "don't do that".[/color]

        The problem is the complexity of "that" which they can and cannot do.
        Even renouned text authors don't seem to explain it clearly. I'm
        opting now for "don't do anything" to try and make it simple. By that
        I mean - Don't expect reloads to update anything but the reference to
        the reloaded module itself. This is simple, just not very convenient.
        [color=blue]
        > Dave> I'm having trouble understanding the benefit of using shared
        > Dave> objects for simple numbers and strings.
        >
        >Can you say "space and time savings"? Ints are 12 bytes, strings are 24
        >bytes (plus the storage for the string), None is 8 bytes. It adds up.[/color]

        Maybe you can save a significant amount of memory by having all the
        *system* modules share a common 'None' object, but when a user
        explicitly says 'M1.x = None', surely we can afford a 8 bytes to
        provide a special None for that reference.

        I'm no expert on these implementation issues, but these numbers seem
        small compared to the 512MB in a typical modern PC. I suppose there
        are some rare cases where you need to create an array of millions of
        references to a single constant. In those cases the debug mode may be
        too much of a burden. In general, we ought to favor simplicity over
        efficiency.
        [color=blue]
        >More importantly, small ints, interned strings and None would constantly be
        >created and freed. The performance savings of sharing them are probably
        >much more important.[/color]

        Again, as a non-expert, this seems strange. The burden of comparing a
        new object to what is already in memory, using an '==' type of
        comparison, must be comparable to simply creating a new object.
        [color=blue]
        >Finally, from a semantic viewpoint, knowing that None is defined by the
        >language to be a singleton object allows the more efficient "is" operator to
        >be used when testing objects against None for equality. If you allowed many
        >copies of that object that wouldn't work.[/color]

        We would lose some, assuming '==' for these small obects is slower
        than 'is', but then you would not have to test '==' on a large number
        of objects already in memory each time you define a new integer or
        small string.
        [color=blue]
        > Dave> We should at least have a special 'debug' mode in which the hidden
        > Dave> sharing of objects is disabled for selected modules.
        >
        >It might help with your problem but would change the semantics of the
        >language.[/color]

        I assume you are referring to the symantics of 'is' when working with
        small objects like None, 2, 'abc'. I agree, that is a problem for the
        proposed debug mode. I don't see a way around it, other than warning
        users not to expect modules imported in the debug mode to optimize the
        sharing of small objects in memory. Use 'x == 2' rather than 'x is 2'
        if you intend to use the debug mode.

        -- Dave

        Comment

        • Skip Montanaro

          #49
          Re: Deprecating reload() ???

          Dave> The same problem occurs with strings (some strings at least):[color=blue][color=green][color=darkred]
          >>> x = 'abcdefghighklm nop'
          >>> y = 'abcdefghighklm nop'
          >>> x is y[/color][/color][/color]
          True[color=blue][color=green][color=darkred]
          >>> x = 'abc xyz'
          >>> y = 'abc xyz'
          >>> x is y[/color][/color][/color]
          False

          The difference is the first string has the form of an identifier, so the
          interpreter automatically interns it and it gets shared after that. The
          second doesn't. You can force things though:
          [color=blue][color=green][color=darkred]
          >>> x = 'abc xyz'
          >>> id(x)[/color][/color][/color]
          10476320[color=blue][color=green][color=darkred]
          >>> x = intern(x)
          >>> x[/color][/color][/color]
          'abc xyz'[color=blue][color=green][color=darkred]
          >>> id(x)[/color][/color][/color]
          10476320[color=blue][color=green][color=darkred]
          >>> y = 'abc xyz'
          >>> id(y)[/color][/color][/color]
          10477088[color=blue][color=green][color=darkred]
          >>> y = intern(y)
          >>> id(y)[/color][/color][/color]
          10476320[color=blue][color=green][color=darkred]
          >>> x is y[/color][/color][/color]
          True

          Dave> We should at least update the description of the reload function
          Dave> in the Python Library Reference. See the thread "Reload
          Dave> Confusion" for some suggested text.

          Please file a bug report on Sourceforge so your ideas don't get lost. Feel
          free to assign it to me (sf id == "montanaro" ).

          Skip

          Comment

          • Jeff Epler

            #50
            Re: Deprecating reload() ???

            On Mon, Mar 15, 2004 at 01:18:34PM -0700, David MacQuigg wrote:[color=blue]
            > Maybe you can save a significant amount of memory by having all the
            > *system* modules share a common 'None' object, but when a user
            > explicitly says 'M1.x = None', surely we can afford a 8 bytes to
            > provide a special None for that reference.[/color]

            Not only is there a lot of Python code written that says
            if x is None: ...
            but there are dozens of pointer comparisons to Py_None in the C source
            code for Python. In this somewhat stale CVS tree, grep found 263 lines
            with both "==" and "Py_None" on the same line, and 86 more with "!=" and
            "Py_None" on the same line. Py_True and Py_False appear with == and !=
            an additional 45 times. Perhaps you'd like to fix all the third-party
            extension modules once you're done inspecting something like 300 sites
            in the Python core.

            For Py_None, at least, the pointer equality rule is enshrined in the API
            documentation:
            Since None is a singleton, testing for object identity (using "=="
            in C) is sufficient.
            The official home of the Python Programming Language


            Jeff

            Comment

            • John Roth

              #51
              Re: Deprecating reload() ???


              "David MacQuigg" <dmq@gain.com > wrote in message
              news:fc0c50htli p4mtpjjdhbuenn6 m38o3mi9u@4ax.c om...[color=blue]
              > On Mon, 15 Mar 2004 11:33:04 -0600, Jeff Epler <jepler@unpytho nic.net>
              > wrote:
              >
              >
              > It's worse than just a misunderstandin g. It's a serious limitation on
              > what we can do with editing a running program.[/color]

              Well, that's a definite yes and no. The limitation is quite simple:
              any object in the module that has a reference from outside of the
              module will not have that reference changed. It will continue to
              refer to the old copy of the object.

              The solution to this is to apply some design discipline. Systems
              exist that have absolute "cannot come down for any reason"
              type of requirements where software has to be replaced while the
              system is running. It's not impossible, it simply requires a great
              deal of discipline in not allowing references to wander all over the
              place.

              As far as updating in place while debugging, there are a few
              solutions that, so far, haven't been implemented. One is to
              notice that functions are objects that have a reference to another
              object called a "code object." This is the actual result of the
              compilation, and if you go behind the scenes and replace the
              code object reference in the function object, you've basically
              done an update in place - as long as you don't have a stack
              frame with a pointer into the old code object! (The stack frame
              could, of course, be fixed too. Extra credit for doing so.)

              I can easily imagine a development environment that could
              do this kind of magic. If someone wants to build it, I'm
              certainly not going to stop them (and wouldn't even if I could.)
              I might even find it useful!

              The thing that is not going to work, ever, is having reload()
              do the work for you.
              [color=blue]
              > I don't agree that
              > what it does now is well defined (at least not in the documentation).[/color]

              It's well enough defined for someone who knows how Python works.
              [color=blue]
              > The discussion in Learning Python is totally misleading. We should at
              > least update the description of the reload function in the Python
              > Library Reference. See the thread "Reload Confusion" for some
              > suggested text.[/color]

              I agree with that: instead of "There are some caveats" it should say:

              WARNING - references to objects in the old copy of the module
              that have leaked out of the module will NOT be replaced. A few of
              the implications are:

              and then continue with the current text (my version of the doc is 2.3.2).

              John Roth[color=blue]
              >
              > -- Dave
              >[/color]


              Comment

              • Hung Jung Lu

                #52
                Re: Deprecating reload() ???

                David MacQuigg <dmq@gain.com > wrote in message news:<fc0c50htl ip4mtpjjdhbuenn 6m38o3mi9u@4ax. com>...[color=blue]
                > On Mon, 15 Mar 2004 11:33:04 -0600, Jeff Epler <jepler@unpytho nic.net>
                > wrote:
                >[color=green]
                > >The only problem I can see with reload() is that it doesn't do what you
                > >want. But on the other hand, what reload() does is perfectly well
                > >defined, and at least the avenues I've seen explored for "enhancing" it
                > >look, well, like train wreck.[/color]
                >
                > It's worse than just a misunderstandin g. It's a serious limitation on
                > what we can do with editing a running program.[/color]

                As I said in another message, you CAN do the kinds of things you want
                to do (edit-and-continue), if you use weakrefs, and use classes
                instead of modules. Take a look at the weakref module. I am not saying
                that it's trivial in Python: it does require a bit of work, but
                edit-and-continue in Python is definitely doable. I've done it, many
                other people have done it.

                (Of course, if you asked whether the Ruby behavior is better, I'd
                think so. I think it's better to automatically replace class behavior
                on reload, by default, and leave open the possibility of explicitly
                refusing replacement. Python is the opposite: by default the class
                behavior does NOT get modified, and you have to do somework to replace
                it.)

                I think it is an historical accident in Python that modules are not
                made more class-like. Another thing I have seen people wishing having
                is getter/setter accessor methods (or properties) for module-level
                attributes.

                It usually is a better practice in Python to store attributes in
                classes rather than modules, exactly because down the future you'd
                often start to wish having class-like behaviors for your modules.

                regards,

                Hung Jung

                Comment

                • David MacQuigg

                  #53
                  Re: Deprecating reload() ???

                  On Mon, 15 Mar 2004 13:50:47 -0600, Skip Montanaro <skip@pobox.com >
                  wrote:
                  [color=blue]
                  > Dave> We should at least update the description of the reload function
                  > Dave> in the Python Library Reference. See the thread "Reload
                  > Dave> Confusion" for some suggested text.
                  >
                  >Please file a bug report on Sourceforge so your ideas don't get lost. Feel
                  >free to assign it to me (sf id == "montanaro" ).[/color]

                  Will do. I would like to get a few comments from folks following this
                  thread before submitting the proposed text to Sourceforge. Here is
                  the summary:
                  """
                  To summarize what happens with reload(M1):

                  The module M1 must have been already imported in the current
                  namespace.

                  The new M1 is executed, and new objects are created in memory.

                  The names in the M1 namespace are updated to point to the new objects.
                  No other references are changed. References to objects removed from
                  the new module remain unchanged.

                  Previously created references from other modules to the old objects
                  remain unchanged and must be updated in each namespace where they
                  occur.

                  The old objects remain in memory until all references to them are
                  gone.
                  """

                  To read this in context, with a nice example, background discussion,
                  etc. see http://ece.arizona.edu/~edatools/Python/Reload.htm I think
                  I've finally got it right, but I'm always prepared for another
                  surprise.

                  Once I'm confident that my understanding is correct, I'll see if I can
                  weave this into the existing text of the Library Reference. I may try
                  also to put in some of the "motivation " for the way things are (from
                  the Background section of the above webpage.)

                  -- Dave

                  Comment

                  • Carl Banks

                    #54
                    Re: Deprecating reload() ???

                    David MacQuigg wrote:[color=blue]
                    > On Mon, 15 Mar 2004 05:49:58 -0600, Skip Montanaro <skip@pobox.com >
                    > wrote:
                    >[color=green]
                    >> Dave> Maybe we could somehow switch off the generation of shared objects
                    >> Dave> for modules in a 'debug' mode.
                    >>
                    >>You'd have to disable the integer free list. There's also code in
                    >>tupleobject .c to recognize and share the empty tuple. String interning
                    >>could be disabled as well. Everybody's ignored the gorilla in the room:
                    >>[color=darkred]
                    >> >>> sys.getrefcount (None)[/color]
                    >> 1559[/color]
                    >
                    > Implementation detail. ( half wink )
                    >[color=green]
                    >>In general, I don't think that disabling immutable object sharing would be
                    >>worth the effort. Consider the meaning of module level integers. In my
                    >>experience they are generally constants and are infrequently changed once
                    >>set. Probably the only thing worth tracking down during a super reload
                    >>would be function, class and method definitions.[/color]
                    >
                    > If you reload a module M1, and it has an attribute M1.x, which was
                    > changed from '1' to '2', we want to change also any references that
                    > may have been created with statements like 'x = M1.x', or 'from M1
                    > import *' If we don't do this, reload() will continue to baffle and
                    > frustrate new users.[/color]


                    What if one of your users does something like 'y = M1.x + 1'; then
                    what are you going to do?

                    It seems to me that your noble effort to make reload() completely
                    foolproof is ultimately in vain: there's just too many opportunities
                    for a module's variables to affect things far away.


                    --
                    CARL BANKS http://www.aerojockey.com/software
                    "If you believe in yourself, drink your school, stay on drugs, and
                    don't do milk, you can get work."
                    -- Parody of Mr. T from a Robert Smigel Cartoon

                    Comment

                    • David MacQuigg

                      #55
                      Re: Deprecating reload() ???

                      On Tue, 16 Mar 2004 04:43:01 GMT, Carl Banks
                      <imbosol@aerojo ckey.invalid> wrote:
                      [color=blue]
                      >What if one of your users does something like 'y = M1.x + 1'; then
                      >what are you going to do?[/color]

                      The goal is *not* to put the program into the state it "would have
                      been" had the changes in M1 been done earlier. That is impossible.
                      We simply want to have all *direct* references to objects in M1 be
                      updated. A direct reference, like 'y = M1.x', sets 'y' to the same
                      object as 'M1.x' The 'y' in the above example points to a new object,
                      with an identity different than anything in the M1 module. It should
                      not get updated.
                      [color=blue]
                      >It seems to me that your noble effort to make reload() completely
                      >foolproof is ultimately in vain: there's just too many opportunities
                      >for a module's variables to affect things far away.[/color]

                      It all depends on your goals for reload(). To me, updating all direct
                      references is a worthy goal, would add a lot of utility, and is easy
                      to explain. Going further than that, updating objects that are "only
                      one operation away from a direct reference" for example, gets into a
                      grey area where I see no clear line we can draw. There might be some
                      benefit, but the cost in user confusion would be too great.

                      Reload() will always be a function that needs to be used cautiously.
                      Changes in a running program can propagate in strange ways. "Train
                      wreck" was the term another poster used.

                      -- Dave

                      Comment

                      • Skip Montanaro

                        #56
                        Re: Deprecating reload() ???

                        [color=blue][color=green]
                        >> What if one of your users does something like 'y = M1.x + 1'; then
                        >> what are you going to do?[/color][/color]

                        Dave> The goal is *not* to put the program into the state it "would have
                        Dave> been" had the changes in M1 been done earlier. That is
                        Dave> impossible. We simply want to have all *direct* references to
                        Dave> objects in M1 be updated.

                        The above looks like a pretty direct reference to M1.x. <0.5 wink>

                        It seems to me that you have a continuum from "don't update anything" to
                        "track and update everything":

                        don't update update global update all direct update
                        anything funcs/classes references everything

                        reload() super_reload() Dave nobody?

                        Other ideas have been mentioned, like fiddling the __bases__ of existing
                        instances or updating active local variables. I'm not sure precisely where
                        those concepts fall on the continuum. Certainly to the right of
                        super_reload() though.

                        In my opinion you do what's easy as a first step then extend it as you can.
                        I think you have to punt on shared objects (ints, None, etc). This isn't
                        worth changing the semantics of the language even in some sort of
                        interactive debug mode.

                        Sitting for long periods in an interactive session and expecting it to track
                        your changes is foreign to me. I will admit to doing stuff like this for
                        short sessions:
                        [color=blue][color=green][color=darkred]
                        >>> import foo
                        >>> x = foo.Foo(...)
                        >>> x.do_it()[/color][/color][/color]
                        ...
                        TypeError ...[color=blue][color=green][color=darkred]
                        >>> # damn! tweak foo.Foo class in emacs
                        >>> reload(foo)
                        >>> x = foo.Foo(...)
                        >>> x.do_it()[/color][/color][/color]
                        ...

                        but that's relatively rare, doesn't go on for many cycles, and is only made
                        tolerable by the presence of readline/command retrieval/copy-n-paste in the
                        interactive environment.

                        Maybe it's just the nature of your users and their background, but an
                        (edit/test/run)+ cycle seems much more common in the Python community than a
                        run/(edit/reload)+ cycle. Note the missing "test" from the second cycle and
                        from the above pseudo-transcript. I think some Python programmers would
                        take the opportunity to add an extra test case to their code in the first
                        cycle, where in the second cycle the testing is going on at the interactive
                        prompt where it can get lost. "I don't need to write a test case. It will
                        just slow me down. The interactive session will tell me when I've got it
                        right." Of course, once the interactive sessions has ended, the sequence of
                        statements you executed is not automatically saved. You still need to pop
                        back to your editor to take care of that. It's a small matter of
                        discipline, but then so is not creating aliases in the first place.

                        Dave> Reload() will always be a function that needs to be used
                        Dave> cautiously. Changes in a running program can propagate in strange
                        Dave> ways. "Train wreck" was the term another poster used.

                        Precisely. You may wind up making reload() easier to explain in the common
                        case, but introduce subtleties which are tougher to predict (instances whose
                        __bases__ change or don't change depending how far along the above continuum
                        you take things). I think changing the definitions of functions and classes
                        will be the much more likely result of edits requiring reloads than tweaking
                        small integers or strings. Forcing people to recreate instances is
                        generally not that big of a deal.

                        Finally, I will drag the last line out of Tim's "The Zen of Python":

                        Namespaces are one honking great idea -- let's do more of those!

                        By making it easier for your users to get away with aliases like

                        x = M1.x

                        you erode the namespace concept ever so slightly just to save typing a
                        couple extra characters or executing a couple extra bytecodes. Why can't
                        they just type M1.x again? I don't think the savings is really worth it in
                        the long run.

                        Skip

                        Comment

                        • David MacQuigg

                          #57
                          Re: Deprecating reload() ???

                          On Tue, 16 Mar 2004 08:58:38 -0600, Skip Montanaro <skip@pobox.com >
                          wrote:
                          [snip][color=blue]
                          >It seems to me that you have a continuum from "don't update anything" to
                          >"track and update everything":
                          >
                          > don't update update global update all direct update
                          > anything funcs/classes references everything
                          >
                          > reload() super_reload() Dave nobody?
                          >
                          >Other ideas have been mentioned, like fiddling the __bases__ of existing
                          >instances or updating active local variables. I'm not sure precisely where
                          >those concepts fall on the continuum. Certainly to the right of
                          >super_reload () though.
                          >
                          >In my opinion you do what's easy as a first step then extend it as you can.
                          >I think you have to punt on shared objects (ints, None, etc). This isn't
                          >worth changing the semantics of the language even in some sort of
                          >interactive debug mode.[/color]

                          I agree, punt is the right play for now, but I want to make one
                          clarification, in case we need to re-open this question. The semantic
                          change we are talking about applies only to the 'is' operator, and
                          only to a few immutable objects which are created via a reload of a
                          module in "debug" mode. All other objects, including those from other
                          modules remain unchanged. Objects like None, 1, 'abc', which are
                          treated as shared objects in normal modules, will be given a unique ID
                          when loaded from a module in debug mode. This means you will have to
                          use '==' to test equality of those objects, not 'is'. Since 'is' is
                          already a tricky, implementation-dependent operator that is best
                          avoided in these situations, the impact of this added option seems far
                          less than "changing the semantics of the language".

                          I'll hold off on any push for expanding super_reload until I have a
                          good use case. Meanwhile, I'll assume I can work with the existing
                          reload. This will probably involve a combination of programming
                          discipline and user education. In programming, I'll do what I can to
                          avoid problems with the modules I expect will be reloaded. Where
                          "direct" references are made to constants or other objects in a
                          reloaded module, I'll be sure to refresh those references at the
                          beginning of each code section. In my user manual, there will
                          probably be statements like: """Don't attempt to reload the stats
                          module while a simulator is active. The reload function can save
                          having to restart your entire session, but it does not update
                          functions or data that have already been sent to the simulator. As
                          with reloading statefiles, always kill and restart the simulator after
                          a reload of the stats module."""
                          [color=blue]
                          >Sitting for long periods in an interactive session and expecting it to track
                          >your changes is foreign to me. I will admit to doing stuff like this for
                          >short sessions:
                          >[color=green][color=darkred]
                          > >>> import foo
                          > >>> x = foo.Foo(...)
                          > >>> x.do_it()[/color][/color]
                          > ...
                          > TypeError ...[color=green][color=darkred]
                          > >>> # damn! tweak foo.Foo class in emacs
                          > >>> reload(foo)
                          > >>> x = foo.Foo(...)
                          > >>> x.do_it()[/color][/color]
                          > ...
                          >
                          >but that's relatively rare, doesn't go on for many cycles, and is only made
                          >tolerable by the presence of readline/command retrieval/copy-n-paste in the
                          >interactive environment.
                          >
                          >Maybe it's just the nature of your users and their background, but an
                          >(edit/test/run)+ cycle seems much more common in the Python community than a
                          >run/(edit/reload)+ cycle. Note the missing "test" from the second cycle and
                          >from the above pseudo-transcript. I think some Python programmers would
                          >take the opportunity to add an extra test case to their code in the first
                          >cycle, where in the second cycle the testing is going on at the interactive
                          >prompt where it can get lost. "I don't need to write a test case. It will
                          >just slow me down. The interactive session will tell me when I've got it
                          >right." Of course, once the interactive sessions has ended, the sequence of
                          >statements you executed is not automatically saved. You still need to pop
                          >back to your editor to take care of that. It's a small matter of
                          >discipline, but then so is not creating aliases in the first place.[/color]

                          This is a good description of the program development cycle. My users
                          (circuit design engineers) won't be doing program development, but
                          will be making changes in existing data and functions. My goal is to
                          make that as easy as possible. The biggest step is offering Python as
                          the scripting language, rather than SKILL, OCEAN, MDL, or a number of
                          other CPL's ( complex proprietary languages ). I expect them to learn
                          in two days enough Python to understand a function definition, and to
                          be able to edit that definition, making it do whatever they want.
                          [color=blue]
                          > Dave> Reload() will always be a function that needs to be used
                          > Dave> cautiously. Changes in a running program can propagate in strange
                          > Dave> ways. "Train wreck" was the term another poster used.
                          >
                          >Precisely. You may wind up making reload() easier to explain in the common
                          >case, but introduce subtleties which are tougher to predict (instances whose
                          >__bases__ change or don't change depending how far along the above continuum
                          >you take things). I think changing the definitions of functions and classes
                          >will be the much more likely result of edits requiring reloads than tweaking
                          >small integers or strings. Forcing people to recreate instances is
                          >generally not that big of a deal.
                          >
                          >Finally, I will drag the last line out of Tim's "The Zen of Python":
                          >
                          > Namespaces are one honking great idea -- let's do more of those!
                          >
                          >By making it easier for your users to get away with aliases like
                          >
                          > x = M1.x
                          >
                          >you erode the namespace concept ever so slightly just to save typing a
                          >couple extra characters or executing a couple extra bytecodes. Why can't
                          >they just type M1.x again? I don't think the savings is really worth it in
                          >the long run.[/color]

                          def h23(freq):
                          s = complex(2*pi*fr eq)
                          h0 = PZfuncs.h0
                          z1 = PZfuncs.z1; z2 = PZfuncs.z2
                          p1 = PZfuncs.p1; p2 = PZfuncs.p2; p3 = PZfuncs.p3
                          return h0*(s-z1)*(s-z2)/((s-p1)*(s-p2)*(s-p3))

                          Notice the clarity in that last formula. This is a standard form of a
                          pole-zero transfer function that will be instantly recognized by a
                          circuit design engineer. The issue isn't the typing of extra
                          characters, but the compactness of expressions.

                          In this case we avoid the problem of local variables out-of-sync with
                          a reloaded module by refreshing those variables with every call to the
                          function. In other cases, this may add too much overhead to the
                          computation.

                          -- Dave

                          Comment

                          • Skip Montanaro

                            #58
                            Re: Deprecating reload() ???


                            Dave> I agree, punt is the right play for now, but I want to make one
                            Dave> clarification, in case we need to re-open this question. The
                            Dave> semantic change we are talking about applies only to the 'is'
                            Dave> operator, and only to a few immutable objects which are created
                            Dave> via a reload of a module in "debug" mode. All other objects,
                            Dave> including those from other modules remain unchanged. Objects like
                            Dave> None, 1, 'abc', which are treated as shared objects in normal
                            Dave> modules, will be given a unique ID when loaded from a module in
                            Dave> debug mode. This means you will have to use '==' to test equality
                            Dave> of those objects, not 'is'. Since 'is' is already a tricky,
                            Dave> implementation-dependent operator that is best avoided in these
                            Dave> situations, the impact of this added option seems far less than
                            Dave> "changing the semantics of the language".

                            Don't forget all the C code. C programmers know the object which represents
                            None is unique, so their code generally looks like this snippet from
                            Modules/socketmodule.c:

                            if (arg == Py_None)
                            timeout = -1.0;

                            "==" in C is the equivalent of "is" in Python. If you change the uniqueness
                            of None, you have a lot of C code to change.

                            Dave> def h23(freq):
                            Dave> s = complex(2*pi*fr eq)
                            Dave> h0 = PZfuncs.h0
                            Dave> z1 = PZfuncs.z1; z2 = PZfuncs.z2
                            Dave> p1 = PZfuncs.p1; p2 = PZfuncs.p2; p3 = PZfuncs.p3
                            Dave> return h0*(s-z1)*(s-z2)/((s-p1)*(s-p2)*(s-p3))

                            Dave> Notice the clarity in that last formula.

                            Yeah, but h0, z1, z2, etc are not long-lived copies of attributes in
                            PZfuncs. If I execute:
                            [color=blue][color=green][color=darkred]
                            >>> blah = h23(freq)
                            >>> reload(PZfuncs)
                            >>> blah = h23(freq)[/color][/color][/color]

                            things will work properly. It's only long-lived aliases that present a
                            problem:

                            def h23(freq, h0=PZfuncs.h0):
                            s = complex(2*pi*fr eq)
                            z1 = PZfuncs.z1; z2 = PZfuncs.z2
                            p1 = PZfuncs.p1; p2 = PZfuncs.p2; p3 = PZfuncs.p3
                            return h0*(s-z1)*(s-z2)/((s-p1)*(s-p2)*(s-p3))

                            Dave> In this case we avoid the problem of local variables out-of-sync
                            Dave> with a reloaded module by refreshing those variables with every
                            Dave> call to the function. In other cases, this may add too much
                            Dave> overhead to the computation.

                            Unlikely. Creating local copies of frequently used globals (in this case
                            frequently used globals in another module) is almost always a win. In fact,
                            it's so much of a win that a fair amount of brain power has been devoted to
                            optimizing global access. See PEPs 266 and 267 and associated threads in
                            python-dev from about the time they were written. (Note that optimizing
                            global access is still an unsolved problem in Python.)

                            Skip

                            Comment

                            • Terry Reedy

                              #59
                              Re: Deprecating reload() ???


                              "David MacQuigg" <dmq@gain.com > wrote in message
                              news:42je50p1ep hn4uoksbpjjoa8e 05otp43le@4ax.c om...[color=blue]
                              > def h23(freq):
                              > s = complex(2*pi*fr eq)
                              > h0 = PZfuncs.h0
                              > z1 = PZfuncs.z1; z2 = PZfuncs.z2
                              > p1 = PZfuncs.p1; p2 = PZfuncs.p2; p3 = PZfuncs.p3
                              > return h0*(s-z1)*(s-z2)/((s-p1)*(s-p2)*(s-p3))
                              >
                              > Notice the clarity in that last formula. This is a standard form of a
                              > pole-zero transfer function that will be instantly recognized by a
                              > circuit design engineer. The issue isn't the typing of extra
                              > characters, but the compactness of expressions.[/color]

                              For one use only, making local copies adds overhead without the
                              compensation of faster multiple accesses. To make the formula nearly as
                              clear without the overhead, I would consider

                              import PZfuncs as z
                              def h23(freq):
                              s = complex(2*pi*fr eq)
                              return z.h0 * (s-z.z1) * (s-z.z2) / ((s-z.p1) * (s-z.p2) * (s-z.p3))

                              Terry J. Reedy




                              Comment

                              • David MacQuigg

                                #60
                                Re: Deprecating reload() ???

                                On Tue, 16 Mar 2004 16:42:55 -0500, "Terry Reedy" <tjreedy@udel.e du>
                                wrote:
                                [color=blue]
                                >"David MacQuigg" <dmq@gain.com > wrote in message
                                >news:42je50p1e phn4uoksbpjjoa8 e05otp43le@4ax. com...[color=green]
                                >> def h23(freq):
                                >> s = complex(2*pi*fr eq)
                                >> h0 = PZfuncs.h0
                                >> z1 = PZfuncs.z1; z2 = PZfuncs.z2
                                >> p1 = PZfuncs.p1; p2 = PZfuncs.p2; p3 = PZfuncs.p3
                                >> return h0*(s-z1)*(s-z2)/((s-p1)*(s-p2)*(s-p3))
                                >>
                                >> Notice the clarity in that last formula. This is a standard form of a
                                >> pole-zero transfer function that will be instantly recognized by a
                                >> circuit design engineer. The issue isn't the typing of extra
                                >> characters, but the compactness of expressions.[/color]
                                >
                                >For one use only, making local copies adds overhead without the
                                >compensation of faster multiple accesses. To make the formula nearly as
                                >clear without the overhead, I would consider
                                >
                                >import PZfuncs as z
                                >def h23(freq):
                                > s = complex(2*pi*fr eq)
                                > return z.h0 * (s-z.z1) * (s-z.z2) / ((s-z.p1) * (s-z.p2) * (s-z.p3))[/color]

                                This is equivalent to:

                                h0 = PZfuncs.h0
                                z1 = PZfuncs.z1; z2 = PZfuncs.z2
                                p1 = PZfuncs.p1; p2 = PZfuncs.p2; p3 = PZfuncs.p3
                                def h23(freq):
                                s = complex(2*pi*fr eq)
                                return h0*(s-z1)*(s-z2)/((s-p1)*(s-p2)*(s-p3))

                                Either way we have the architectural problem of ensuring that the code
                                just above the def gets executed *after* each reload of PZfuncs, and
                                *before* any call to h23.

                                -- Dave

                                Comment

                                Working...