python decorators获取函数变量

时间:2014-03-24 21:12:57

标签: python python-decorators

我有这段代码:

def check_karma(needed_karma, user_karma):
    # check karma or exit
    return True

def hello_world():
    user_karma = 50
    check_karma(20, user_karma)
    print "Hello World"

我可以在这里使用装饰器吗?,像这样:

...
@check_karma(20, user_karma)
def hello_world():
    user_karma = 50
    print "Hello World"

我不知道是否可以访问函数内部的数据,因为我在测试脚本中成功编写了@check_karma(20)。

1 个答案:

答案 0 :(得分:0)

是的,在这个实例中可以使用一个装饰器(它实际上可能是有益的),但是,它并不像定义一个函数那么简单。在这种情况下,您想要做的是定义所谓的仿函数仿函数是一个可以作为函数运行的类。

例如,假设你有班级Apple。您可以通过执行以下操作来实例化此类的对象:

apple = Apple(color='red')

现在,如果这是仿函数,您可以使用apple对象更进一步,就好像它是一个函数一样,通过apple()调用它。这可以用来创建你想要制作的装饰器。您将在装饰器的定义中初始化check_karma ,如下所示:

@check_karma(needed_karma)
def hello_world():
    ...

这是因为装饰者必须是函数才能返回另一个函数。上面的代码片段基本上是这样做的:

def hello_world():
    ...
hello_world = check_karma(needed_karma)(hello_world)

然后每次调用hello_world时,我们都会调用check_karma 仿函数返回的函数。 user_karma可能应该从其他地方请求。

以下是如何在代码中应用此功能的示例:

user_karma = 50  # pretend this is where you store `user_karma`.

class KarmaRestrictor:
    def __init__(self, needed_karma):
        self.needed_karma = needed_karma

    def __call__(self, restricted_func):
        # This is the actual decoration routine. This `__call__` descriptor
        # is what makes this class a **functor**.

        def _restricted_func(*args, **kwargs):
            if self.get_user_karma() >= self.needed_karma:
                return restricted_func(*args, **kwargs)
            else:
                # TODO: Maybe have a failure routine?
                pass

        return _restricted_func

    def get_user_karma(self):
        return user_karma  # wherever you store this.

check_karma = KarmaRestrictor  # give this decorator an alias.

@check_karma(20)
def hello_world():
    print 'Hello World'