Ticket #5405 (needs_review enhancement)

Opened 13 months ago

Last modified 3 months ago

[with patch, needs work] create a decorator for adding default keyword arguments to a function

Reported by: mhansen Owned by: cwitty
Priority: minor Milestone: sage-4.3.4
Component: misc Keywords:
Cc: mhansen, jason Author(s):
Report Upstream: N/A Reviewer(s):
Merged in: Work issues:

Description (last modified by nthiery) (diff)

The typical usage of this decorator would be to be applied above a :obj:cached_method or :obj:cached_function decorator so that the correct cached object is returned.

Attachments

trac_5405.patch Download (1.6 KB) - added by mhansen 13 months ago.
trac_5405-decorator-partial.patch Download (1.8 KB) - added by timdumol 3 months ago.
Adds module sage.misc.decorators with content specialize.

Change History

Changed 13 months ago by mhansen

  Changed 12 months ago by nthiery

Hi Mike!

I am not so sure about the name, although I can't propose much better than default_values, or set_default_values.

Could it be generalized to handle both positional and non positional arguments?

I'd suggest to have the doc by starting with what the thing actually does, followed by the typical usage. Speaking of which: could you add an example of this typical usage? (it was not clear to me).

  Changed 12 months ago by jason

  • cc jason added

  Changed 11 months ago by nthiery

  • cc mhansen added; jason removed
  • summary changed from [with patch, needs review] create a decorator for adding default keyword arguments to a function to [with patch, needs work] create a decorator for adding default keyword arguments to a function

Oops, should have set the subject to needs work. Done.

  Changed 6 months ago by jason

  • cc jason added

  Changed 5 months ago by timdumol

Sorry if I don't get this right, but doesn't functools.partial already fulfill this purpose?

  Changed 5 months ago by jason

Do you mean something like this?

from functools import partial

def partial_dec(*args, **kwds):
    def p(f):
        return partial(f,*args,**kwds)
    return p
    
@partial_dec(b=2)
def f(a,b):
    return 10*a+b

f(4)

  Changed 5 months ago by timdumol

Actually I meant something like this:

from functools import partial

@partial(partial, b=4)
def f(a,b):
    return 10*a + b

f(4)

  Changed 5 months ago by jason

Cute. Very nice!

  Changed 5 months ago by jason

So now can you use @wraps or something so that g? works correctly below?

from functools import partial, wraps

@partial(partial, b=4)
def g(a,b):
    """Docs"""
    return 10*a + b

g?

  Changed 5 months ago by timdumol

This works, but it certainly isn't obvious:

from functools import partial, wraps

@partial(lambda x: wraps(x)(partial(partial, b = 4))(x))
def g(a,b):
    """Docs"""
    return 10*a + b

print(g(5))

g?

  Changed 5 months ago by jason

and at that point, I'd say

@default_keywords...
def g...

is nicer. However, one might use partial in the above decorator. I think our discussion is evidence for the usefulness of the idea on this ticket.

  Changed 5 months ago by timdumol

Yep. It's certainly much clearer. Using partial should deal with the positional and non-positional arguments thing.

  Changed 5 months ago by jason

So we've agreed that we should create a partial decorator that allows something like:

from sage.misc.decorators (or wherever) import partial

@partial(*args, **kwds) # Same as calling partial(g, *args, **kwds) and wrapping with @wraps
def g(a,b):
   ...

just works as expected.

follow-up: ↓ 15   Changed 5 months ago by timdumol

Perhaps a name of curry [1] would be better, since it prevents name collision with functools.partial? Then again, it supersedes functools.partial anyways.

[1]  http://en.wikipedia.org/wiki/Currying

in reply to: ↑ 14 ; follow-up: ↓ 16   Changed 5 months ago by nthiery

  • description modified (diff)

Thanks much for pointing out functools.partial and functool.wrapper; I have several other use cases for them!

Replying to timdumol:

Perhaps a name of curry [1] would be better, since it prevents name collision with functools.partial? Then again, it supersedes functools.partial anyways. [1]  http://en.wikipedia.org/wiki/Currying

I prefer partial, since curry does not really encompass the specialization of named arguments. It's really functools.partial, but made into a decorator.

in reply to: ↑ 15   Changed 5 months ago by timdumol

I prefer partial, since curry does not really encompass the specialization of named arguments. It's really functools.partial, but made into a decorator.

Fair enough -- but just to clarify, functools.partial *is* a decorator, just that it doesn't update the documentation string.

Changed 3 months ago by timdumol

Adds module sage.misc.decorators with content specialize.

  Changed 3 months ago by timdumol

  • status changed from needs_work to needs_review
  • upstream set to N/A

Nevermind, functools.partial is not a decorator. My apologies.

This patch should do the trick. I named it specialize rather than partial, since partial conflicts with functools.partial.

Note: See TracTickets for help on using tickets.