[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.python

Distinguishing between functions and methods in a decorator.

Berteun Damman

2/7/2008 4:11:00 PM

Hello,

I was wondering a bit about the differences between methods and
functions. I have the following:

def wrap(arg):
print type(arg)
return arg

class C:
def f():
pass

@wrap
def g():
pass

def h():
pass

print type(C.f)
print type(h)

Which gives the following output:
<type 'function'>
<type 'instancemethod'>
<type 'function'>

The first line is caused by the 'wrap' function of course. I had
expected the first line to be 'instancemethod' too. So, I would guess,
these methods of C are first created as functions, and only then become
methods after they are 'attached' to some classobj. (You can do that
yourself of course, by saying, for example, C.h = h, then the type of
C.h is 'instancemethod' too.)

Why does the wrapping occur before the function is 'made' into an
instancemethod?

The reason for asking is that I would like to differentiate between
wrapping a function and an instancemethod, because in the latter case,
the first parameter will be the implicit 'self', which I would like to
ignore. However, when the wrapping occurs, the method still looks like
a function.

Berteun
4 Answers

Diez B. Roggisch

2/7/2008 4:26:00 PM

0

Berteun Damman wrote:

> Hello,
>
> I was wondering a bit about the differences between methods and
> functions. I have the following:
>
> def wrap(arg):
> print type(arg)
> return arg
>
> class C:
> def f():
> pass
>
> @wrap
> def g():
> pass
>
> def h():
> pass
>
> print type(C.f)
> print type(h)
>
> Which gives the following output:
> <type 'function'>
> <type 'instancemethod'>
> <type 'function'>
>
> The first line is caused by the 'wrap' function of course. I had
> expected the first line to be 'instancemethod' too. So, I would guess,
> these methods of C are first created as functions, and only then become
> methods after they are 'attached' to some classobj. (You can do that
> yourself of course, by saying, for example, C.h = h, then the type of
> C.h is 'instancemethod' too.)
>
> Why does the wrapping occur before the function is 'made' into an
> instancemethod?

Because a decorator could choose to return any function-object as it likes,
see this example:

def bar(self):
print "bar"

def makebar(f):
return bar

class Foo(object):

@makebar
def baz(self):
pass

foo = Foo()
foo.baz()

So you can't decide if a function is an instancemethod until the very last
moment.

Diez

Diez B. Roggisch

2/7/2008 5:22:00 PM

0

Berteun Damman schrieb:
> Hello,
>
> I was wondering a bit about the differences between methods and
> functions. I have the following:
>
> def wrap(arg):
> print type(arg)
> return arg
>
> class C:
> def f():
> pass
>
> @wrap
> def g():
> pass
>
> def h():
> pass
>
> print type(C.f)
> print type(h)
>
> Which gives the following output:
> <type 'function'>
> <type 'instancemethod'>
> <type 'function'>
>
> The first line is caused by the 'wrap' function of course. I had
> expected the first line to be 'instancemethod' too. So, I would guess,
> these methods of C are first created as functions, and only then become
> methods after they are 'attached' to some classobj. (You can do that
> yourself of course, by saying, for example, C.h = h, then the type of
> C.h is 'instancemethod' too.)
>
> Why does the wrapping occur before the function is 'made' into an
> instancemethod?
>
> The reason for asking is that I would like to differentiate between
> wrapping a function and an instancemethod, because in the latter case,
> the first parameter will be the implicit 'self', which I would like to
> ignore. However, when the wrapping occurs, the method still looks like
> a function.

Can you provide an example of what you are actually after? The
descriptor-protocol might come to use there.

Diez

Arnaud Delobelle

2/7/2008 6:17:00 PM

0

On Feb 7, 4:10 pm, Berteun Damman <berteun@NO_SPAMdds.nl> wrote:
> Hello,
>
> I was wondering a bit about the differences between methods and
> functions. I have the following:
>
> def wrap(arg):
> print type(arg)
> return arg
>
> class C:
> def f():
> pass
>
> @wrap
> def g():
> pass
>
> def h():
> pass
>
> print type(C.f)
> print type(h)
>
> Which gives the following output:
> <type 'function'>
> <type 'instancemethod'>
> <type 'function'>
>
> The first line is caused by the 'wrap' function of course. I had
> expected the first line to be 'instancemethod' too. So, I would guess,
> these methods of C are first created as functions, and only then become
> methods after they are 'attached' to some classobj. (You can do that
> yourself of course, by saying, for example, C.h = h, then the type of
> C.h is 'instancemethod' too.)
>
> Why does the wrapping occur before the function is 'made' into an
> instancemethod?

Consider this:

>>> class Foo(object):
.... def bar(self): pass
....
>>> Foo.bar
<unbound method Foo.bar>
>>> Foo.__dict__['bar']
<function bar at 0x7d5b0>
>>>

It shows that when Foo.bar is evaluated, a new instancemethod object
is created and that the 'bar' in the dictionary of 'Foo' is forever a
plain function object. In fact, Foo.bar is equivalent to
Foo.__dict__['bar'].__get__(None, Foo):

>>> Foo.__dict__['bar'].__get__(None, Foo)
<unbound method Foo.bar>
>>>

For more details you can read http://users.rcn.com/python/download/Desc....

> The reason for asking is that I would like to differentiate between
> wrapping a function and an instancemethod, because in the latter case,
> the first parameter will be the implicit 'self', which I would like to
> ignore. However, when the wrapping occurs, the method still looks like
> a function.
>
> Berteun

I think you're better off having a 'wrap' decorator for functions and
a 'wrapmethod' decorator for methods.

HTH

--
Arnaud

Berteun Damman

2/8/2008 1:11:00 PM

0

On Thu, 07 Feb 2008 18:22:03 +0100, Diez B. Roggisch
<deets@nospam.web.de> wrote:
> Can you provide an example of what you are actually after? The
> descriptor-protocol might come to use there.

Thanks for your responses. I have read the Descriptor protocol how-to,
which clarifies method access on objects, and indeed provides a
solution.

My idea was to have some @pre and @post decorators, which check some
pre-conditions. When applied to a method, the first parameter will be an
instance-object, and I wondered whether I could detect whether the
precondition cared about it or not.

So,
@pre(lambda x: x > 0)
def method(self, x):

Here the precondition function does not use 'self', yet it will of
course be provided in a call, so I need to strip it. In case of a @pre
applied to a function, this does not happen. I'm not sure whether this
magic is such a nice solution though.

However, the descriptor protocol indeed is what I need. If I provide the
__get__ method, this will be invoked instead of __call__, which will
happen on functions (or methods, if __get__ is not provided). This way
the two are clearly distinguishable, and I need not worry about
heuristics (such as, is the first parameter called 'self' or something).

Besides, it taught me a bit more about the inner design of Python. :)

Thanks,

Berteun