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

Discussion in 'Python' started by K. Jansma, Feb 18, 2006.

  1. K. Jansma

    K. Jansma Guest

    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)

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

    [0]
    >>> a.f(0)

    [0, 0]
    >>> a.f(0)

    [0, 0, 0]
    >>> b = Test()
    >>> b.f(0)

    [0]

    But this is what I get:

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

    [0]
    >>> a.f(0)

    [0, 0]
    >>> a.f(0)

    [0, 0, 0]
    >>> b = Test()
    >>> b.f(0)

    [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.
     
    K. Jansma, Feb 18, 2006
    #1
    1. Advertising

  2. K. Jansma

    Duncan Booth Guest

    K. Jansma wrote:

    > 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__?
    >


    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
     
    Duncan Booth, Feb 18, 2006
    #2
    1. Advertising

  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:
    > How can I avoid this without using eg. self.L in an __init__?


    Why not use it? That's how it's meant to be done!

    > Thanks in advance,
    > Karel.


    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"
     
    Felipe Almeida Lessa, Feb 18, 2006
    #3
  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:
    > 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


    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"
     
    Felipe Almeida Lessa, Feb 18, 2006
    #4
  5. K. Jansma

    Ben Finney Guest

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

    Duncan Booth <> writes:
    > 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:


    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.id.au/>
     
    Ben Finney, Feb 18, 2006
    #5
  6. K. Jansma

    Duncan Booth Guest

    Ben Finney wrote:

    > Duncan Booth <> writes:
    >> 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:

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


    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).
     
    Duncan Booth, Feb 20, 2006
    #6
  7. On Mon, 20 Feb 2006 08:52:09 +0000, Duncan Booth wrote:

    > Ben Finney wrote:
    >
    >> Duncan Booth <> writes:
    >>> 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:

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

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



    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(location):
    if name.endswith(".py") and os.path.isfile(location+name):
    try:
    fp = file(location+name, "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("None")
    # 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*100)
     
    Steven D'Aprano, Feb 20, 2006
    #7
  8. K. Jansma

    Duncan Booth Guest

    Steven D'Aprano wrote:

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

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

    >
    >
    > 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.


    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.b64encode & base64.b64decode avoid part of the code if passed
    None, but don't actually substitute another value in place of the default.

    cgi.FieldStorage 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.
     
    Duncan Booth, Feb 21, 2006
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Lars Uffmann

    tmpnam behaviour on subsequent calls

    Lars Uffmann, Jan 18, 2008, in forum: C++
    Replies:
    8
    Views:
    1,203
    James Kanze
    Jan 22, 2008
  2. Michel Rouzic
    Replies:
    4
    Views:
    1,858
    Michel Rouzic
    Apr 28, 2008
  3. Saraswati lakki
    Replies:
    0
    Views:
    1,411
    Saraswati lakki
    Jan 6, 2012
  4. Replies:
    0
    Views:
    102
  5. Bob
    Replies:
    5
    Views:
    290
Loading...

Share This Page