装饰者和课堂上

时间:2009-04-01 19:57:52

标签: python decorator

有没有办法在嵌套好的类结构中编写装饰器?例如,没有类就可以正常工作:

def wrap1(func):
    def loc(*args,**kwargs):
        print 1
        return func(*args,**kwargs)
    return loc

def wrap2(func):
    def loc(*args,**kwargs):
        print 2
        return func(*args,**kwargs)
    return loc


def wrap3(func):
    def loc(*args,**kwargs):
        print 3
        return func(*args,**kwargs)
    return loc

def merger(func):
    return wrap1(wrap2(wrap3(func)))


@merger
def merged():
    print "merged"


@wrap1
@wrap2
@wrap3
def individually_wrapped():
    print "individually wrapped"

merged()
individually_wrapped()

输出结果为:

1
2
3
merged
1
2
3
individually wrapped

这就是我想要的。但现在让我们说我想将mergedindividually_wrapped作为静态或类方法。只要装饰器不在类名称空间之外,这也可以工作。有没有什么好方法将装饰器放在命名空间中?我宁愿不列举所有不起作用的方法,但主要问题是如果merger是一种方法,它就无法访问wrapX方法。也许这是一个愚蠢的想做的事情,但有没有人得到这样的东西工作,所有装饰器和装饰方法在同一个类?

2 个答案:

答案 0 :(得分:5)

“有没有什么好方法可以将装饰器放在命名空间中?”

没有令人信服的理由。你有模块文件。这些是一个类和一些装饰器的整洁容器。

你不需要装饰器作为类的方法 - 你可以从另一个方法调用一个方法。

答案 1 :(得分:2)

实际上,将它们全部放入类中应该没有问题。在类体内部时,只需命名它就可以命名到目前为止定义的任何变量:

class A(object):
    a = 1
    b = 2
    c = a + b

print A.c

得到结果3,因为当Python执行一个类体时,函数可以“看到”已声明的变量a和b。所以以下内容也有效:

class B(object):
    @staticmethod
    def wrapper(*args, **kw):
       ...

    @wrapper
    def a(...):
        ...

现在,你的合并功能怎么样?问题是包装函数在类主体执行完毕后运行,并且它定义的变量不再在封闭范围内。那你怎么能引用它们呢?通过使用类的名称作为前缀!像这样:

class C(object):
    @staticmethod
    def wrap1(*args, **kw):
        ...
    @staticmethod
    def wrap2(*args, **kw):
        ...
    @staticmethod
    def wrap3(*args, **kw):
        ...
    @staticmethod
    def merger(*args, **kw):
        C.wrap1(C.wrap2(C.wrap3(...)))

    @merger
    def plain(...):
        ...

因此,Python的一般规则是:在类主体级别运行的代码可以讨论到目前为止已经定义的所有变量和方法,这意味着您可以使用这些类变量包装。但是一旦你在类中的一个函数“内部”,无论是类函数,静态函数还是方法(这个包装器是一个类方法,因为它需要args而不是“self”),那么你必须使用“获取”其内容的类的名称。