【问题标题】:Working of a Decorator装饰者的工作
【发布时间】:2013-03-03 00:47:47
【问题描述】:

我有一个关于装饰器工作的问题。我想用一个例子来解释我的问题

我为理解装饰器而实现的代码

import sys
import inspect
def entryExit(f):
    def new_f(self,*args, **kwargs):
        print "Entering", f.__name__,self.__class__.__name__,inspect.getargspec(f).args[1:] 
        f(self,*args)        
        print "Exited", f.__name__,self.__class__.__name__,inspect.getargspec(f).args[1:]        
    return new_f


class A:
    @entryExit
    def move(self,g,h):
        print "hello"        
        print g,h            

    @entryExit    
    def move1(self,m,n):
        print "hello"        
        print m,n
        return m
a=A()
a.move(5,7)
h=a.move1(3,4)
print h

这段代码的输出是

Entering move A ['g', 'h']
hello
5 7
Exited move A ['g', 'h']
Entering move1 A ['m', 'n']
hello
3 4
Exited move1 A ['m', 'n']
None

输出的最后一行显示None。但是通过使用装饰器改变了方法的实际含义。方法move1 中的return 语句未执行。我需要的实际输出是

Entering move A ['g', 'h']
hello
5 7
Exited move A ['g', 'h']
Entering move1 A ['m', 'n']
hello
3 4
Exited move1 A ['m', 'n']
3

那么我在创建装饰器时是否犯了任何错误,或者装饰器总是忽略函数中的返回语句?

【问题讨论】:

  • 装饰器是只是函数,所以你需要像对待任何其他链式函数调用一样对待它..

标签: python return decorator


【解决方案1】:

要让函数返回一个值,您必须将装饰器的定义更改为:

def new_f(self,*args, **kwargs):
    print "Entering", f.__name__,self.__class__.__name__,inspect.getargspec(f).args[1:] 
    ret = f(self,*args)        
    print "Exited", f.__name__,self.__class__.__name__,inspect.getargspec(f).args[1:]    
    return ret    
return new_f

并不是装饰器“总是忽略” return 语句,而是您必须自己处理 return ——就像您必须使用 *args**kwargs 处理参数一样。

【讨论】:

    【解决方案2】:

    问题是装饰器丢弃了被装饰函数的返回值。

    以下内容:

    def new_f(self,*args, **kwargs):
        print "Entering", f.__name__,self.__class__.__name__,inspect.getargspec(f).args[1:] 
        f(self,*args)        
        print "Exited", f.__name__,self.__class__.__name__,inspect.getargspec(f).args[1:]        
    

    应改为:

    def new_f(self,*args, **kwargs):
        print "Entering", f.__name__,self.__class__.__name__,inspect.getargspec(f).args[1:] 
        ret = f(self,*args)        
        print "Exited", f.__name__,self.__class__.__name__,inspect.getargspec(f).args[1:]        
        return ret
    

    您当前的代码忽略f(self,*args) 的返回值并隐式返回None

    【讨论】:

    • @NPE 非常感谢。现在一切都说得通了。我还有一个疑问,是否可以检索在运行时返回的参数名称。
    • 在我的情况下,它会是“m”。是否可以使用装饰器进行检索?
    • @karthik:不,那在函数的源代码中。 (你为什么需要它?)
    • @David Robinson,因为我的工作是通过插入源代码来解析 python。所以我使用装饰器将代码插入方法并在执行期间检索动态信息。我能够检索除执行期间返回的参数之外的所有信息
    • @karthik:听起来……很牵强。您确定需要动态地将代码插入方法中,并且没有其他方法可以做您想做的事情吗?
    【解决方案3】:

    试试这个:

    def new_f(self,*args, **kwargs):
            print "Entering", f.__name__,self.__class__.__name__,inspect.getargspec(f).args[1:] 
            r = f(self,*args)        
            print "Exited", f.__name__,self.__class__.__name__,inspect.getargspec(f).args[1:]  
            return r      
    return new_f
    

    当你实际调用装饰器内部的函数时,就会发生返回。所以,你也需要从装饰函数中返回它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-05-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-04
      相关资源
      最近更新 更多