我正在寻找一种减少样板装饰器的方法.我们有很多使用@decorate的类.例如:
class MyClass(Base):
@decorate
def fun1(self):
pass
@decorate
def fun2(self):
pass
def fun3(self):
pass
Run Code Online (Sandbox Code Playgroud)
我想这样做,默认情况下装饰者在那里,除非有人另有说明.
我使用此代码进行自动装配
from functools import wraps
def myDecorator(func):
@wraps(func)
def decorator(self, *args, **kwargs):
try:
print 'enter'
ret = func(self, *args, **kwargs)
print 'leave'
except:
print 'exception'
ret = None
return ret
return decorator
class TestDecorateAllMeta(type):
def __new__(cls, name, bases, local):
for attr in local:
value = local[attr]
if callable(value):
local[attr] = myDecorator(value)
return type.__new__(cls, name, bases, local)
class TestClass(object):
__metaclass__ = TestDecorateAllMeta
def test_print2(self, val):
print val
def test_print(self, val):
print val
c = TestClass()
c.test_print1("print 1")
c.test_print2("print 2")
Run Code Online (Sandbox Code Playgroud)
我的问题是:
理想情况下,我的最终解决方案是:
class TestClass(object):
__metaclass__ = TestDecorateAllMeta
def autowrap(self):
print("Auto wrap")
@dont_decorate
def test_dont_decorate(self, val):
print val
Run Code Online (Sandbox Code Playgroud)
编辑
要谈谈下面的评论之一,因为classess可以调用而不是执行
if callable(value):
Run Code Online (Sandbox Code Playgroud)
它应该是:
if isinstance(value,types.FunctionType)
Run Code Online (Sandbox Code Playgroud)
我不会让我的类的用户指定一个__metaclass__属性,而是让它们从定义它的基类派生。无需不必要地暴露管道。
除此之外,看起来还不错。您的@dont_decorate函数装饰器可以通过在原始函数上设置一个属性来实现,然后您的类装饰器会检测该属性并跳过装饰(如果存在)。
def dont_decorate(func):
func._dont_decorate = True
return func
Run Code Online (Sandbox Code Playgroud)
然后在您的元类中,您现在刚刚放置了以下行if callable(value)::
if callable(value) and not hasttr(value, "_dont_decorate"):
Run Code Online (Sandbox Code Playgroud)
顺便说一句,类是可调用的,因此如果您不想装饰内部类,您可能应该使用isinstance()而不是检查函数callable()。
如果您对更明确的替代方案感兴趣,您可以看看最近的这个问题,其中有人想使用类装饰器做本质上相同的事情。不幸的是,这有点复杂,因为当装饰器看到这些方法时,它们已经被包装了。
| 归档时间: |
|
| 查看次数: |
2099 次 |
| 最近记录: |