【问题标题】:Python: Decorators: How does the following code work?Python:装饰器:以下代码如何工作?
【发布时间】:2010-01-10 06:02:41
【问题描述】:

以下代码中的 cmets 是否正确?特别是“instance = ...”那个?

# This does nothing.

class donothing(object):
    def __init__(self, func):
        """
        The 'func' argument is the function being decorated because in this
        case, we're not instantiating the decorator class. Instead we are just
        using the class object as a callable (a class is always callable as this
        is how an instance is returned) to use as a decorator, which means that
        it is being instantiated upon definition of the decorated function and
        the decorated function is being passed in as an argument to the class's
        __init__ method.
        """
        self.func = func

    def __call__(self, *args, **kwargs):
        """
        The __call__ function is called when the decorated function is called
        because the function has be eaten by the decorator class. Now it's up to
        the this method to return a call to the original function. The arguments
        are passed in as args, kwargs to be manipulated.
        """
        # Returns original function call with original arguments.
        return self.func(*args, **kwargs)

@donothing
def printer(text):
    print(text)

printer('hello world')

# The printer function is now an alias for the donothing instance created, so
# the preceding was the same as:
#
# instance = donothing(printer)
# instance('hello world')
#


# Next example:

class checkforkeysinparams(object):
    def __init__(self, required):
        self.required = set(required)

    def __call__(self, params):
        def wrapper(params):
            missing = self.required.difference(params)
            if missing:
                raise TypeError('Missing from "params" argument: %s' % ', '.join(sorted(missing)))
        return wrapper


# Apply decorator class, passing in the __init__'s 'required' argument.

@checkforkeysinparams(['name', 'pass', 'code'])
def complex_function(params):
    # Obviously these three are needed or a KeyError will be raised.
    print(params['name'])
    print(params['pass'])
    print(params['code'])


# Create params to pass in. Note, I've commented out one of the required params.

params = {
    'name': 'John Doe',
    'pass': 'OpenSesame',
    #'code': '1134',
}

# This call will output: TypeError: Missing from "params" argument: code

complex_function(params=params)

【问题讨论】:

  • 是的,instance = ... 的内容几乎就是 @donothing 装饰器在内部的使用方式。
  • 你可以直接测试它而不是问“这行得通吗?”...
  • @Tor Valamo 有时间学习阅读。这是非常解放的。我的问题是:“下面的代码是如何工作的?”
  • 有趣的是,您所说的donothing 实际上与内置的staticmethod 在实践中的功能非常相似(尽管不是在实现中)。事实上,我最近遇到了一种情况,staticmethod 并没有按照我需要的方式工作,所以我想出了你的确切课程,除了我实际上称之为staticmethod 并且我一直将它用作静态方法的替代品,比真实的方法更灵活。

标签: python decorator


【解决方案1】:

是的,完美的描述,装饰器donothing装饰了函数printer并返回一个类donothing的对象,所以是的装饰器简单地归结为这个

x = donothing(func) # donothing is a class not function

如果你想避免使用@deco 语法,你可以像这样使用它。

所以现在 x 是一个对象,当你执行 x() 时,该对象的 __call__ 被调用,并在那里调用 __init__ 中传递的函数

编辑: 第二个装饰器是错误的,因为它只检查参数但从不调用被传递的函数 传递给装饰器的函数是名称params,但应该是类似func或更好的名称

你可以通过传递正确的参数来测试它什么都不做

params = {
    'name': 'John Doe',
    'pass': 'OpenSesame',
    'code': '1134',
}
complex_function(params=params)

它不会像 complex_function 那样打印参数。

所以正确的装饰器是

class checkforkeysinparams(object):
    def __init__(self, required):
        self.required = set(required)

    def __call__(self, func):
        def wrapper(params):
            missing = self.required.difference(params)
            if missing:
                raise TypeError('Missing from "params" argument: %s' % ', '.join(sorted(missing)))

            func(params)

        return wrapper

在第一个示例中,类本身被用作装饰器,这里类checkforkeysinparams 的对象被用作装饰器 因此函数被传递给该对象的__call__

【讨论】:

  • 感谢您的澄清,顺便说一句,我喜欢 @ 语法。第二个呢。
  • @orokusaki,我添加了第二个装饰器的解释,顺便说一句编码错误
猜你喜欢
  • 2016-12-01
  • 2011-07-25
  • 2020-04-08
  • 1970-01-01
  • 2016-03-06
  • 2017-10-21
  • 2016-01-24
  • 2021-02-08
  • 2017-05-04
相关资源
最近更新 更多