I have the following descriptor, which saves the configuration inside my class after a method which is annotated with @saveconfig
is called:
class saveconfig(object):
def __init__(self, f):
self.f = f
def __get__(self, instance, owner):
def wrapper(*args):
self.f(instance, *args)
instance.cfg.write()
instance.paramcfg.write()
return wrapper
It's used like this:
class pbtools():
@saveconfig
def getip(self, ip):
(...)
It works fine. Now i want to get the decorated method by using getattr. But since the method is wrapped by the descriptor, i only get wrapper
as a 开发者_开发知识库result:
pbt = pbtools()
# results in "<function wrapper at 0x23cced8>:"
method = getattr(pbt, "getip")
How can i access the wrapped method getip
with getattr, to be able to call it by it's name? (of course i cannot access the method directly otherwise i would not have to do that).
Additional explanation:
The script is called from commandline. I have to map a command line parameter (string) to a method with the same name to invoke it. Furthermore, i have to map any additional parameters from the comamndline to parameters of the method, like this:
pbtools getip 192.168.178.123 #-> calls getip with parameter 192.168.178.123
Since i cannot get the original method, i don't know how many parameters it has to map them. I have several methods that are decorated like that, because i want to move the cross cutting concern of saving the config out of the methods in the pbtools-class.
I'm still not 100% sure I fully understand your problem. You say that "Since i cannot get the original method, i don't know how many parameters it has to map them", but you don't need access to the original method to call by variable number of arguments (since the decorator has *args
). You can do something like this:
import sys
cmd = sys.argv[1]
params = sys.argv[2:]
pbt = pbtools()
func = getattr(pbt, cmd)
func(*params)
You can also simplify your decorator a bit. It doesn't really need the __get__
mechanism.
import functools
def saveconfig(f):
@functools.wraps(f)
def wrapper(self, *args):
f(self, *args)
self.cfg.write()
self.paramcfg.write()
return wrapper
The functools.wraps
is a helper decorator that makes the wrapper mimic the original function (i.e. it copies the function name, docstring and stuff like that). It will make debugging easier, since you will know where exceptions are originating from etc.
First of all sorry about the comment my mistake, now for your last code will not work as you which (your method is not decorated anymore) because to understand decorator you have to see this :
class pbtools():
@saveconfig
def getip():
(...)
is equivalent to:
class pbtools():
def getip():
(...)
getip = saveconfig(getip)
and in your latest case saveconfig
return self.f
which is in our code equal to getip
so in this case this code:
getip = saveconfig(getip)
is equivalent to :
getip = getip
so basically it don't do nothing.
A work around can be by saving the wrapped function in the wrapping one like this:
class saveconfig(object):
def __init__(self, f):
self.f = f
def __get__(self, instance, owner):
def wrapper(*args):
self.f(instance, *args)
instance.cfg.write()
instance.paramcfg.write()
wrapper.func = self.f # Create a new attribute and assign it to the wrapped func.
return wrapper
and now you can :
class pbtools():
@saveconfig
def getip():
print "hi"
pbt = pbtools()
method = getattr(pbt, "getip")
print method.func
# <function getip at 0x2363410>
method.func()
# hi
Hope this can help :)
精彩评论