Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #77904 > unrolled thread

functools.wraps behaviour

Started byISE Development <isenntp@gmail.com>
First post2014-09-16 01:15 +0200
Last post2014-09-15 21:39 -0600
Articles 4 — 3 participants

Back to article view | Back to comp.lang.python


Contents

  functools.wraps behaviour ISE Development <isenntp@gmail.com> - 2014-09-16 01:15 +0200
    Re: functools.wraps behaviour Chris Angelico <rosuav@gmail.com> - 2014-09-16 10:46 +1000
      Re: functools.wraps behaviour ISE Development <isenntp@gmail.com> - 2014-09-16 09:24 +0200
    Re: functools.wraps behaviour Ian Kelly <ian.g.kelly@gmail.com> - 2014-09-15 21:39 -0600

#77904 — functools.wraps behaviour

FromISE Development <isenntp@gmail.com>
Date2014-09-16 01:15 +0200
Subjectfunctools.wraps behaviour
Message-ID<541772fa$0$2078$426a74cc@news.free.fr>
The purpose of 'functools.wraps' is to make a decorated function look like 
the original function, i.e. such that the __name__, __module__, __doc__ 
attributes are the same as the wrapped function.

However, I've noticed inconsistent behaviour.

Given the following:

    import functools

    def decorator(func):
        @functools.wraps(func)
        def wrapper(self):
            func(self)
        return wrapper

    class Klass:
        @decorator
        def method(self):
            raise Exception('boom!')

    print('Klass.method:',Klass.method)

    k = Klass()
    print('k.method',k.method)

    try:
        k.method(1)
    except Exception as e:
        print('exception:',e)

The output (Python 3.3) is:

Klass.method: <function Klass.method at 0x7f2d7c454b00>
k.method <bound method Klass.method of <__main__.Klass object at 
0x7f2d7c4570d0>>
exception: wrapper() takes 1 positional argument but 2 were given

The first two lines are as expected, using the name of the decorated 
function. However, the exception uses the name of the decorating wrapper 
function.

Is this a bug in functools? Or is this a language feature? If so, is there a 
valid argument to change this behaviour?

-- isedev

[toc] | [next] | [standalone]


#77907

FromChris Angelico <rosuav@gmail.com>
Date2014-09-16 10:46 +1000
Message-ID<mailman.14037.1410828831.18130.python-list@python.org>
In reply to#77904
On Tue, Sep 16, 2014 at 9:15 AM, ISE Development <isenntp@gmail.com> wrote:
>         @functools.wraps(func)
>         def wrapper(self):
>             func(self)
>         return wrapper
>
>     try:
>         k.method(1)
>     except Exception as e:
>         print('exception:',e)
>
> The output (Python 3.3) is:
>
> Klass.method: <function Klass.method at 0x7f2d7c454b00>
> k.method <bound method Klass.method of <__main__.Klass object at
> 0x7f2d7c4570d0>>
> exception: wrapper() takes 1 positional argument but 2 were given
>
> The first two lines are as expected, using the name of the decorated
> function. However, the exception uses the name of the decorating wrapper
> function.

In your wrapper, you're swallowing all arguments. That means you're
consciously rejecting them, and passing none on. If you want a wrapper
to let the wrapped function decide about arguments, try this:

    def decorator(func):
        @functools.wraps(func)
        def wrapper(self, *args, **kwargs):
            func(self, args, kwargs)
        return wrapper

With that change, the error message reports that it's method() that's
rejecting the args.

So yes, I'd say this is a feature; you can either let the wrapped
function make the decision, or you can have the wrapping function deal
with args.

ChrisA

[toc] | [prev] | [next] | [standalone]


#77917

FromISE Development <isenntp@gmail.com>
Date2014-09-16 09:24 +0200
Message-ID<5417e5a3$0$2143$426a74cc@news.free.fr>
In reply to#77907
Chris Angelico wrote:

> On Tue, Sep 16, 2014 at 9:15 AM, ISE Development <isenntp@gmail.com>
> wrote:
>>         @functools.wraps(func)
>>         def wrapper(self):
>>             func(self)
>>         return wrapper
>>
>>     try:
>>         k.method(1)
>>     except Exception as e:
>>         print('exception:',e)
>>
>> The output (Python 3.3) is:
>>
>> Klass.method: <function Klass.method at 0x7f2d7c454b00>
>> k.method <bound method Klass.method of <__main__.Klass object at
>> 0x7f2d7c4570d0>>
>> exception: wrapper() takes 1 positional argument but 2 were given
>>
>> The first two lines are as expected, using the name of the decorated
>> function. However, the exception uses the name of the decorating wrapper
>> function.
> 
> In your wrapper, you're swallowing all arguments. That means you're
> consciously rejecting them, and passing none on. If you want a wrapper
> to let the wrapped function decide about arguments, try this:
> 
>     def decorator(func):
>         @functools.wraps(func)
>         def wrapper(self, *args, **kwargs):
>             func(self, args, kwargs)
>         return wrapper
> 
> With that change, the error message reports that it's method() that's
> rejecting the args.
> 
> So yes, I'd say this is a feature; you can either let the wrapped
> function make the decision, or you can have the wrapping function deal
> with args.
> 
> ChrisA

Very good point. Hadn't thought about it that way - it makes sense now.

Thanks.

-- isedev

[toc] | [prev] | [next] | [standalone]


#77912

FromIan Kelly <ian.g.kelly@gmail.com>
Date2014-09-15 21:39 -0600
Message-ID<mailman.14040.1410838808.18130.python-list@python.org>
In reply to#77904
On Mon, Sep 15, 2014 at 5:15 PM, ISE Development <isenntp@gmail.com> wrote:
> The first two lines are as expected, using the name of the decorated
> function. However, the exception uses the name of the decorating wrapper
> function.
>
> Is this a bug in functools? Or is this a language feature? If so, is there a
> valid argument to change this behaviour?

I believe this is done in order to have useful stack traces. If it
said 'method' in the stack trace, it could mislead the person
debugging into thinking that method is actually raising the exception,
but here the exception is actually coming from wrapped, and method is
not even called.

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web