mutable default parameter problem [Prothon]

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

    #16
    Re: mutable default parameter problem [Prothon]

    Peter Hansen wrote:
    [color=blue][color=green]
    >> In Prothon:
    >> def foo(x):
    >> print foo.list.append !(x)
    >> foo.list = []
    >>
    >> (Sorry. I couldn't resist bragging.)[/color]
    >
    > About what?
    >
    > Python 2.3.3 (#51, Dec 18 2003, 20:22:39) [MSC v.1200 32 bit (Intel)][color=green][color=darkred]
    > >>> def foo(x):[/color][/color]
    > ... foo.list.append (x)
    > ... print foo.list
    > ...[color=green][color=darkred]
    > >>> foo.list = []
    > >>> foo('test')[/color][/color]
    > ['test']
    >
    > (Oh, did you mean bragging about how a hard-to-see exclamation
    > mark causes append() to return the sequence? I thought
    > maybe it was about the function attribute or something.)[/color]

    Actually, I didn't know if the function attribute assignment outside the
    function would work in Python or not. I guess I'll know better than to try
    to play one-upmanship with Python next time. I did say I was sorry :-)

    FYI: It's not that the exclamation mark causes append to return the
    sequence. The exclamation mark is always there and the sequence is always
    returned. The exclamation mark is the universal symbol for in-place
    modification. This is straight from Ruby and solves the problem that caused
    Guido to not allow sequences to be returned. And, yes, I do think that's
    worth bragging about ;-)


    Comment

    • Andrea Griffini

      #17
      Re: mutable default parameter problem [Prothon]

      On Wed, 16 Jun 2004 12:40:10 -0700, "Mark Hahn" <mark@prothon.o rg>
      wrote:
      [color=blue]
      >In Prothon:
      >
      > def foo(x):
      > print foo.list.append !(x)
      > foo.list = []
      >
      >(Sorry. I couldn't resist bragging.)[/color]

      The very first thing I tried was assigning foo.list
      outside of the function (and, by the way, that works in
      python too); this however doesn't mimic C++ static,
      as initialization of the static local variable is done
      in C++ when (and only IF) the function is entered.
      The value used for initialization can for example
      depend on local parameters or global state at *that time*.

      Using "hasattr" seemed ugly to me at first, but after
      all you need an additional flag anyway, so why not
      checking the presence of a certain key in foo.__dict__ ?
      That way both initialization and setting the flag are
      done at the same time using just one clean statement.

      The only (very small) syntax price is the if (that in
      C++ is implicit in the overused keyword "static").

      Andrea

      Comment

      • David Bolen

        #18
        Re: mutable default parameter problem [Prothon]

        Andrea Griffini <agriff@tin.i t> writes:
        [color=blue]
        > But if there are those better-looking statics, why so
        > much use of that modifiable-default-of-a-fake-parameter
        > ugly trick ? Is this something that became legal
        > only recently ?[/color]

        Function attributes were in fact somewhat recently added (as of Python
        2.1, so circa April of 2001).

        -- David

        Comment

        • Michele Simionato

          #19
          Re: mutable default parameter problem [Prothon]

          "Mark Hahn" <mark@prothon.o rg> wrote in message news:<5L2Ac.26$ u%3.13@fed1read 04>...[color=blue]
          > FYI: It's not that the exclamation mark causes append to return the
          > sequence. The exclamation mark is always there and the sequence is always
          > returned. The exclamation mark is the universal symbol for in-place
          > modification. This is straight from Ruby and solves the problem that caused
          > Guido to not allow sequences to be returned. And, yes, I do think that's
          > worth bragging about ;-)[/color]

          I think the esclamation mark comes from Scheme if not from a more
          ancient language. It is certainly not a new idea. OTOH, it is a good
          idea, no question
          about that. Same for "?" in booleans.


          Michele Simionato

          Comment

          • Dave Brueck

            #20
            Re: mutable default parameter problem [Prothon]

            Mark wrote:[color=blue][color=green]
            > > I like more as an example:
            > >[color=darkred]
            > > >>> def foo(x):[/color]
            > > ... if not hasattr(foo,'li st'):
            > > ... foo.list = []
            > > ... foo.list.append (x)
            > > ... print foo.list[/color]
            >
            > In Prothon:
            >
            > def foo(x):
            > print foo.list.append !(x)
            > foo.list = []
            >
            > (Sorry. I couldn't resist bragging.)[/color]

            About what?

            -Dave


            Comment

            • Mark Hahn

              #21
              Re: mutable default parameter problem [Prothon]


              "Dave Brueck" <dave@pythonapo crypha.com> wrote
              [color=blue][color=green][color=darkred]
              > > > I like more as an example:
              > > >
              > > > >>> def foo(x):
              > > > ... if not hasattr(foo,'li st'):
              > > > ... foo.list = []
              > > > ... foo.list.append (x)
              > > > ... print foo.list[/color]
              > >
              > > In Prothon:
              > >
              > > def foo(x):
              > > print foo.list.append !(x)
              > > foo.list = []
              > >
              > > (Sorry. I couldn't resist bragging.)[/color]
              >
              > About what?[/color]

              Is there an echo in here? :-)


              Comment

              • Christos TZOTZIOY Georgiou

                #22
                Re: mutable default parameter problem [Prothon]

                On Wed, 16 Jun 2004 21:41:07 -0700, rumours say that "Mark Hahn"
                <mark@prothon.o rg> might have written:
                [color=blue]
                >"Dave Brueck" <dave@pythonapo crypha.com> wrote
                >[color=green][color=darkred]
                >> > > I like more as an example:
                >> > >
                >> > > >>> def foo(x):
                >> > > ... if not hasattr(foo,'li st'):
                >> > > ... foo.list = []
                >> > > ... foo.list.append (x)
                >> > > ... print foo.list
                >> >
                >> > In Prothon:
                >> >
                >> > def foo(x):
                >> > print foo.list.append !(x)
                >> > foo.list = []
                >> >
                >> > (Sorry. I couldn't resist bragging.)[/color]
                >>
                >> About what?[/color]
                >
                >Is there an echo in here? :-)[/color]

                Probably not. Given the python version:

                def foo(x):
                foo.list.append (x)
                print foo.list
                foo.list = []

                Dave's question is legitimate. Are you bragging about the two lines
                combined into one?
                --
                TZOTZIOY, I speak England very best,
                "I have a cunning plan, m'lord" --Sean Bean as Odysseus/Ulysses

                Comment

                • Mark Hahn

                  #23
                  Re: mutable default parameter problem [Prothon]

                  Christos TZOTZIOY Georgiou wrote:
                  [color=blue]
                  > Dave's question is legitimate. Are you bragging about the two lines
                  > combined into one?[/color]

                  As I replied before to the same exact question, I didn't know that Python
                  could do the function attribute assignment outside of the function (yes it
                  was stupid of me) and I was bragging about taking six lines to three. It
                  turns out that Prothon can only improve it by one line. I also said I was
                  sorry in my very first posting. If you want me to repeat this a third time
                  I will.


                  Comment

                  • Pierre-Frédéric Caillaud

                    #24
                    Re: mutable default parameter problem [Prothon]


                    [color=blue]
                    > 2) Evaluate the default expression once at each call time when the
                    > default
                    > value is needed. The default expression would be evaluated in the
                    > context
                    > of the function definition (like a closure).[/color]


                    I like Choice 2 because I've always wanted to do the following :

                    def func( x, y=2*x ):
                    do stuff...

                    ie. use default values for function parameters which depend on previous
                    function parameters.
                    This can be very practical at times :

                    before (suppose 'info' is a class which has "text" and "htmlclass" as
                    members):

                    def format_informat ion( info, htmlclass = None ):
                    if htmlclass == None:
                    htmlclass = info.htmlclass
                    return "<p class=%s>%s</p>" % (htmlclass, info.text )

                    after:

                    def format_informat ion( info, htmlclass = info.htmlcass ):
                    return "<p class=%s>%s</p>" % (htmlclass, info.text )


                    the intended use would be :
                    format_informat ion( info )
                    format_informat ion( info, 'red_text' ) overrides the html_class in info.


                    The former example could be simplified (below) but I still think the
                    second example using your choice 2 is more elegant.

                    def format_informat ion( info, htmlclass = None ):
                    return "<p class=%s>%s</p>" % (htmlclass or info.htmlclass, info.text )

                    Comment

                    • Pierre-Frédéric Caillaud

                      #25
                      Re: mutable default parameter problem [Prothon]



                      [color=blue]
                      > I'm new to python. To my eyes this is a pretty poor attempt to
                      > have static variables. I've implemented in the past a few[/color]

                      static variables in python

                      def accumulate( x ):
                      accumulate.accu mulator += x
                      return accumulate.accu mulator

                      accumulate.accu mulator = 0

                      Comment

                      • Grégoire Dooms

                        #26
                        Re: mutable default parameter problem [Prothon]

                        Mark Hahn wrote:[color=blue]
                        > Troy Melhase wrote:
                        >
                        >[color=green]
                        >>Here's an idea: if it ain't broke, don't fix it.
                        >>
                        >>Seriously, you see a "wart" and a "problem". I see a pleasant
                        >>side-effect of the documented semantics. True, new folks are
                        >>surprised by the behavior, but once it's understood, it becomes more
                        >>powerful.[/color]
                        >
                        >
                        > All four of the Python gotcha's, wart's and regrets lists I have found
                        > included this problem. It is not only a newbie's problem as I showed in my
                        > posting.
                        >
                        >[color=green]
                        >>How do you intend to account for code like this:
                        >>
                        >>def F(a, b, cache={}):
                        >> try:
                        >> return cache[(a,b)]
                        >> except (IndexError, ):
                        >> value = cache[(a,b)] = do_some_long_ca lc(a,b)
                        >> return value
                        >>
                        >>Or even this:
                        >>
                        >>shared_cach e = {}
                        >>
                        >>def F(a, b, cache=shared_ca che):
                        >> ...[/color]
                        >
                        >
                        > The first example is very unreadable and uncool in general. Your second
                        > example will work just fine with our fix.
                        >
                        >[color=green]
                        >>Of course you can argue that this is bad style,[/color]
                        >
                        >
                        > Yes I (and many others) will.
                        >
                        >[color=green]
                        >>but the counter
                        >>argument is just as strong: this is quite pythonic and quite
                        >>readable.[/color]
                        >
                        >
                        > I disagree strongly. I would never be caught coding something like that and
                        > I love Python dearly.
                        >
                        >[color=green]
                        >>Python is a tool, and you decrease the utility of that tool when you
                        >>limit it's idioms.[/color]
                        >
                        >
                        > So far you have only shown me an idiom that many say should not be used.
                        > Show me one that everyone agrees is useful.
                        >
                        >[color=green][color=darkred]
                        >>>How much Python code would these different proposals break?[/color]
                        >>
                        >>A lot. I ran this:
                        >>
                        >>$ find /usr/lib/python2.3/ -name "*.py" -exec grep "def.*=\[\]" {}
                        >>\; | wc
                        >>
                        >>And see 67 instances just in the standard library. Multiply that by
                        >>a factor of 1000, 10000 or more to reflect code in the field, and you
                        >>might start to understand the significance of changing the language
                        >>definition.[/color]
                        >
                        >
                        > That count is not accurate. Fixing this will not break every use of [] as a
                        > default formal param. Using [] in __init__ for example would break nothing.
                        > I can think of many other cases where it is legal to use []. The only case
                        > I can think of that would break would be the idiom we disagree on above. If
                        > I am wrong, then show me other cases.
                        >[/color]

                        Right. I'd like to see how many of these 67 instances of mutable def
                        args actually mutates them. I hope it is 0. In this case the proposed
                        modification would break nothing at all.

                        But I wonder what the actual semantics of the second proposal are.

                        You say the default argument is evaluated in its declaration context at
                        each call. But is that evaluation context garanteed to be the same at
                        every call ?

                        #Ex:
                        x=0
                        def t(a,b,c=x+1):
                        # could I assert c==1 if t called with 2 args ?

                        def make_some_obj() :
                        return []
                        def t(a,b,c=make_so me_obj()):
                        # can I assert c==[] if t called with 2 args ?

                        I think every data coming from outside the expression (the variables in
                        the expression including the global variables accessed from a function)
                        should be preserved. Let aside the eventual mutable state stored in an
                        object:

                        #Ex:
                        class Inc:
                        def __init__(self):
                        self.x=0
                        def newval():
                        self.x += 1
                        return self.x
                        x=Inc()
                        def t(a,b,c=x.newva l()):
                        # can I assert c will increase by 1 at each call with 2 args ?


                        [color=blue]
                        > If I also might make a general argument for the fix then let me continue.
                        > Doing a late evaluation of the default expression makes the language more
                        > dynamic, which fits the overall goal of making Prothon more dynamic. Using
                        > prototypes instead of classes, dynamic var scoping, this fix, and many other
                        > Prothon changes from Python all work towards that goal.
                        >
                        > Dynamic var scoping fixed another Python gotcha which doesn't break
                        > anything. Here are the two versions of code showing the problem and the
                        > fix:
                        >
                        > --- Python ---
                        >
                        >[color=green][color=darkred]
                        >>>>x = 1
                        >>>>def f():[/color][/color]
                        >
                        > ... x = x + 1
                        > ... print x
                        > ...
                        >[color=green][color=darkred]
                        >>>>f()[/color][/color]
                        >
                        > UnboundLocalErr or: local variable 'x' referenced before assignment
                        >
                        > --- Prothon ---
                        >
                        > O>> x = 1
                        > 1
                        > O>> def f():
                        > ... x = x + 1
                        > ... print x
                        > ...
                        > O>> f()
                        > 2
                        >
                        > Prothon's scoping rules are dynamic which means that x comes from outside
                        > the function until the actual assignment happens. At that point x becomes a
                        > local variable. This, along with the fact that vars are inherited from
                        > ancestors along with methods, allow for some intuitive and simple var
                        > initialization techniques.[/color]

                        So then
                        0>> f()
                        2
                        0>> x
                        1
                        [color=blue]
                        >
                        > Obviously it is the responsibility of the programmer to make sure that the
                        > outer x has the proper initialization value for the local x. This can cause
                        > a hiding-of-uninitialized-vars bug if the programmer uses the same names for
                        > unrelated variables but it is worth the extra power and intuitiveness.
                        >[/color]

                        Nice, I had never heard about Prothon. I'll give it a look.


                        --
                        Grégoire Dooms

                        Comment

                        • Pierre-Frédéric Caillaud

                          #27
                          Re: mutable default parameter problem [Prothon]


                          [color=blue]
                          > 2) Evaluate the default expression once at each call time when the
                          > default
                          > value is needed. The default expression would be evaluated in the
                          > context
                          > of the function definition (like a closure).[/color]


                          I like Choice 2 because I've always wanted to do the following :

                          def func( x, y=2*x ):
                          do stuff...

                          ie. use default values for function parameters which depend on previous
                          function parameters.
                          This can be very practical at times :

                          before (suppose 'info' is a class which has "text" and "htmlclass" as
                          members):

                          def format_informat ion( info, htmlclass = None ):
                          if htmlclass == None:
                          htmlclass = info.htmlclass
                          return "<p class=%s>%s</p>" % (htmlclass, info.text )

                          after:

                          def format_informat ion( info, htmlclass = info.htmlcass ):
                          return "<p class=%s>%s</p>" % (htmlclass, info.text )


                          the intended use would be :
                          format_informat ion( info )
                          format_informat ion( info, 'red_text' ) overrides the html_class in info.


                          The former example could be simplified (below) but I still think the
                          second example using your choice 2 is more elegant.

                          def format_informat ion( info, htmlclass = None ):
                          return "<p class=%s>%s</p>" % (htmlclass or info.htmlclass, info.text )
                          --
                          Using Opera's revolutionary e-mail client: http://www.opera.com/m2/

                          Comment

                          • Pierre-Frédéric Caillaud

                            #28
                            Re: mutable default parameter problem [Prothon]



                            [color=blue]
                            > I'm new to python. To my eyes this is a pretty poor attempt to
                            > have static variables. I've implemented in the past a few[/color]

                            static variables in python

                            def accumulate( x ):
                            accumulate.accu mulator += x
                            return accumulate.accu mulator

                            accumulate.accu mulator = 0
                            --
                            Using Opera's revolutionary e-mail client: http://www.opera.com/m2/

                            Comment

                            • Mark Hahn

                              #29
                              Re: mutable default parameter problem [Prothon]

                              Grégoire Dooms wrote:
                              [color=blue]
                              > But I wonder what the actual semantics of the second proposal are.
                              >
                              > You say the default argument is evaluated in its declaration context
                              > at each call. But is that evaluation context garanteed to be the same
                              > at every call ?
                              >
                              > #Ex:
                              > x=0
                              > def t(a,b,c=x+1):
                              > # could I assert c==1 if t called with 2 args ?[/color]

                              No, because x could change value. If you wanted that then you would say
                              c=1. When you say c = x+1 you get x+1, no more, no less. You can code it
                              to get whatever you want.
                              [color=blue]
                              > def make_some_obj() :
                              > return []
                              > def t(a,b,c=make_so me_obj()):
                              > # can I assert c==[] if t called with 2 args ?[/color]

                              This case would always give you [], unless you redefined make_some_obj :-)
                              This is a dynamic language after all.
                              [color=blue]
                              > I think every data coming from outside the expression (the variables
                              > in the expression including the global variables accessed from a
                              > function) should be preserved. Let aside the eventual mutable state
                              > stored in an object:
                              >
                              > #Ex:
                              > class Inc:
                              > def __init__(self):
                              > self.x=0
                              > def newval():
                              > self.x += 1
                              > return self.x
                              > x=Inc()
                              > def t(a,b,c=x.newva l()):
                              > # can I assert c will increase by 1 at each call with 2 args ?[/color]

                              If you really want this then you should be asking for solution 3, which just
                              keeps the results of the expression evalutation at definition time and then
                              makes a copy at each call. You would be the only one asking for solution 3
                              so far. It appears that we are going with solution 2.
                              [color=blue]
                              > Nice, I had never heard about Prothon. I'll give it a look.[/color]

                              You can find it at http://prothon.org. Hang out on the Prothon mailing list
                              for a while. We are discussing some really fun stuff.


                              Comment

                              • Mark Hahn

                                #30
                                Re: mutable default parameter problem [Prothon]

                                Pierre-Frédéric Caillaud wrote:
                                [color=blue][color=green]
                                >> 2) Evaluate the default expression once at each call time when the
                                >> default
                                >> value is needed. The default expression would be evaluated in the
                                >> context
                                >> of the function definition (like a closure).[/color]
                                >
                                >
                                > I like Choice 2 because I've always wanted to do the following :
                                >
                                > def func( x, y=2*x ):[/color]

                                It looks like you will get your wish. The voting has been pretty much
                                unanimous for option 2.


                                Comment

                                Working...