Login | Register For Free | Help
Search for: (Advanced)

Mailing List Archive: Python: Python

Determining if a function is a method of a class within a decorator

 

 

Python python RSS feed   Index | Next | Previous | View Threaded


davidh at ilm

Jun 29, 2009, 6:01 PM

Post #1 of 9 (377 views)
Permalink
Determining if a function is a method of a class within a decorator

I'm having a little problem with some python metaprogramming. I want to
have a decorator which I can use either with functions or methods of
classes, which will allow me to swap one function or method for another.
It works as I want it to, except that I want to be able to do some
things a little differently depending on whether I'm swapping two
functions, or two methods of a class.

Trouble is, it appears that when the decorator is called the function is
not yet bound to an instance, so no matter whether it's a method or
function, it looks the same to the decorator.

This simple example illustrates the problem:

import inspect
class swapWith(object):
def __init__(self, replacement):
self.replacement = replacement

def __call__(self, thingToReplace):
def _replacer(*args, **kws):
import inspect
print
"replacing:",self.replacement,inspect.ismethod(self.replacement)
return self.replacement(*args, **kws)
return _replacer

class MyClass(object):

def swapIn(self):
print "this method will be swapped in"

@swapWith(swapIn)
def swapOut(self):
print "this method will be swapped out"

c = MyClass()
c.swapOut()


def swapInFn():
print "this function will be swapped in"

@swapWith(swapInFn)
def swapOutFn():
print "this function will be swapped out"

swapOutFn()


Both MyClass.swapIn and swapInFn look like the same thing to the
decorator, and MyClass.swapOut and swapOutFn look the same. So is there
a pattern I can follow that will allow me to determine whether the
objects I'm given are plain functions or belong to a class?

Thanks in advance,
-David

--
Presenting:
mediocre nebula.


--
http://mail.python.org/mailman/listinfo/python-list


tjreedy at udel

Jun 29, 2009, 6:31 PM

Post #2 of 9 (352 views)
Permalink
Re: Determining if a function is a method of a class within a decorator [In reply to]

David Hirschfield wrote:
> I'm having a little problem with some python metaprogramming. I want to
> have a decorator which I can use either with functions or methods of
> classes, which will allow me to swap one function or method for another.
> It works as I want it to, except that I want to be able to do some
> things a little differently depending on whether I'm swapping two
> functions, or two methods of a class.

Unbounds methods are simply functions which have become attributes of a
class. Especially in Py3, there is *no* difference.

Bound methods are a special type of partial function. In Python, both
are something else, though still callables. Conceptually, a partial
function *is* a function, just with fewer parameters.

> Trouble is, it appears that when the decorator is called the function is
> not yet bound to an instance, so no matter whether it's a method or
> function, it looks the same to the decorator.

Right. Whether it is an A or an A, it looks like an A.

Worse: when the decorator is called, there is no class for there to be
instances of.
>
> This simple example illustrates the problem:

Add a second parameter to tell the decorator which variant of behavior
you want. Or write two variations of the decorator and use the one you want.

tjr

--
http://mail.python.org/mailman/listinfo/python-list


davidh at ilm

Jun 29, 2009, 7:01 PM

Post #3 of 9 (353 views)
Permalink
Re: Determining if a function is a method of a class within a decorator [In reply to]

Yeah, it definitely seems like having two separate decorators is the
solution. But the strange thing is that I found this snippet after some
deep googling, that seems to do something *like* what I want, though I
don't understand the descriptor stuff nearly well enough to get what's
happening:

http://stackoverflow.com/questions/306130/python-decorator-makes-function-forget-that-it-belongs-to-a-class

answer number 3, by ianb. It seems to indicate there's a way to
introspect and determine the class that the function is going to be
bound to...but I don't get it, and I'm not sure it's applicable to my case.

I'd love an explanation of what is going on in that setup, and if it
isn't usable for my situation, why not?
Thanks again,
-David

