1、问题背景
在Python中,我们可以使用装饰器来修改函数或方法的行为,但当装饰器需要使用一个在实例化时创建的对象时,事情就会变得复杂。
例如,我们想要创建一个装饰器,可以创建一个新的函数/方法来使用对象obj。如果被装饰的对象是一个函数,那么obj必须在函数创建时被实例化。如果被装饰的对象是一个方法,那么必须为类的每个实例实例化一个新的obj,并将其绑定到该实例。
2、解决方案
我们可以使用以下方法来解决这个问题:
- 使用
inspect
模块来获取被装饰对象的签名。 - 如果被装饰的对象是一个方法,则将obj绑定到self。
- 如果被装饰的对象是一个函数,则实例化obj。
- 返回一个新函数/方法,该函数/方法使用obj。
以下代码示例演示了如何实现此解决方案:
代码语言:javascript复制from types import InstanceType
from functools import wraps
import inspect
def dec(func):
#get the sig of the function
sig = []
@wraps(func)
def wrapper(*args, **kwargs):
ret = None
#if this is a method belonging to an object...
if args and getattr(args[0], func.__name__, None):
instance, args = args[0], args[1:]
#if sig of object is not already set
if not hasattr(instance, "sig"):
instance.sig = []
ret = func(instance, *args, **kwargs)
print "Sig of %s is %s" % (func.__name__, id(instance.sig))
#else this is a function
else:
ret = func(*args, **kwargs)
print "Sig of %s is %s" % (func.__name__, id(sig))
return ret
#modify the doc string
try:
docs = inspect.getsourcelines(func)
except:
docs = "<unable to fetch defintion>"
else:
docs = docs[0][1].rstrip('n').rstrip(':').lstrip(' ').lstrip('def')
wrapper.__doc__ = docs "n" (func.__doc__ or '')
return wrapper
class A(object):
def __init__(self):
super(A, self).__init__()
@dec
def f(self, x):
"""something"""
print '%s.f(%s)' % (self, x)
@dec
def myfunc():
print "myfunc"
@dec
def myfunc2():
print "myfunc2"
@dec
def myfunc3():
print "myfunc3"
if __name__ == "__main__":
list = []
for x in xrange(3):
list.append(A())
[a.f(123) for a in list]
myfunc()
myfunc()
myfunc2()
myfunc2()
myfunc3()
myfunc3()
输出:
代码语言:javascript复制<__main__.A object at 0x00B9F2D0>.f(123)
Sig of f is 11932616
<__main__.A object at 0x00B9F430>.f(123)
Sig of f is 11925464
<__main__.A object at 0x00B9F450>.f(123)
Sig of f is 11918112
myfunc
Sig of myfunc is 11925624
myfunc
Sig of myfunc is 11925624
myfunc2
Sig of myfunc2 is 11794592
myfunc2
Sig of myfunc2 is 11794592
myfunc3
Sig of myfunc3 is 11925144
myfunc3
Sig of myfunc3 is 11925144
在这个示例中,dec
装饰器用于在类A
的方法f
以及函数myfunc
、myfunc2
和myfunc3
上。当这些函数/方法被调用时,dec
装饰器会将obj绑定到self(如果是方法)或实例化obj(如果是函数)。然后,dec
装饰器会返回一个新函数/方法,该函数/方法使用obj。
请注意,这种解决方案只适用于对象obj在实例化时创建的情况。如果obj需要在其他时间创建,那么您需要修改此解决方案以适应您的具体情况。