好的,根据清单的代码,我有一个解决方案。
如您所见,pydoc 仍然有关于装饰物的不错的文档:
class A(__builtin__.object)
| Methods defined here:
|
| f(*args, **kwargs)
| f(self, x)
| something
同样,带有修饰方法的类的每个实例都会有一个不同的obj。此外,每个函数都有自己的obj。
<__main__.A object at 0x7c209bee4a50>.f(123)
obj of <__main__.A object at 0x7c209bee4a50>.f is 136479497243752
<__main__.A object at 0x7c209bee4a10>.f(123)
obj of <__main__.A object at 0x7c209bee4a10>.f is 136479497250720
<__main__.A object at 0x7c209bee4a90>.f(123)
obj of <__main__.A object at 0x7c209bee4a90>.f is 136479497446824
myfunc
obj of myfunc is 136479497243392
myfunc
obj of myfunc is 136479497243392
myfunc2
obj of myfunc2 is 136479497245688
myfunc2
obj of myfunc2 is 136479497245688
myfunc3
obj of myfunc3 is 136479497246408
myfunc3
obj of myfunc3 is 136479497246408
代码如下:
__all__ = ['dec', 'A']
from functools import wraps
import inspect
def dec(cls=None):
# cls will be closed in subdec
def subdec(func):
# closed in wrapper, guaranteed to be unique per decorator evaluation
obj = []
@wraps(func)
def wrapper(*args, **kwargs):
if (args and type(args[0]) == cls):
instance = args[0]
# We will attach to instance a dict _objs of
# function_name:obj. This way we don't pollute the namespace
# when decorating many functions.
# Alternatively, you could make a dict external to instance
# of instance:{function_name:obj}, but that takes more work
# because you need to make it not prevent garbage collection
# of instance.
if not hasattr(instance, "_objs"):
instance._objs = {}
if func.__name__ not in instance._objs:
instance._objs[func.__name__] = []
func(*args, **kwargs) # This is only used to check the arity.
# My real code is all to do with
# manipulating obj.
print "obj of %s.%s is %s" % (
instance,
func.__name__,
id(instance._objs[func.__name__])
)
else:
# Functions are identified by the closed obj
func(*args, **kwargs)
print "obj of %s is %s" % (func.__name__, id(obj))
# Find function/method signature and prepend it to the new object's doc
try:
doc = inspect.getsourcelines(func)
except IOError:
line = "<unable to fetch definition>"
else:
line = '@'
i = 0
while line.lstrip(' ').startswith("@"):
try:
line = doc[0][i]
except IndexError:
line = "<unable to fetch definition>"
i += 1
line = line.rstrip('\n').rstrip(':').lstrip(' ').lstrip('def')
wrapper.__doc__ = line + "\n" + (func.__doc__ or '')
return wrapper
return subdec
class A(object):
def f(self, x):
"""something"""
print '%s.f(%s)' % (self, x)
A.f = dec(A)(A.f)
@dec()
def myfunc():
print "myfunc"
@dec()
def myfunc2():
print "myfunc2"
@dec()
def myfunc3():
print "myfunc3"
if __name__ == "__main__":
a, b, c = A(), A(), A()
# a, b, and c each have their own instance of obj:
a.f(123)
b.f(123)
c.f(123)
myfunc()
myfunc()
myfunc2()
myfunc2()
myfunc3()
myfunc3()
添加的外部装饰器cls 仅用于获取类的标识,因此被装饰的函数可以确定它是函数还是方法。不过,我不确定这与 [多重] 继承的效果如何……也许 manifest 的检查该部分的想法更好。