Terry Reedy wrote:
> David Hirschfield wrote:
>> I'm having a little problem with some python metaprogramming. I want
>> to have a decorator which I can use either with functions or methods
>> of classes, which will allow me to swap one function or method for
>> another. It works as I want it to, except that I want to be able to
>> do some things a little differently depending on whether I'm swapping
>> two functions, or two methods of a class.
>
> Unbounds methods are simply functions which have become attributes of
> a class. Especially in Py3, there is *no* difference.
>
> Bound methods are a special type of partial function. In Python, both
> are something else, though still callables. Conceptually, a partial
> function *is* a function, just with fewer parameters.
>
>> Trouble is, it appears that when the decorator is called the function
>> is not yet bound to an instance, so no matter whether it's a method
>> or function, it looks the same to the decorator.
>
> Right. Whether it is an A or an A, it looks like an A.
>
> Worse: when the decorator is called, there is no class for there to be
> instances of.
>>
>> This simple example illustrates the problem:
>
> Add a second parameter to tell the decorator which variant of behavior
> you want. Or write two variations of the decorator and use the one you
> want.
>
> tjr
>

--
Presenting:
mediocre nebula.


--
http://mail.python.org/mailman/listinfo/python-list


steven at REMOVE

Jun 29, 2009, 7:25 PM

Post #4 of 9 (354 views)
Permalink
Re: Determining if a function is a method of a class within a decorator [In reply to]

On Mon, 29 Jun 2009 18:01:29 -0700, David Hirschfield wrote:

> I'm having a little problem with some python metaprogramming. I want to
> have a decorator which I can use either with functions or methods of
> classes, which will allow me to swap one function or method for another.
> It works as I want it to, except that I want to be able to do some
> things a little differently depending on whether I'm swapping two
> functions, or two methods of a class.
>
> Trouble is, it appears that when the decorator is called the function is
> not yet bound to an instance, so no matter whether it's a method or
> function, it looks the same to the decorator.

Then:

* use a naming convention to recognise methods (e.g. check if the first
argument is called "self" by looking at function.func_code.co_varnames);

* use two different decorators, or a decorator that takes an extra
"method or function argument";

* play around with the class metaclass and see if you can do something
special (and probably fragile);

* do the replacements after the class is created without decorator
syntax, e.g.:

Class.method1 = swapWith(Class.method2)(Class.method1)




> This simple example illustrates the problem:
[snip]


No it doesn't. It appears to work perfectly, from what I can guess you're
trying to accomplish.



Have you considered a possibly simpler way of swapping methods/functions?


>>> def parrot():
... print "It's pining for the fjords."
...
>>> def cheeseshop():
... print "We don't stock Cheddar."
...
>>> parrot, cheeseshop = cheeseshop, parrot
>>>
>>> parrot()
We don't stock Cheddar.
>>> cheeseshop()
It's pining for the fjords.


Admittedly, this doesn't let you do extra processing before calling the
swapped functions, but perhaps it will do for what you need.



--
Steven
--
http://mail.python.org/mailman/listinfo/python-list


tjreedy at udel

Jun 30, 2009, 12:32 PM

Post #5 of 9 (338 views)
Permalink
Re: Determining if a function is a method of a class within a decorator [In reply to]

I do not like top posting.
Some thoughts in randon order:
Introspection is version-specific.
Call-time introspection is different from definition-time introspection.
Do what is easy and works.
Do not use recipes that depend on version-specific stuff you do not
understand.
Code objects, I believe, know the names of parameters.
That question and responses were only about methods, not non-class
functions.
You get to match these responses to your post ;-).

Terry

