share function argument between subsequent calls but not between class instances!

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

    #1

    share function argument between subsequent calls but not between class instances!

    Hi,

    given the following example class

    class Test:
    def f(self,a, L=[]):
    L.append(a)
    return L

    and the following statements

    a = Test()
    a.f(0)
    a.f(0)
    a.f(0)
    b = Test()
    b.f(0)

    this is the output I would like to have (i.e., expect)
    [color=blue][color=green][color=darkred]
    >>> a = Test()
    >>> a.f(0)[/color][/color][/color]
    [0][color=blue][color=green][color=darkred]
    >>> a.f(0)[/color][/color][/color]
    [0, 0][color=blue][color=green][color=darkred]
    >>> a.f(0)[/color][/color][/color]
    [0, 0, 0][color=blue][color=green][color=darkred]
    >>> b = Test()
    >>> b.f(0)[/color][/color][/color]
    [0]

    But this is what I get:
    [color=blue][color=green][color=darkred]
    >>> a = Test()
    >>> a.f(0)[/color][/color][/color]
    [0][color=blue][color=green][color=darkred]
    >>> a.f(0)[/color][/color][/color]
    [0, 0][color=blue][color=green][color=darkred]
    >>> a.f(0)[/color][/color][/color]
    [0, 0, 0][color=blue][color=green][color=darkred]
    >>> b = Test()
    >>> b.f(0)[/color][/color][/color]
    [0, 0, 0, 0]


    as you can see, the b.f method shares L with a.f.
    How can I avoid this without using eg. self.L in an __init__?

    Thanks in advance,
    Karel.

  • Duncan Booth

    #2
    Re: share function argument between subsequent calls but not between class instances!

    K. Jansma wrote:
    [color=blue]
    > as you can see, the b.f method shares L with a.f.
    > How can I avoid this without using eg. self.L in an __init__?
    >[/color]

    You cannot.

    If a method argument has a default value then the same default is used
    whenever the method is called. If you want each instance to have its own
    value then you must use an attribute on the instance.

    If you intend to only use the default some of the time, and at other times
    pass in a different list, then save the 'default' in the instance and use a
    special marker value to indicate when you intend the default to be used:

    marker = object()

    class Test(object):
    def __init__(self):
    self.L = []

    def f(self,a, L=marker):
    if L is marker:
    L = self.L
    L.append(a)
    return L

    Comment

    • Felipe Almeida Lessa

      #3
      Re: share function argument between subsequent calls but notbetween class instances!

      Em Sáb, 2006-02-18 às 17:42 +0100, K. Jansma escreveu:[color=blue]
      > How can I avoid this without using eg. self.L in an __init__?[/color]

      Why not use it? That's how it's meant to be done!
      [color=blue]
      > Thanks in advance,
      > Karel.[/color]

      Cya,
      Felipe.

      --
      "Quem excele em empregar a força militar subjulga os exércitos dos
      outros povos sem travar batalha, toma cidades fortificadas dos outros
      povos sem as atacar e destrói os estados dos outros povos sem lutas
      prolongadas. Deve lutar sob o Céu com o propósito primordial da
      'preservação' . Desse modo suas armas não se embotarão, e os ganhos
      poderão ser preservados. Essa é a estratégia para planejar ofensivas."

      -- Sun Tzu, em "A arte da guerra"

      Comment

      • Felipe Almeida Lessa

        #4
        Re: share function argument between subsequent calls but notbetween class instances!

        Em Sáb, 2006-02-18 às 16:50 +0000, Duncan Booth escreveu:[color=blue]
        > marker = object()
        >
        > class Test(object):
        > def __init__(self):
        > self.L = []
        >
        > def f(self,a, L=marker):
        > if L is marker:
        > L = self.L
        > L.append(a)
        > return L[/color]

        As hasattr(None, "append") == False, you could also do:

        class Test(object):
        def __init__(self):
        self.L = []

        def f(self, a, L=None):
        if L is None:
        L = self.L
        L.append(a)
        return L

        --
        "Quem excele em empregar a força militar subjulga os exércitos dos
        outros povos sem travar batalha, toma cidades fortificadas dos outros
        povos sem as atacar e destrói os estados dos outros povos sem lutas
        prolongadas. Deve lutar sob o Céu com o propósito primordial da
        'preservação' . Desse modo suas armas não se embotarão, e os ganhos
        poderão ser preservados. Essa é a estratégia para planejar ofensivas."

        -- Sun Tzu, em "A arte da guerra"

        Comment

        • Ben Finney

          #5
          Re: share function argument between subsequent calls but notbetween class instances!

          Duncan Booth <duncan.booth@i nvalid.invalid> writes:[color=blue]
          > If you intend to only use the default some of the time, and at other
          > times pass in a different list, then save the 'default' in the
          > instance and use a special marker value to indicate when you intend
          > the default to be used:[/color]

          The most common idiom for such a marker is the None value.

          class Test(object):
          def __init__(self):
          self.L = []
          def f(self, a, L=None):
          if L is None:
          L = self.L
          L.append(a)
          return L

          --
          \ "Consider the daffodil. And while you're doing that, I'll be |
          `\ over here, looking through your stuff." -- Jack Handey |
          _o__) |
          Ben Finney <http://www.benfinney.i d.au/>

          Comment

          • Duncan Booth

            #6
            Re: share function argument between subsequent calls but not between class instances!

            Ben Finney wrote:
            [color=blue]
            > Duncan Booth <duncan.booth@i nvalid.invalid> writes:[color=green]
            >> If you intend to only use the default some of the time, and at other
            >> times pass in a different list, then save the 'default' in the
            >> instance and use a special marker value to indicate when you intend
            >> the default to be used:[/color]
            >
            > The most common idiom for such a marker is the None value.
            >[/color]

            Can you provide any firm evidence that using None is more common?

            Both uses are common. Use whichever you are happier with (except of course
            in the case where None is a potential value distinct from the default).

            Comment

            • Steven D'Aprano

              #7
              Re: share function argument between subsequent calls but not between class instances!

              On Mon, 20 Feb 2006 08:52:09 +0000, Duncan Booth wrote:
              [color=blue]
              > Ben Finney wrote:
              >[color=green]
              >> Duncan Booth <duncan.booth@i nvalid.invalid> writes:[color=darkred]
              >>> If you intend to only use the default some of the time, and at other
              >>> times pass in a different list, then save the 'default' in the
              >>> instance and use a special marker value to indicate when you intend
              >>> the default to be used:[/color]
              >>
              >> The most common idiom for such a marker is the None value.
              >>[/color]
              >
              > Can you provide any firm evidence that using None is more common?[/color]


              Yes, I wrote a quick and dirty script to roughly count the default
              values in the Python 2.3 standard library. Here are my results:

              $ python default_counter .py
              185 .py source files were opened.
              4437 function or method definitions were found.
              These functions included at least 1228 arguments with default values.
              529 or 4.307818e+01% used None as the default value.

              So, roughly 40% of default values in the standard library are None. If I
              cared enough (I don't) I would re-write the counter to analyse all the
              default values. But by eye-balling the function lines, the impression I
              get is that the remaining 60% of default values are divided unequally
              between dozens of different defaults. Some random examples:

              "rb", "", "Prompt: ", -1, 0, 1, 3, sys.maxint, (), [].

              My gut-feeling would be, 40-odd percent None, 40-odd percent for small
              ints (-1, 0, 1, ..?), the remainder split between everything else.

              If anyone cares to look at my quick and dirty source code, it is attached
              following my signature.


              --
              Steven.




              * * *

              """Rough and ready script to analyse the Python standard library
              and count function definitions that use None as a default argument.
              """

              from __future__ import division
              import os

              location = "/usr/lib/python2.3/"

              file_count = 0 # number of files successfully opened
              func_count = 0 # number of function definitions
              default_count = 0 # number of functions with a default value
              none_count = 0 # number of functions with None as a default value

              for name in os.listdir(loca tion):
              if name.endswith(" .py") and os.path.isfile( location+name):
              try:
              fp = file(location+n ame, "r")
              except IOError:
              continue
              file_count += 1
              lines = fp.readlines()
              fp.close()
              for line in lines:
              line = line.strip()
              if line.startswith ("#"):
              continue
              elif line.startswith ("def "):
              func_count += 1
              default_count += line.count("=")
              none_count += line.count("Non e")
              # if line.count("=") : print line

              # Report results found:

              print "%d .py source files were opened." % file_count
              print "%d function or method definitions were found." % func_count
              print "These functions included at least %d arguments with default values." % default_count
              print "%d or %e%% used None as the default value." % \
              (none_count, none_count/default_count*1 00)


              Comment

              • Duncan Booth

                #8
                Re: share function argument between subsequent calls but not between class instances!

                Steven D'Aprano wrote:
                [color=blue][color=green][color=darkred]
                >>> The most common idiom for such a marker is the None value.
                >>>[/color]
                >>
                >> Can you provide any firm evidence that using None is more common?[/color]
                >
                >
                > Yes, I wrote a quick and dirty script to roughly count the default
                > values in the Python 2.3 standard library. Here are my results:
                >
                > $ python default_counter .py
                > 185 .py source files were opened.
                > 4437 function or method definitions were found.
                > These functions included at least 1228 arguments with default values.
                > 529 or 4.307818e+01% used None as the default value.
                >
                > So, roughly 40% of default values in the standard library are None.[/color]

                Fair enough, although I would point out that you haven't made any attempt
                to distinguish those cases where None is being used as a marker from the
                cases where it is being used as a value in its own right or a flag to
                control the function logic.

                The marker cases do seem to be the most common but there are plenty of
                other cases:

                e.g. base64.b64encod e & base64.b64decod e avoid part of the code if passed
                None, but don't actually substitute another value in place of the default.

                cgi.FieldStorag e has methods getvalue, getfirst where the default=None is
                simply that: the default to be returned. The make_file method has a
                defaulted argument which it doesn't use at all.

                Also, most of the standard library predates a time when you could create a
                unique marker value just by calling 'object()'. When it was written None
                was by far the simplest option even in cases where a separate marker value
                might have been more appropriate.

                Comment

                Working...