Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #77904 > unrolled thread
| Started by | ISE Development <isenntp@gmail.com> |
|---|---|
| First post | 2014-09-16 01:15 +0200 |
| Last post | 2014-09-15 21:39 -0600 |
| Articles | 4 — 3 participants |
Back to article view | Back to comp.lang.python
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
| From | ISE Development <isenntp@gmail.com> |
|---|---|
| Date | 2014-09-16 01:15 +0200 |
| Subject | functools.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]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2014-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]
| From | ISE Development <isenntp@gmail.com> |
|---|---|
| Date | 2014-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]
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2014-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