function that accepts any amount of arguments?

Discussion in 'Python' started by globalrev, Apr 24, 2008.

  1. globalrev

    globalrev Guest

    if i want a function that can take any amount of arguments how do i
    do?

    lets say i want a function average that accepts any number of integers
    and returns the average.
     
    globalrev, Apr 24, 2008
    #1
    1. Advertising

  2. globalrev

    Paul McNett Guest

    globalrev wrote:
    > if i want a function that can take any amount of arguments how do i
    > do?


    Put an asterisk before the argument name.


    > lets say i want a function average that accepts any number of integers
    > and returns the average.


    def avg(*args):
    return sum(args) / len(args)

    There are some dangers (at least two glaring ones) with this code,
    though, which I leave as an exercise for the reader.

    :)

    Paul
     
    Paul McNett, Apr 24, 2008
    #2
    1. Advertising

  3. globalrev

    Steve Holden Guest

    globalrev wrote:
    > if i want a function that can take any amount of arguments how do i
    > do?
    >
    > lets say i want a function average that accepts any number of integers
    > and returns the average.


    Use a parameter of the form *args - the asterisk tells the interpreter
    to collect positional arguments into a tuple. Untested:

    def mean(*x):
    total = 0.0
    for v in x:
    total += v
    return v/len(x)

    regards
    Steve
    --
    Steve Holden +1 571 484 6266 +1 800 494 3119
    Holden Web LLC http://www.holdenweb.com/
     
    Steve Holden, Apr 24, 2008
    #3
  4. globalrev

    Terry Reedy Guest

    "globalrev" <> wrote in message
    news:...
    | if i want a function that can take any amount of arguments how do i
    | do?
    |
    | lets say i want a function average that accepts any number of integers
    | and returns the average.

    To add to the other comments, read the ref manual section of function defs.
     
    Terry Reedy, Apr 24, 2008
    #4
  5. globalrev

    Steve Holden Guest

    Ken wrote:
    > "Steve Holden" <> wrote in message

    [...]
    >> def mean(*x):
    >> total = 0.0
    >> for v in x:
    >> total += v
    >> return v/len(x)
    >>

    >
    > think you want total/len(x) in return statement
    >

    Yes indeed, how glad I am I wrote "untested". I clearly wasn't pair
    programming when I wrote this post ;-)

    regards
    Steve
    --
    Steve Holden +1 571 484 6266 +1 800 494 3119
    Holden Web LLC http://www.holdenweb.com/
     
    Steve Holden, Apr 24, 2008
    #5
  6. Paul McNett a écrit :
    >
    > def avg(*args):
    > return sum(args) / len(args)
    >
    > There are some dangers (at least two glaring ones) with this code,
    > though, which I leave as an exercise for the reader.


    try:
    avg("toto", 42)
    except TypeError, e:
    print "this is the first one : %s" % e
    try:
    avg()
    except ZeroDivisionError, e:
    print "this is the second : %s" % e

    As far as I'm concerned, I would not handle the first one in the avg
    function - just document that avg expects numeric args.

    Not quite sure what's the best thing to do in the second case - raise a
    ValueError if args is empty, or silently return 0.0 - but I'd tend to
    choose the first solution (Python's Zen, verses 9-11).
     
    Bruno Desthuilliers, Apr 24, 2008
    #6
  7. globalrev

    malkarouri Guest

    On Apr 24, 12:43 pm, Bruno Desthuilliers <bruno.
    > wrote:
    [...]
    > Not quite sure what's the best thing to do in the second case - raise a
    > ValueError if args is empty, or silently return 0.0 - but I'd tend to
    > choose the first solution (Python's Zen, verses 9-11).


    What's wrong with raising ZeroDivisionError (not stopping the
    exception in the first place)?

    k
     
    malkarouri, Apr 24, 2008
    #7
  8. On Apr 24, 5:28 am, malkarouri <> wrote:
    >
    > What's wrong with raising ZeroDivisionError (not stopping the
    > exception in the first place)?
    >


    Because when I use your module, call avg (or mean) without args, I
    should see an error that says, "Hey, you have to pass at least one
    value in!"

    ZeroDivisonError doesn't mean that. It means I tried to divide by
    zero. Naively, I don't see where I was dividing by zero (because I
    don't remember how to calculate the mean---that's what your code was
    for.)

    ValueError does mean that I didn't pass the right kind of arguments
    in. ValueError("No items specified") would be even clearer. (Or maybe
    TypeError?)

    In general, any exception thrown should be meaningful to the code you
    are throwing it to. That means they aren't familiar with how your code
    works.
     
    Jonathan Gardner, Apr 24, 2008
    #8
  9. globalrev

    Steve Holden Guest

    Jonathan Gardner wrote:
    > On Apr 24, 5:28 am, malkarouri <> wrote:
    >> What's wrong with raising ZeroDivisionError (not stopping the
    >> exception in the first place)?
    >>

    >
    > Because when I use your module, call avg (or mean) without args, I
    > should see an error that says, "Hey, you have to pass at least one
    > value in!"
    >
    > ZeroDivisonError doesn't mean that. It means I tried to divide by
    > zero. Naively, I don't see where I was dividing by zero (because I
    > don't remember how to calculate the mean---that's what your code was
    > for.)
    >
    > ValueError does mean that I didn't pass the right kind of arguments
    > in. ValueError("No items specified") would be even clearer. (Or maybe
    > TypeError?)
    >
    > In general, any exception thrown should be meaningful to the code you
    > are throwing it to. That means they aren't familiar with how your code
    > works.
    >


    This is Advice. Software Engineering's next door ;-)

    regards
    Steve
    --
    Steve Holden +1 571 484 6266 +1 800 494 3119
    Holden Web LLC http://www.holdenweb.com/
     
    Steve Holden, Apr 24, 2008
    #9
  10. globalrev

    Guest

    On 24 avr, 14:28, malkarouri <> wrote:
    > On Apr 24, 12:43 pm, Bruno Desthuilliers <> wrote:
    >
    > [...]
    >
    > > Not quite sure what's the best thing to do in the second case - raise a
    > > ValueError if args is empty, or silently return 0.0 - but I'd tend to
    > > choose the first solution (Python's Zen, verses 9-11).

    >
    > What's wrong with raising ZeroDivisionError (not stopping the
    > exception in the first place)?


    Because - from a semantic POV - the real error is not that you're
    trying to divide zero by zero, but that you failed to pass any
    argument. FWIW, I'd personnaly write avg as taking a sequence - ie,
    not using varargs - in which case calling it without arguments would a
    TypeError (so BTW please s/Value/Type/ in my previous post).
     
    , Apr 24, 2008
    #10
  11. On 4/24/08, Jonathan Gardner <> wrote:
    > On Apr 24, 5:28 am, malkarouri <> wrote:
    > >
    > > What's wrong with raising ZeroDivisionError (not stopping the
    > > exception in the first place)?
    > >

    >
    >
    > Because when I use your module, call avg (or mean) without args, I
    > should see an error that says, "Hey, you have to pass at least one
    > value in!"
    >
    > ZeroDivisonError doesn't mean that. It means I tried to divide by
    > zero. Naively, I don't see where I was dividing by zero (because I
    > don't remember how to calculate the mean---that's what your code was
    > for.)
    >
    > ValueError does mean that I didn't pass the right kind of arguments
    > in. ValueError("No items specified") would be even clearer. (Or maybe
    > TypeError?)
    >
    > In general, any exception thrown should be meaningful to the code you
    > are throwing it to. That means they aren't familiar with how your code
    > works.
    >


    [source]|557> def average(n, *ints):
    |...> return (sum(ints)+n) / (len(ints) + 1)
    |...>
    [source]|558> average (1,2,3)
    <558> 2
    [source]|559> average(3)
    <559> 3
    [source]|560> average(1,2)
    <560> 1
    [source]|561> average(0)
    <561> 0
    [source]|562> average()
    ---------------------------------------------------------------------------
    TypeError Traceback (most recent call last)

    /usr/share/doc/packages/python-dateutil/source/<ipython console> in <module>()

    TypeError: average() takes at least 1 argument (0 given)
     
    member thudfoo, Apr 24, 2008
    #11
  12. globalrev

    Steve Holden Guest

    member thudfoo wrote:
    > On 4/24/08, Jonathan Gardner <> wrote:
    >> On Apr 24, 5:28 am, malkarouri <> wrote:
    >> >
    >> > What's wrong with raising ZeroDivisionError (not stopping the
    >> > exception in the first place)?
    >> >

    >>
    >>
    >> Because when I use your module, call avg (or mean) without args, I
    >> should see an error that says, "Hey, you have to pass at least one
    >> value in!"
    >>
    >> ZeroDivisonError doesn't mean that. It means I tried to divide by
    >> zero. Naively, I don't see where I was dividing by zero (because I
    >> don't remember how to calculate the mean---that's what your code was
    >> for.)
    >>
    >> ValueError does mean that I didn't pass the right kind of arguments
    >> in. ValueError("No items specified") would be even clearer. (Or maybe
    >> TypeError?)
    >>
    >> In general, any exception thrown should be meaningful to the code you
    >> are throwing it to. That means they aren't familiar with how your code
    >> works.
    >>

    >
    > [source]|557> def average(n, *ints):
    > |...> return (sum(ints)+n) / (len(ints) + 1)
    > |...>
    > [source]|558> average (1,2,3)
    > <558> 2
    > [source]|559> average(3)
    > <559> 3
    > [source]|560> average(1,2)
    > <560> 1
    > [source]|561> average(0)
    > <561> 0
    > [source]|562> average()
    > ---------------------------------------------------------------------------
    > TypeError Traceback (most recent call last)
    >
    > /usr/share/doc/packages/python-dateutil/source/<ipython console> in <module>()
    >
    > TypeError: average() takes at least 1 argument (0 given)
    > --
    > http://mail.python.org/mailman/listinfo/python-list
    >

    It would also be usual to use floating arithmetic to ensure that the
    mean of 1 and 2 was 1.5 rather than 1.

    regards
    Steve
    --
    Steve Holden +1 571 484 6266 +1 800 494 3119
    Holden Web LLC http://www.holdenweb.com/
     
    Steve Holden, Apr 24, 2008
    #12
  13. globalrev

    Steve Holden Guest

    Nick Craig-Wood wrote:
    > Steve Holden <> wrote:
    >> Ken wrote:
    >>> "Steve Holden" <> wrote in message

    >> [...]
    >>>> def mean(*x):
    >>>> total = 0.0
    >>>> for v in x:
    >>>> total += v
    >>>> return v/len(x)
    >>>>
    >>> think you want total/len(x) in return statement
    >>>

    >> Yes indeed, how glad I am I wrote "untested". I clearly wasn't pair
    >> programming when I wrote this post ;-)

    >
    > Posting to comp.lang.python is pair programming with the entire
    > internet ;-)
    >
    >

    +1 QOTW :)

    regards
    Steve
    --
    Steve Holden +1 571 484 6266 +1 800 494 3119
    Holden Web LLC http://www.holdenweb.com/
     
    Steve Holden, Apr 25, 2008
    #13
  14. globalrev

    Lie Guest

    On Apr 25, 2:12 am, ""
    <> wrote:
    > On 24 avr, 14:28, malkarouri <> wrote:
    >
    > > On Apr 24, 12:43 pm, Bruno Desthuilliers <> wrote:

    >
    > > [...]

    >
    > > > Not quite sure what's the best thing to do in the second case - raise a
    > > > ValueError if args is empty, or silently return 0.0 - but I'd tend to
    > > > choose the first solution (Python's Zen, verses 9-11).

    >
    > > What's wrong with raising ZeroDivisionError (not stopping the
    > > exception in the first place)?

    >
    > Because - from a semantic POV -  the real error is not that you're
    > trying to divide zero by zero, but that you failed to pass any
    > argument. FWIW, I'd personnaly write avg as taking a sequence - ie,
    > not using varargs - in which case calling it without arguments would a
    > TypeError (so BTW please s/Value/Type/ in my previous post).


    The problem with passing it as a sequence is, if you want to call it,
    you may have to wrestle with this odd looking code:
    avg((3, 4, 6, 7))

    rather than this, more natural code:
    avg(3, 4, 6, 7)

    And FWIW, the OP asked if it is possible to pass variable amount of
    arguments, avg is just a mere example of one where it could be used
    not where it could be best used.

    Nick Craig-Wood wrote:
    > Steve Holden <> wrote:
    >> Ken wrote:
    >>> "Steve Holden" <> wrote in message

    >> [...]
    >>>> def mean(*x):
    >>>> total = 0.0
    >>>> for v in x:
    >>>> total += v
    >>>> return v/len(x)


    >>> think you want total/len(x) in return statement


    >> Yes indeed, how glad I am I wrote "untested". I clearly wasn't pair
    >> programming when I wrote this post ;-)


    > Posting to comp.lang.python is pair programming with the entire
    > internet ;-)


    No, actually it's pair programming with the readers of c.l.py (or more
    accurately with the readers of c.l.py that happens to pass the said
    thread).
     
    Lie, Apr 26, 2008
    #14
  15. Lie a écrit :
    > On Apr 25, 2:12 am, ""
    > <> wrote:


    (...)

    >> FWIW, I'd personnaly write avg as taking a sequence - ie,
    >> not using varargs - in which case calling it without arguments would a
    >> TypeError (so BTW please s/Value/Type/ in my previous post).

    >
    > The problem with passing it as a sequence is, if you want to call it,
    > you may have to wrestle with this odd looking code:
    > avg((3, 4, 6, 7))
    >
    > rather than this, more natural code:
    > avg(3, 4, 6, 7)


    Possibly. Yet my experience is that, most of the time, such a function
    will be called with an already existing sequence, so the most common
    call scheme is

    res = avg(some_sequence)

    which is more natural than

    res = avg(*some_sequence)

    !-)


    > And FWIW, the OP asked if it is possible to pass variable amount of
    > arguments, avg is just a mere example of one where it could be used
    > not where it could be best used.


    Indeed - but that's not what I was commenting on.
     
    Bruno Desthuilliers, Apr 28, 2008
    #15
    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. winbatch
    Replies:
    5
    Views:
    571
    Winbatch
    Feb 15, 2005
  2. titancipher
    Replies:
    4
    Views:
    515
    titancipher
    Jun 13, 2005
  3. Jeff Rodriguez
    Replies:
    1
    Views:
    322
    Mark McIntyre
    Dec 7, 2003
  4. jmborr
    Replies:
    1
    Views:
    423
    Stargaming
    Nov 3, 2007
  5. Peng Yu
    Replies:
    12
    Views:
    709
    kwikius
    Sep 7, 2008
Loading...

Share This Page