David Hirschfield wrote:
> Yeah, it definitely seems like having two separate decorators is the
> solution. But the strange thing is that I found this snippet after some
> deep googling, that seems to do something *like* what I want, though I
> don't understand the descriptor stuff nearly well enough to get what's
> happening:
>
> http://stackoverflow.com/questions/306130/python-decorator-makes-function-forget-that-it-belongs-to-a-class
>
>
> answer number 3, by ianb. It seems to indicate there's a way to
> introspect and determine the class that the function is going to be
> bound to...but I don't get it, and I'm not sure it's applicable to my case.
>
> I'd love an explanation of what is going on in that setup, and if it
> isn't usable for my situation, why not?
> Thanks again,
> -David
>
> Terry Reedy wrote:
>> David Hirschfield wrote:
>>> I'm having a little problem with some python metaprogramming. I want
>>> to have a decorator which I can use either with functions or methods
>>> of classes, which will allow me to swap one function or method for
>>> another. It works as I want it to, except that I want to be able to
>>> do some things a little differently depending on whether I'm swapping
>>> two functions, or two methods of a class.
>>
>> Unbounds methods are simply functions which have become attributes of
>> a class. Especially in Py3, there is *no* difference.
>>
>> Bound methods are a special type of partial function. In Python, both
>> are something else, though still callables. Conceptually, a partial
>> function *is* a function, just with fewer parameters.
>>
>>> Trouble is, it appears that when the decorator is called the function
>>> is not yet bound to an instance, so no matter whether it's a method
>>> or function, it looks the same to the decorator.
>>
>> Right. Whether it is an A or an A, it looks like an A.
>>
>> Worse: when the decorator is called, there is no class for there to be
>> instances of.
>>>
>>> This simple example illustrates the problem:
>>
>> Add a second parameter to tell the decorator which variant of behavior
>> you want. Or write two variations of the decorator and use the one you
>> want.
>>
>> tjr
>>
>

--
http://mail.python.org/mailman/listinfo/python-list


pavlovevidence at gmail

Jun 30, 2009, 5:50 PM

Post #6 of 9 (335 views)
Permalink
Re: Determining if a function is a method of a class within a decorator [In reply to]

On Jun 29, 6:01 pm, David Hirschfield <dav...@ilm.com> wrote:
> So is there
> a pattern I can follow that will allow me to determine whether the
> objects I'm given are plain functions or belong to a class?
>
> Thanks in advance,



class HomemadeUnboundMethod(object):
def __init__(self,func):
self.func = func
def __call__(self,*args,**kwargs):
print "is a function: %s" % self.func.func_name
return self.func(*args,**kwargs)
def __get__(self,obj,owner):
return HomemadeBoundMethod(obj,self.func)

class HomemadeBoundMethod(object):
def __init__(self,obj,func):
self.obj = obj
self.func = func
def __call__(self,*args,**kwargs):
print "is a method: %s" % self.func.func_name
return self.func(self.obj,*args,**kwargs)

class A(object):
@HomemadeUnboundMethod
def method(self): pass

@HomemadeUnboundMethod
def function(): pass

A().method()
function()



Just override the __call__ functions to do what you want the decorated
function to do. There are other little improvements you might make
(account for the owner parameter of __get__ for instance) but you get
the idea.


Carl Banks
--
http://mail.python.org/mailman/listinfo/python-list


davidh at ilm

Jun 30, 2009, 6:14 PM

Post #7 of 9 (333 views)
Permalink
Re: Determining if a function is a method of a class within a decorator [In reply to]

Unfortunately that still requires two separate decorators, when I was
hoping there was a way to determine if I was handed a function or method
from within the same decorator.

Seems like there really isn't, so two decorators is the way to go.
Thanks,
-David

