课堂上的装饰师

2024-09-25 08:34:19 发布

您现在位置:Python中文网/ 问答频道 /正文

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

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()

输出为:

^{pr2}$

这就是我想要的。但是现在让我们假设我想将merged和{}作为静态或类方法。只要decorator不在类名称空间中,这也会起作用。有什么好方法可以把装饰器放在命名空间中吗?我不想列举所有不起作用的方法,但主要问题是如果merger是一个方法,它就不能访问{}方法。也许这是一件很愚蠢的事情,但是有没有人在同一个类中使用了所有的decorator和decorated方法?在


Tags: 方法returndefargsmergedmergerlockwargs
2条回答

实际上,把它们放在一个类中应该没有问题。在类主体内部时,您可以通过简单地命名到目前为止定义的任何变量:

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

print A.c

这将产生结果3,因为当Python执行一个类主体时,函数可以“看到”已声明的变量a和b。因此,以下方法同样有效:

^{pr2}$

那么,你的合并职能呢?问题是包装器函数在类体完成执行后长时间运行,并且它定义的变量不再在封闭范围内。那你怎么能提到他们呢?用类名作为前缀!像这样:

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的一般规则是:在类主体级别运行的代码可以讨论到目前为止在它内部定义的所有变量和方法,这意味着您可以使用这些类变量作为包装器。但是一旦你进入了类中的一个函数,不管它是类函数、静态函数还是方法(这个包装器是一个类方法,因为它接受参数,但没有“self”),那么你就必须使用类的名称来“获取”它的内容。在

“有没有什么好方法可以将decorator放入命名空间?”在

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

你永远不需要装饰器作为类的方法,你只需要从另一个方法调用一个方法。在

相关问题 更多 >