2010-01-10 54 views
1

下面的代码中的注释是否正确?特别是“实例= ...”吗?Python:装饰器:下面的代码是如何工作的?

# 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) 
+0

是,'instance = ...'的东西几乎是'@ donothing'装饰器在内部被使用的方式。 – 2010-01-10 06:27:34

+0

你可以测试它,而不是问“这是否工作?”... – 2010-01-10 08:24:49

+0

@Tor Valamo学习阅读某个时间。这是非常自由的。我的问题是:“以下代码如何工作?” – orokusaki 2010-01-11 02:15:05

回答

2

是完美的描述,装饰donothing装饰功能printer并返回donothing类的对象,所以是装饰简单地归结为

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

,如果你能使用它像这样,你希望避免@deco语法。

所以现在x是一个对象,当你做X(),该对象的__call__被调用,有它调用中传递的功能__init__

编辑: 其次装饰是错误的,因为它只检查了参数,但永远不会调用传递 和函数的函数传递给装饰器的名字params但应命名像FUNC或更好的名字

可以测试它通过传递正确的PARAMS

什么都不做
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类这里的对象被用作deocrator 因此功能被传递给该对象的__call__

+0

甜的thx澄清,顺便说一句,我喜欢@语法。那么第二个呢。 – orokusaki 2010-01-10 07:01:29

+0

@orokusaki,我添加了第二个装饰者的解释,其中btw被错误编码 – 2010-01-10 08:20:40

+0

哦,甜蜜的感谢Anurag。 – orokusaki 2010-01-11 02:13:40