使用方法(使用任意参数)装饰函数

时间:2013-02-10 21:14:38

标签: python function methods decorator python-decorators

参考

在写这个问题之前,我已经提到了以下一些有趣的问题,并认为这个场景没有解释/涵盖:

我有function如下:

def simple_function():
    print 'this is a simple_function'

而且,我有以下class一些methods

class Test:

    def Test_method_1(self, func, args=None, kwargs=None):
        print 'this is Test::Test_method_1'
        <execute some instructions here>

    def Test_method_2(self):
        print 'this is Test::Test_method_2'

我正在使用Test_method_1simple_function,如下所示:

t = Test()
t.Test_method_1(simple_function)

假设simple_function采用任意参数,则调用Test_method_1如下:

def simple_function(a, b, c, d=f, g=h):
    print 'this is a simple_function'

t = Test()
t.Test_method_1(simple_function, args=[a, b, c], kwargs={d:f, g:h})

现在,我想将Test_method_2用作decorator version的{​​{1}}。所以Test_method_1定义可以写成如下:

simple_function

注意:t = Test() @t.Test_method_2 def simple_function(): print 'this is a simple_function' 将使用适当的参数调用Test_method_2

现在问题:

  • 1 - 这可能吗?
  • 2 - 如果可能,如何将装饰函数的名称(此处Test_method_1)作为参数传递给simple_function(包括Test_method_2)?
  • 3 - [这是杀手问题,我相信]我想将任意参数传递给self(装饰者)和Test_method_2(正在装饰的函数) - simple_function - 如何定义*args and **kwargs来接收参数(包括Test_method_2)?

使用self作为Test_method_2的装饰器以及两者的任意参数如下:

simple_function

1 个答案:

答案 0 :(得分:1)

当然有可能。所有@decorator语法都定义了后面的函数,然后调用装饰器,传入后面的函数并用返回的函数替换对该函数的引用。

以下内容:

@foo
def bar():
    pass

被翻译为:

def bar():
    pass
bar = foo(bar)

这意味着你的t.Test_method_2()方法必须要有一个参数,即待装饰的函数,并返回一些可调用的东西:

import functools

def Test_method_2(self, func):
    @functools.wraps(func)
    def wrapper(self, *args, **kw):
        print 'Wrapped function name:', func.__name__
        return func(*args, **kw)
    return wrapper

将是返回包装函数的最小装饰器,并在调用时打印包装函数的名称。参数被称为并不重要;我在这里使用了func,但它可以是任何合法的python标识符。

self是方法签名的标准部分。因为您在实例Test_method_2上引用t,所以Python会自动为您处理self参数,就像处理所有方法一样。

@后面的任何内容只是一个表达式。所以如果你使用语法:

@t.Test_method_2(a, b, c, d, e=f, g=h)

然后Test_method_2()应该返回一个装饰器函数。一个额外级别的范围嵌套应该这样做:

def Test_method_2(self, *args, **kw):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*wrapperargs, **wrapperkw):
            fargs = args + wrapperargs
            fkw = dict(kw)
            fkw.update(wrapperkw)
            return func(*fargs, **fkw)
        return wrapper
    return decorator

解构这个:

@t.Test_method_2(5, 6, 7, 8, baz='spam', ham='eggs')
def simple_function(x, y, z, n=m):
    print 'this is a simple_function'

@之后的部分,t.Test_method_2(5, 6, 7, 8, baz='spam', ham='eggs')返回嵌套函数decorator

@decorator
def simple_function(x, y, z, n=m):
    print 'this is a simple_function'

然后哪个python变成:

simple_function = decorator(simple_function)

decorator(func)返回wrapper(*wrapperargs, **wrapperkw)

调用simple_function(1, 2, foo='bar')会调用wrapper(1, 2, foo='bar')来调用原始 simple_function()并传递fargs = [5, 6, 7, 8, 1, 2]fkw = {'baz': 'spam', 'ham': 'eggs', 'foo': 'bar'}作为位置和关键字参数。

您在链接问题中看到的类装饰器模式以类似的方式工作; @之后的表达式返回被调用的东西;而不是嵌套函数,而是创建一个类实例。这只是存储装饰器使用状态的两种不同方法。

嵌套函数的编写要小一些,而使用类可以提供比嵌套范围更多的内省选项。