0

参考

在写这个问题之前,我已经参考了以下一些有趣的问题,并且觉得这个场景没有被解释/覆盖:

我有一个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. Test_method_1所以simple_function定义可以写成如下:

t = Test()

@t.Test_method_2
def simple_function():
    print 'this is a simple_function'

注意:Test_method_2Test_method_1使用适当的参数调用。

现在的问题:

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

Test_method_2作为带有任意参数的装饰器的用法simple_function如下:

t = Test()
@t.Test_method_2(a, b, c, d, e=f, g=h)
def simple_function(x, y, z, n=m):
    print 'this is a simple_function'
4

1 回答 1

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'}关键字参数传入。

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

嵌套函数编写起来更紧凑,而使用类比嵌套作用域提供了更多的自省选项。

于 2013-02-10T21:24:04.530 回答