Carl Banks wrote:
> On Jun 29, 6:01 pm, David Hirschfield <dav...@ilm.com> wrote:
>
>> So is there
>> a pattern I can follow that will allow me to determine whether the
>> objects I'm given are plain functions or belong to a class?
>>
>> Thanks in advance,
>>
>
>
>
> class HomemadeUnboundMethod(object):
> def __init__(self,func):
> self.func = func
> def __call__(self,*args,**kwargs):
> print "is a function: %s" % self.func.func_name
> return self.func(*args,**kwargs)
> def __get__(self,obj,owner):
> return HomemadeBoundMethod(obj,self.func)
>
> class HomemadeBoundMethod(object):
> def __init__(self,obj,func):
> self.obj = obj
> self.func = func
> def __call__(self,*args,**kwargs):
> print "is a method: %s" % self.func.func_name
> return self.func(self.obj,*args,**kwargs)
>
> class A(object):
> @HomemadeUnboundMethod
> def method(self): pass
>
> @HomemadeUnboundMethod
> def function(): pass
>
> A().method()
> function()
>
>
>
> Just override the __call__ functions to do what you want the decorated
> function to do. There are other little improvements you might make
> (account for the owner parameter of __get__ for instance) but you get
> the idea.
>
>
> Carl Banks
>

--
Presenting:
mediocre nebula.


jeremiah.dodds at gmail

Jul 2, 2009, 1:44 AM

Post #8 of 9 (293 views)
Permalink
Re: Determining if a function is a method of a class within a decorator [In reply to]

On Wed, Jul 1, 2009 at 2:14 AM, David Hirschfield <davidh[at]ilm.com> wrote:

> Unfortunately that still requires two separate decorators, when I was
> hoping there was a way to determine if I was handed a function or method
> from within the same decorator.
>
> Seems like there really isn't, so two decorators is the way to go.
> Thanks,
> -David
>
>
This is a really horrible idea, but it may work:

If you can rely on your code using the word "self", you could use the
inspect module to look at the arguments of the function being decorated, and
dispatch based on that. The idea itself feels extremely dirty though.


piet at cs

Jul 5, 2009, 10:28 AM

Post #9 of 9 (255 views)
Permalink
Re: Determining if a function is a method of a class within a decorator [In reply to]

>>>>> David Hirschfield <davidh[at]ilm.com> (DH) wrote:

>DH> Yeah, it definitely seems like having two separate decorators is the
>DH> solution. But the strange thing is that I found this snippet after some
>DH> deep googling, that seems to do something *like* what I want, though I
>DH> don't understand the descriptor stuff nearly well enough to get what's
>DH> happening:

>DH> http://stackoverflow.com/questions/306130/python-decorator-makes-function-forget-that-it-belongs-to-a-class

>DH> answer number 3, by ianb. It seems to indicate there's a way to introspect
>DH> and determine the class that the function is going to be bound to...but I
>DH> don't get it, and I'm not sure it's applicable to my case.

>DH> I'd love an explanation of what is going on in that setup, and if it isn't
>DH> usable for my situation, why not?

What that example does is not getting the name of the class in the
decorator, but in the bound method that is the result of the decorator
when that method is called. This is just done by asking for the class of
the self parameter. Actually they even don't do that in that example but
it could have been done. Note also that there is an error in the code:
keyargs should be kw.

There is also something special in that code: it uses the descriptor
protocol. This is necessary for a method. The descriptor protocol for
methods defines a __get__ method that transforms the unbound method into
a bound method. That code uses this to decorate the generated bound method
object instead of decorating the unbound method.

A side effect of doing the class detection at call time is that you get
the name of the subclass if you use the method on an instance of the
subclass, not the name of the class that the method was defined in:

class D(C):
pass

D().f(1, 2) will talk about class D, not class C.

So if you would like to do something special for bound methods the
__get__ might be the proper place to do it.
--
Piet van Oostrum <piet[at]cs.uu.nl>
URL: http://pietvanoostrum.com [PGP 8DAE142BE17999C4]
Private email: piet[at]vanoostrum.org
--
http://mail.python.org/mailman/listinfo/python-list

Python python RSS feed   Index | Next | Previous | View Threaded
 
 


Interested in having your list archived? Contact lists@gossamer-threads.com
 
  Web Applications & Managed Hosting Powered by Gossamer Threads Inc.