Param decorator - can you suggest improvements

Discussion in 'Python' started by Mark Carter, Jan 17, 2013.

  1. Mark Carter

    Mark Carter Guest

    I thought it would be interesting to try to implement Scheme SRFI 39 (Parameter objects) in Python.

    The idea is that you define a function that returns a default value. If youcall that function with no arguments, it returns the current default. If you call it with an argument, it resets the default to the value passed in. Here's a working implementation:

    # http://www.artima.com/weblogs/viewpost.jsp?thread=240845

    from functools import wraps

    class Param(object):
    def __init__(self, default):
    self.default = default
    #self.func = func

    def __call__(self, func, *args):
    @wraps(func)
    def wrapper(*args):
    #print 'calling hi'
    if len(args) >0:
    self.default = args[0]
    #print len(args), ' ', args
    return self.default # self.func(*args)
    return wrapper


    @Param(42)
    def hi(newval):
    pass

    print hi() # 42
    print hi(12) # 12
    print hi() # 12
    hi(13) # sets it to 13
    print hi() # 13


    Can anyone suggest a better implementation?
    Mark Carter, Jan 17, 2013
    #1
    1. Advertising

  2. On Thu, 17 Jan 2013 06:35:29 -0800, Mark Carter wrote:

    > I thought it would be interesting to try to implement Scheme SRFI 39
    > (Parameter objects) in Python.
    >
    > The idea is that you define a function that returns a default value. If
    > you call that function with no arguments, it returns the current
    > default. If you call it with an argument, it resets the default to the
    > value passed in. Here's a working implementation:

    [...]
    > Can anyone suggest a better implementation?


    I don't like the decorator version, because it requires creating a do-
    nothing function that just gets thrown away. He's my version, a factory
    function that takes two arguments, the default value and an optional
    function name, and returns a Param function:

    def param(default, name=None):
    SENTINEL = object()
    default = [default]
    def param(arg=SENTINEL):
    if arg is SENTINEL:
    return default[0]
    else:
    default[0] = arg
    return arg
    if name is not None:
    param.__name__ = name
    return param


    In Python 3, it's even nicer, although no shorter:

    def param(default, name=None):
    SENTINEL = object()
    def param(arg=SENTINEL):
    nonlocal default
    if arg is SENTINEL:
    return default
    else:
    default = arg
    return arg
    if name is not None:
    param.__name__ = name
    return param



    --
    Steven
    Steven D'Aprano, Jan 17, 2013
    #2
    1. Advertising

  3. On Fri, 18 Jan 2013 03:38:08 +0000, Dan Sommers wrote:

    > On Thu, 17 Jan 2013 15:21:08 +0000, Steven D'Aprano wrote:
    >
    >> On Thu, 17 Jan 2013 06:35:29 -0800, Mark Carter wrote:
    >>
    >>> I thought it would be interesting to try to implement Scheme SRFI 39
    >>> (Parameter objects) in Python.
    >>>
    >>> The idea is that you define a function that returns a default value.
    >>> If you call that function with no arguments, it returns the current
    >>> default. If you call it with an argument, it resets the default to the
    >>> value passed in. Here's a working implementation:

    >> [...]
    >>> Can anyone suggest a better implementation?

    >>
    >> I don't like the decorator version, because it requires creating a do-
    >> nothing function that just gets thrown away. He's my version, a factory
    >> function that takes two arguments, the default value and an optional
    >> function name, and returns a Param function: [...]

    >
    > This, or something like this, is very old:
    >
    > sentinel = object()
    > class Magic:
    > def __init__(self, value):
    > self.value = value
    > def __call__(self, value=sentinel):
    > if value != sentinel:
    > self.value = value
    > return self.value


    There's not really any magic in that :)

    Better to use "if value is not sentinel" rather than != because the
    caller might provide a custom object that compares equal to sentinel.

    Also you should name it SENTINEL, or even _SENTINEL, to indicate that it
    is (1) a constant, and (2) a private variable.


    > It's not a function, nor a decorator, but it behaves like a function.


    A callable, so-called because you can call it :)

    I believe that C++ calls it a "functor", not to be confused with what
    Haskell calls a functor, which is completely different.



    --
    Steven
    Steven D'Aprano, Jan 18, 2013
    #3
    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. Geathaa
    Replies:
    2
    Views:
    683
    Geathaa
    Jul 30, 2003
  2. Gus Gassmann

    Suggest improvements

    Gus Gassmann, Oct 14, 2010, in forum: C Programming
    Replies:
    23
    Views:
    629
    Tim Rentsch
    Oct 17, 2010
  3. Dave
    Replies:
    5
    Views:
    620
    John Bokma
    Apr 26, 2011
  4. Joel Goldstick
    Replies:
    0
    Views:
    94
    Joel Goldstick
    Aug 3, 2013
  5. Terry Reedy
    Replies:
    29
    Views:
    224
    Piet van Oostrum
    Oct 1, 2013
Loading...

Share This Page