I came up with the following code to decorate instance methods using a decorator that requires the instance itself as an argument:
from functools import wraps
def logging_decorator(tricky_instance):
def wrapper(fn):
@wraps(fn)
def wrapped(*a, **kw):
if tricky_instance.log:
print("Calling %s.." % fn.__name__)
return fn(*a, *开发者_开发技巧*kw)
return wrapped
return wrapper
class Tricky(object):
def __init__(self, log):
self.log = log
self.say_hi = logging_decorator(self)(self.say_hi)
def say_hi(self):
print("Hello, world!")
i1 = Tricky(log=True)
i2 = Tricky(log=False)
i1.say_hi()
i2.say_hi()
This seems to work great, but I fear that I may have overlooked some unintended side effects of this trick. Am I about to shoot myself in the foot, or is this safe?
Note that I don't actually want to use this for logging, it's just the shortest meaningful example I could come up with.
It's not really clear to me why you would ever want to do this. If you want to assign a new method type dynamically use types
:
import types
class Tricky(object):
def __init__(self):
def method(self):
print('Hello')
self.method = types.MethodType(method, self)
If you want to do something with the instance, do it in the __init__
method. If you just want access to the method's instance inside the decorator, you can use the im_self
attribute:
def decorator(tricky_instance):
def wrapper(meth):
print(meth.im_self == tricky_instance)
return meth
return wrapper
Personally, I think this is veering into Maybe-I-Shouldn't-Use-Decorators land.
I think I was trying to be needlessly smart. There seems to be an embarrassingly simpler solution:
from functools import wraps
def logging_decorator(fn):
@wraps(fn)
def wrapped(self, *a, **kw):
if self.log:
print("Calling %s.." % fn.__name__)
return fn(self, *a, **kw)
return wrapped
class Tricky(object):
def __init__(self, log):
self.log = log
@logging_decorator
def say_hi(self):
print("Hello, world!")
i1 = Tricky(log=True)
i2 = Tricky(log=False)
i1.say_hi()
i2.say_hi()
精彩评论