Checking default arguments

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Igor V. Rafienko

    #1

    Checking default arguments


    Hi,


    I was wondering whether it was possible to find out which parameter
    value is being used: the default argument or the user-supplied one.
    That is:

    def foo(x, y="bar"):
    # how to figure out whether the value of y is
    # the default argument, or user-supplied?

    foo(1, "bar") =user-supplied
    foo(1) =default

    {}.pop seems to be able to make this dictinction.

    I've checked the inspect module, but nothing obvious jumped at me. Any
    hints?

    Thanks,





    ivr
    --
    "...but it's HDTV -- it's got a better resolution than the real world."
    -- Fry, "When aliens attack"
  • Neil Cerutti

    #2
    Re: Checking default arguments

    On 2007-02-02, Igor V. Rafienko <igorr@ifi.uio. nowrote:
    Hi,
    >
    I was wondering whether it was possible to find out which
    parameter value is being used: the default argument or the
    user-supplied one. That is:
    >
    def foo(x, y="bar"):
    # how to figure out whether the value of y is
    # the default argument, or user-supplied?
    >
    foo(1, "bar") =user-supplied
    foo(1) =default
    >
    {}.pop seems to be able to make this dictinction.
    You can fake it (this may be how dict.pop work) by not providing
    defaults, but using positional arguments.

    Here's a silly example, which returns a tuple if the user
    supplies the second argument, and a list otherwise.

    def foo(x, *args):
    if len(args) == 0:
    y_provided = True
    y = "bar"
    else:
    y_provided = False
    y = args[0]
    if y_provided:
    return (x, y)
    else:
    return [x, y]

    --
    Neil Cerutti
    Wonderful bargains for men with 16 and 17 necks --sign at clothing store

    Comment

    • Steven Bethard

      #3
      Re: Checking default arguments

      Igor V. Rafienko wrote:
      I was wondering whether it was possible to find out which parameter
      value is being used: the default argument or the user-supplied one.
      That is:
      >
      def foo(x, y="bar"):
      # how to figure out whether the value of y is
      # the default argument, or user-supplied?
      >
      foo(1, "bar") =user-supplied
      foo(1) =default
      Why are you trying to make this distinction? That is, why should passing
      in "bar" be any different from getting the default value "bar"

      You could do something like::
      >>def foo(x='b a r'):
      ... if x is foo.func_defaul ts[0]:
      ... print 'default'
      ... else:
      ... print 'supplied'
      ...
      >>foo('b a r')
      supplied
      >>foo()
      default

      But that won't really work if your default value gets interned by
      Python, like small integers or identifier-like string literals::
      >>def foo(x='bar'):
      ... if x is foo.func_defaul ts[0]:
      ... print 'default'
      ... else:
      ... print 'supplied'
      ...
      >>bar = ''.join(chr(i) for i in [98, 97, 114])
      >>foo(bar)
      supplied
      >>foo('bar')
      default


      STeVe

      Comment

      • Gabriel Genellina

        #4
        Re: Checking default arguments

        En Fri, 02 Feb 2007 15:30:53 -0300, Igor V. Rafienko <igorr@ifi.uio. no>
        escribió:
        >I was wondering whether it was possible to find out which parameter
        value is being used: the default argument or the user-supplied one.
        That is:
        >
        def foo(x, y="bar"):
        # how to figure out whether the value of y is
        # the default argument, or user-supplied?
        >
        foo(1, "bar") =user-supplied
        foo(1) =default
        You can use None as a flag:

        def foo(x, y=None):
        if y is None: y="bar"
        ...

        If None is valid, use your own flag:

        _marker=object( )
        def foo(x, y=_marker):
        if y is _marker: y="bar"
        ...

        --
        Gabriel Genellina

        Comment

        • Ben Finney

          #5
          Re: Checking default arguments

          igorr@ifi.uio.n o (Igor V. Rafienko) writes:
          I was wondering whether it was possible to find out which parameter
          value is being used: the default argument or the user-supplied one.
          That is:
          >
          def foo(x, y="bar"):
          # how to figure out whether the value of y is
          # the default argument, or user-supplied?
          If it doesn't make a difference, use "bar".

          If it *does* make a difference, use a unique object:

          ===== wombat.py =====
          Y_DEFAULT = object()

          def foo(x, y=Y_DEFAULT):
          if y is Y_DEFAULT:
          # no value for y was supplied
          else:
          # y value was specified by caller
          =====

          ===== fnord.py =====

          import wombat

          foo("spam") # 'y' argument gets unique default object
          foo("spam", "eggs") # 'y' argument is supplied by caller
          =====

          By using a unique object, and comparing on "is", you make it clear
          that this is never going to match any other value that is created
          elsewhere in the program.

          Of course, the "consenting adults" maxim applies: if a perverse user
          wnats to call 'foo("spam", wombat.Y_DEFAUL T)' this doesn't prevent it,
          but then they've explicitly asked for it.

          --
          \ "A lot of people are afraid of heights. Not me, I'm afraid of |
          `\ widths." -- Steven Wright |
          _o__) |
          Ben Finney

          Comment

          • George Sakkis

            #6
            Re: Checking default arguments

            On Feb 2, 1:30 pm, i...@ifi.uio.no (Igor V. Rafienko) wrote:
            Hi,
            >
            I was wondering whether it was possible to find out which parameter
            value is being used: the default argument or the user-supplied one.
            That is:
            >
            def foo(x, y="bar"):
            # how to figure out whether the value of y is
            # the default argument, or user-supplied?
            >
            foo(1, "bar") =user-supplied
            foo(1) =default
            >
            {}.pop seems to be able to make this dictinction.
            >
            I've checked the inspect module, but nothing obvious jumped at me. Any
            hints?
            I don't know why you might want to distinguish between the two in
            practice (the unique object idea mentioned in other posts should
            handle most uses cases), but if you insist, here's one way to do it:

            import inspect

            def determine_suppl ied_args(func):
            varnames,_,_,de faults = inspect.getargs pec(func)
            num_varnames = len(varnames); num_defaults = len(defaults)
            def wrapper(*args, **kwds):
            max_defaults = min(num_default s, num_varnames-len(args))
            supplied_args = dict(zip(varnam es,args))
            default_args = {}
            if max_defaults 0:
            for var,default in zip(varnames[-max_defaults:], defaults[-
            max_defaults:]):
            # if passed as keyword argument, don't use the default
            if var in kwds:
            supplied_args[var] = kwds[var]
            else:
            default_args[var] = default
            wrapper._suppli ed_args = supplied_args
            wrapper._defaul t_args = default_args
            return func(*args, **kwds)
            return wrapper


            @determine_supp lied_args
            def f(x, y='bar', z=None, *args, **kwds):
            print "Supplied:" , f._supplied_arg s
            print "Default:", f._default_args

            >>f(1)
            Supplied: {'x': 1}
            Default: {'y': 'bar', 'z': None}
            >>f(1, 'bar')
            Supplied: {'y': 'bar', 'x': 1}
            Default: {'z': None}
            >>f(1, y='bar')
            Supplied: {'y': 'bar', 'x': 1}
            Default: {'z': None}
            >>f(1, z=None)
            Supplied: {'x': 1, 'z': None}
            Default: {'y': 'bar'}
            >>f(1, 'bar', None)
            Supplied: {'y': 'bar', 'x': 1, 'z': None}
            Default: {}
            >>f(1, 'bar', z=None)
            Supplied: {'y': 'bar', 'x': 1, 'z': None}
            Default: {}
            >>f(1, z=None, y='bar')
            Supplied: {'y': 'bar', 'x': 1, 'z': None}
            Default: {}


            Regards,
            George

            Comment

            • Igor V. Rafienko

              #7
              Re: Checking default arguments

              [ George Sakkis ]

              First of all, thanks to everyone who replied.

              [ ... ]
              I don't know why you might want to distinguish between the two in
              practice (the unique object idea mentioned in other posts should
              handle most uses cases), but if you insist, here's one way to do it:

              There is no actual code situation where it happens. I was simply
              intrigued by the problem and could not find an answer.

              Since {}.pop behaves this way, I checked the C code. Apparently, it
              *is* quite easy from C, since PyArg_UnpackTup le and clever initial
              values (NULL vs. Py_None) make all the difference.

              The inspect-suggestion is, unfortunately, a bit more difficult to
              comprehend than I initially hoped for :)

              Thanks for all the suggestions

              [ ... ]





              ivr
              --
              "...but it's HDTV -- it's got a better resolution than the real world."
              -- Fry, "When aliens attack"

              Comment

              Working...