【python】装饰器与装饰

介绍

装饰者

装饰器很可能属于 Python 中最漂亮和最强大的设计可能性,但同时,许多人认为这个概念很复杂。准确地说,装饰器的使用非常简单,但是编写装饰器可能会很复杂,尤其是如果您对装饰器和一些函数式编程概念没有经验的话。

尽管它是相同的底层概念,但我们在 Python 中有两种不同的装饰器:

  • 函数装饰器
  • 类装饰器

Python 中的装饰器是用于修改函数或类的任何可调用 Python 对象。对函数“func”或类“C”的引用传递给装饰器,装饰器返回修改后的函数或类。修改后的函数或类通常包含对原始函数“func”或类“C”的调用。

你也可以参考我们关于装饰器记忆的章节。

如果你喜欢本页右侧的图片,如果你也对使用 Python、Numpy、Scipy 和 Matplotlib 进行图像处理感兴趣,你一定会喜欢我们关于图像处理技术的章节,它解释了整个制作过程——我们的装饰者和标志图片!

装饰器的第一步

我们从我们的各种 Python 培训课程中了解到,装饰器的定义有一些地方,很多初学者都会卡在那里。

因此,我们将通过重复函数的一些重要方面来介绍装饰器。首先,您必须知道或记住函数名是对函数的引用,并且我们可以为同一个函数分配多个名称:

def  succ ( x ):
    返回 x  +  1
后继者 =  succ
后继者( 10 )

输出:

11
成功( 10 )

输出:

11

这意味着我们有两个名称,即同一个函数的“succ”和“successor”。下一个重要的事实是我们可以删除“succ”或“successor”而不删除函数本身。

del  succ
继任者( 10 )

输出:

11

函数内的函数

在函数内部拥有或定义函数的概念对于 C 或 C++ 程序员来说是全新的:

def  f (): 
    def  g (): 
        print ( "嗨,是我'g'" ) 
        print ( "谢谢你给我打电话" ) 
    print ( "这是'f'函数" ) 
    print ( "我在打电话' g' 现在:" ) 
    g () 
f ()

输出:

这是函数'f'
我现在打电话给'g':
嗨,是我'g'
谢谢你给我打电话

在函数中使用“正确”返回语句的另一个示例:

def  temperature ( t ): 
    def  celsius2fahrenheit ( x ): 
        return  9  *  x  /  5  +  32 
    result  =  "It's "  +  str ( celsius2fahrenheit ( t ))  +  "degrees!"  
    返回 结果
打印(温度(20 ))

输出:

这是68.0度!

下面的例子是关于阶乘函数的,我们之前定义如下:

def  factorial ( n ): 
    """ 计算 n 的阶乘,
        n 应该是一个整数并且 n <= 0 """ 
    if  n  ==  0 : 
        return  1 
    else : 
        return  n  *  factorial ( n - 1 )

如果有人向此函数传递负值或浮点数会发生什么?它永远不会结束。您可能会想到如下检查:

def  factorial ( n ): 
    """ 计算 n 的阶乘,
        n 应该是一个整数并且 n <= 0 """ 
    if  type ( n )  ==  int  and  n  >= 0 : 
        if  n  ==  0 : 
            return  1 
        else : 
            return  n  *  factorial ( n - 1 ) 
    else : 
        raise  TypeError ( "n 必须是一个正整数或零" )

如果用4 '' for example, i.e.阶乘 (4) ''调用这个函数,首先要检查的是它是否是我的正整数。原则上,这是有道理的。“问题”现在出现在递归步骤中。现在factorial (3) '' is called. This call and all others also check whether it is a positive whole number. But this is unnecessary: If you subtract the value1 '' 从一个正整数,你又得到一个正整数或 `` 0 ''。因此,我们的函数的两个明确定义的参数值。

使用嵌套函数(局部函数)可以优雅地解决这个问题:

def  factorial ( n ): 
    """ 计算 n 的阶乘,
        n 应该是一个整数并且 n <= 0 """ 
    def  inner_factorial ( n ): 
        if  n  ==  0 : 
            return  1 
        else : 
            return  n  *  inner_factorial ( n - 1 )
    如果 类型( n )  ==  int 并且 n  >= 0 :
        返回 inner_factorial ( n ) 
    else 加注 类型错误“n应为positve int或0” 

作为参数的函数

如果你只看前面的例子,这似乎不是很有用。结合 Python 函数的两个更强大的可能性,它会变得很有用。由于函数的每个参数都是对对象的引用,函数也是对象,因此我们可以将函数——或者更好的“对函数的引用”——作为参数传递给函数。我们将在下一个简单示例中演示这一点:

def  g (): 
    print ( "嗨,是我 'g'" ) 
    print ( "谢谢你给我打电话" ) 
def  f ( func ): 
    print ( "嗨,是我 'f'" ) 
    print ( "我会打电话给我'func' now" ) 
    func () 
f ( g )

输出:

嗨,我是‘f’
我现在就叫'func'
嗨,是我'g'
谢谢你给我打电话

您可能对输出不满意。'f' 应该写成它调用的是 'g' 而不是 'func'。当然,我们需要知道 func 的“真实”名称是什么。为此,我们可以使用属性__name__,因为它包含以下名称:

def  g (): 
    print ( "嗨,是我 'g'" ) 
    print ( "谢谢你给我打电话" ) 
def  f ( func ): 
    print ( "嗨,是我 'f'" ) 
    print ( "我会打电话给你'func' now" ) 
    func () 
    print ( "func 的真名是"  +  func . __name__ )  
f ( g )

输出:

嗨,我是‘f’
我现在就叫'func'
嗨,是我'g'
谢谢你给我打电话
func 的真名是 g

输出再次解释了正在发生的事情。另一个例子:

import  math 
def  foo ( func ): 
    print ( "The function "  +  func . __name__  +  " was connected to foo" ) 
    res  =  0 
    for  x  in  [ 1 ,  2 ,  2.5 ]: 
        res  +=  func ( x ) 
    return  res 
print ( foo ( math . sin ))
打印( foo ( math . cos )))

输出:

函数 sin 被传递给 foo
2.3492405557375347
函数 cos 被传递给 foo
-0.6769881462259364

函数返回函数

函数的输出也是对对象的引用。因此函数可以返回对函数对象的引用。

def  f ( x ): 
    def  g ( y ): 
        return  y  +  x  +  3  
    return  g 
nf1  =  f ( 1 ) 
nf2  =  f ( 3 ) 
print ( nf1 ( 1 ) ) 
print ( nf2 ( 1 ))

输出:

5
7

前面的例子看起来很人为,完全没用。我们现在将展示另一个面向语言的示例,它显示了更实际的触感。好的,仍然不是一个有用的功能。我们用几乎不言自明的名称编写了一个函数greeting_func_gen。因此,此函数返回(或生成)可用于创建不同语言(即德语、法语、意大利语、土耳其语和希腊语)的人的函数:

高清 greeting_func_gen (郎):
    DEF  customized_greeting (名称):
        如果==  “德” #德国
            短语 =  “Guten摩根” 
        ELIF==  “FR” :法国
            短语 =  “卓悦” 
        ELIF==  “它” :  # 意大利语
            短语 =  "Buongiorno " 
        elif  lang  ==  "tr" :  # 土耳其语
            短语 =  "Günaydın "
        ELIF==  "gr" :  # 希腊语
            短语 =  "Καλημερα " 
        else :
            短语 =  "Hi "
        返回 短语 + 名称 +  "!" 
    返回 customized_greeting 
say_hi  =  greeting_func_gen (“TR” 打印(say_hi (“Gülay” ))    的方式#这个土耳其名字的意思是“玫瑰月亮”

输出:

Günaydın Gülay!

在以下示例中,它变得越来越有用,同时也更加面向数学。我们现在将实现一个多项式“工厂”函数。我们将从编写一个可以创建 2 次多项式的版本开始。

p(X)=一个X2+乙X+C

作为多项式工厂函数的 Python 实现可以这样写:

def  polynomial_creator ( a ,  b ,  c ): 
    def  polynomial ( x ):
        返回 a  *  x ** 2  +  b  *  x  +  c
    返回 多项式
p1  =  polynomial_creator ( 2 ,  3 ,  - 1 ) 
p2  =  polynomial_creator ( - 1 ,  2 , 1 )
 X  范围( - 2 ,  2 ,  1 ):
    打印( x ,  p1 ( x ),  p2 ( x ))

输出:

-2 1 -7
-1 -2 -2
0 -1 1
1 4 2

我们可以推广我们的工厂函数,以便它可以用于任意次数的多项式:

∑克=0n一个克⋅X克=一个n⋅Xn+一个n-1⋅Xn-1+...+一个2⋅X2+一个1⋅X+一个0

def  polynomial_creator ( * coefficients ): 
    """ 系数的形式为 a_n, ... a_1, a_0 
    """ 
    def  polynomial ( x ): 
        res  =  0 
        for  index ,  coeff  in  enumerate ( coefficients [:: - 1 ]) : 
            res  +=  coeff  *  x **  index 
        return  res 
    return  polynomial 
p1  =  polynomial_creator ( 4 ) 
p2  = polynomial_creator ( 2 ,  4 ) 
p3  =  polynomial_creator ( 1 ,  8 ,  - 1 ,  3 ,  2 ) 
p4   =  polynomial_creator ( - 1 ,  2 ,  1 ) 
for  x  in  range ( - 2 ,  2 ,  1 ): 
    print ( x ,  p1 ( x ),  p2 ( x ), p3 ( x ),  p4 ( x ))

输出:

-2 4 0 -56 -7
-1 4 2 -9 -2
0 4 4 2 1
1 4 6 13 2

例如,函数 p3 实现以下多项式:

p3(X)=X4+8⋅X3-X2+3⋅X+2

我们装饰器 polynomial_creator 中的多项式函数可以更有效地实现。我们可以用某种方式对它进行因式分解,这样它就不需要任何求幂。

没有求幂的一般多项式的因式分解版本:

r电子秒=(...(一个n⋅X+一个n-1)⋅X+...+一个1)⋅X+一个0

避免取幂的多项式创建器装饰器的实现:

def  polynomial_creator ( * coeffs ): 
    """ 系数的形式为 a_n, a_n_1, ... a_1, a_0 
    """ 
    def  polynomial ( x ): 
        res  =  coeffs [ 0 ] 
        for  i  in  range ( 1 ,  len ( coeffs )): 
            res  =  res  *  x  +  coeffs [ i ]
        返回 res
    返回 多项式
p1  =  polynomial_creator ( 4) 
p2  =  polynomial_creator ( 2 ,  4 ) 
p3  =  polynomial_creator ( 1 ,  8 ,  - 1 ,  3 ,  2 ) 
p4  =  polynomial_creator ( - 1 ,  2 ,  1 ) 
for  x  in  range ( - 2 ,  2 ,  1 ): 
    print ( x ,  p1 ( x ),  p2( x ),  p3 ( x ),  p4 ( x ))

输出:

-2 4 0 -56 -7
-1 4 2 -9 -2
0 4 4 2 1
1 4 6 13 2

如果您想了解有关多项式以及如何创建多项式类的更多信息,可以继续阅读我们关于多项式的章节。

一个简单的装饰器

现在我们已经准备好定义我们的第一个简单装饰器了:

def  our_decorator ( func ): 
    def  function_wrapper ( x ): 
        print ( "调用前"  +  func . __name__ ) 
        func ( x ) 
        print ( "调用后"  +  func . __name__ ) 
    return  function_wrapper 
def  foo ( x ): 
    print ( "Hi , foo 已被调用 "  +  str ( x ))
打印("我们在装饰前调用 foo:" ) 
foo ( "Hi" ) 
print ( "我们现在用 f 装饰 foo:" ) 
foo  =  our_decorator ( foo ) 
print ( "我们在装饰后调用 foo:" ) 
foo ( 42 )

输出:

我们在装饰前调用 foo :
嗨, foo 已被称为 Hi
我们现在用 f 装饰 foo:
我们在装饰后调用 foo :
在调用 foo 之前
嗨, foo 已被调用 42
调用 foo 后

如果您查看前一个程序的输出,您可以看到发生了什么。在修饰“foo = our_decorator(foo)”之后,foo 是对“function_wrapper”的引用。'foo' 将在 'function_wrapper' 内被调用,但在调用之前和之后将执行一些额外的代码,即在我们的例子中两个打印函数。

Python 中装饰器的常用语法

Python 中的装饰通常不像我们在前面的示例中那样执行,即使符号foo = our_decorator(foo)很吸引人且易于掌握。这就是我们使用它的原因!您还可以在我们之前的方法中看到一个设计问题。“foo”在同一个程序中存在两个版本,装饰前和装饰后。

我们现在要做一个适当的装饰。装饰出现在函数头之前的行中。“@”后跟装饰器函数名称。

我们现在将重写我们的初始示例。而不是写声明

 foo = our_decorator(foo)

我们可以写

 @our_decorator 

但是这条线必须直接定位在装饰函数的前面。完整的例子现在看起来像这样:

def  our_decorator ( func ): 
    def  function_wrapper ( x ): 
        print ( "调用前"  +  func . __name__ ) 
        func ( x ) 
        print ( "调用后"  +  func . __name__ ) 
    return  function_wrapper 
@our_decorator 
def  foo ( x ): 
    print ( “嗨, foo 已被调用”  +  str ( x )) 
foo (“你好” )

输出:

在调用 foo 之前
嗨, foo 已被称为 Hi
调用 foo 后

我们可以用我们的装饰器“our_decorator”装饰每一个接受一个参数的其他函数。我们在下面演示这一点。我们稍微改变了我们的函数包装器,以便我们可以看到函数调用的结果:

def  our_decorator ( func ): 
    def  function_wrapper ( x ): 
        print ( "调用前"  +  func . __name__ ) 
        res  =  func ( x ) 
        print ( res ) 
        print ( "调用后"  +  func . __name__ ) 
    return  function_wrapper 
@our_decorator 
def  succ (ñ ):
    返回 ñ  +  1个
SUCC (10 )

输出:

在调用 succ 之前
11
调用 succ 后

也可以装饰第三方函数,例如我们从模块导入的函数。在这种情况下,我们不能使用带有“at”符号的 Python 语法:

from  math  import  sin ,  cos 
def  our_decorator ( func ): 
    def  function_wrapper ( x ): 
        print ( "调用前"  +  func . __name__ ) 
        res  =  func ( x ) 
        print ( res ) 
        print ( "调用后"  +  func . __name__ ) 
    return  function_wrapper 
sin  =  our_decorator ( sin )
cos  =  our_decorator ( cos ) 
for  f  in  [ sin ,  cos ]: 
    f ( 3.1415 )

输出:

在称罪之前
9.265358966049026e-05
称罪后
调用cos之前
-0.9999999957076562
调用cos后

总而言之,我们可以说 Python 中的装饰器是一个可调用的 Python 对象,用于修改函数、方法或类定义。将要修改的原始对象作为参数传递给装饰器。装饰器返回一个修改过的对象,例如一个修改过的函数,它绑定到定义中使用的名称。

前面的 function_wrapper 仅适用于只有一个参数的函数。我们提供了 function_wrapper 的通用版本,它在以下示例中接受具有任意参数的函数:

from  random  import  random ,  randint ,  choice 
def  our_decorator ( func ): 
    def  function_wrapper ( * args ,  ** kwargs ): 
        print ( "Before call"  +  func . __name__ ) 
        res  =  func ( * args ,  ** kwargs ) 
        print ( res )
        打印( “调用后”  +  func .__name__ ) 
    return  function_wrapper 
random  =  our_decorator ( random ) 
randint  =  our_decorator ( randint ) 
choice  =  our_decorator ( choice ) 
random () 
randint ( 3 ,  8 ) 
choice ([ 4 ,  5 ,  6 ])

输出:

在调用随机之前
0.3206237466802222
随机调用后
在调用 randint 之前
6
调用randint后
呼叫选择前
5
调用后选择

装饰器的用例

使用装饰器检查参数

在关于递归函数的章节中,我们介绍了阶乘函数。我们想让函数尽可能简单,我们不想掩盖潜在的想法,所以我们没有合并任何参数检查。因此,如果有人使用负参数或浮点参数调用我们的函数,我们的函数将进入无限循环。

以下程序使用装饰器函数来确保传递给函数 factorial 的参数是正整数:

def  argument_test_natural_number ( f ): 
    def  helper ( x ): 
        if  type ( x )  ==  int  and  x  >  0 : 
            return  f ( x ) 
        else : 
            raise  Exception ( "Argument is not an integer" ) 
    return  helper 
@argument_test_natural_number 
def  factorial ( n ):
    如果 n  ==  1 :
        否则返回 1
    : 
        return  n  *  factorial ( n - 1 ) 
for  i  in  range ( 1 , 10 ): 
	print ( i ,  factorial ( i )) 
print ( factorial ( - 1 ))

输出:

1 1
2 2
3 6
4 24
5 120
6 720
7 5040
8 40320
9 362880

使用装饰器计算函数调用

以下示例使用装饰器来计算函数被调用的次数。准确地说,我们可以仅将这个装饰器用于只有一个参数的函数:

def  call_counter ( func ): 
    def  helper ( x ): 
        helper 调用 +=  1
        返回 func ( x )
    助手呼叫 =  0
    返回 辅助
@call_counter 
DEF  SUCC (X ):
    返回 X  +  1张
打印(SUCC 呼叫)
用于 范围(10 ):
    SUCC (我)
打印(SUCC 电话)

输出:

0
10

我们指出我们只能将我们之前的装饰器用于函数,这些函数只接受一个参数。我们将使用 *args 和 **kwargs 符号来编写装饰器,这些装饰器可以处理具有任意数量的位置和关键字参数的函数。

def  call_counter ( func ): 
    def  helper ( * args ,  ** kwargs ): 
        helper 调用 +=  1
        返回 func ( * args ,  ** kwargs ) 
    helper call  =  0 
    return  helper 
@call_counter 
def  succ ( x ): 
    return  x  +  1 
@call_counter 
def  mul1 ( x ,  y= 1 ): 
    return  x * y  +  1 
print ( succ . calls ) 
for  i  in  range ( 10 ): 
    succ ( i ) 
mul1 ( 3 ,  4 ) 
mul1 ( 4 ) 
mul1 ( y = 3 ,  x = 2 ) 
print ( SUCC 调用)
打印(MUL1 电话)

输出:

0
10
3

带参数的装饰器

我们在以下代码中定义了两个装饰器:

def  night_greeting ( func ): 
    def  function_wrapper ( x ): 
        print ( "Good  night ," +  func . __name__  +  "returns:" ) 
        return  func ( x ) 
    return  function_wrapper 
def  Morning_greeting ( func ): 
    def  function_wrapper ( x ): 
        print ( "早上好,"  +  func . __name__  +  " 返回:" )
        return  func ( x ) 
    return  function_wrapper 
@evening_greeting 
def  foo ( x ): 
    print ( 42 ) 
foo ( "Hi" )

输出:

晚上好, foo 回来了:
42

除了问候语之外,这两个装饰器几乎相同。我们想在装饰器中添加一个参数,以便在我们进行装饰时自定义问候语。我们必须在我们之前的装饰器函数周围包装另一个函数来实现这一点。我们现在可以轻松地用希腊语说“早安”:

def  greeting ( expr ): 
    def  greeting_decorator ( func ): 
        def  function_wrapper ( x ): 
            print ( expr  +  ", "  +  func . __name__  +  "returns:" ) 
            func ( x ) 
        return  function_wrapper 
    return  greeting_decorator 
@greeting ( "καλημερα" ) 
def  foo ( x ):
    打印( 42 ) 
foo (“你好” )

输出:

καλημερα, foo 返回:
42

如果我们不想或不能使用“at”装饰器语法,我们可以通过函数调用来实现:

高清 问候(EXPR ):
    DEF  greeting_decorator (FUNC ):
        DEF  function_wrapper (X ):
            打印(EXPR  +  “ ”  +  FUNC __name__  +  “回报” 返回 FUNC (X )
        返回 function_wrapper
    回报 greeting_decorator
高清 FOO (X ):
    打印( 42 )
问候 2  = 问候("καλημερα" ) 
foo  =  greeting2 ( foo ) 
foo ( "Hi" )

输出:

καλημερα, foo 返回:
42

当然,我们不需要“greeting2”的额外定义。我们可以直接将调用“greeting(“καλημερα”)”的结果应用到“foo”上:

 foo = 问候(“καλημερα”)(foo)

使用来自 functools 的包装

到目前为止,我们定义装饰器的方式还没有考虑到属性

  • __name__ (函数名称),
  • __doc__ (文档字符串)和
  • __module__ (定义函数的模块)

装修后将失去原有的功能。

以下装饰器将保存在文件 greeting_decorator.py 中:

    定义问候(功能):
    def function_wrapper(x):
        """ function_wrapper 的问候 """
        打印(“嗨,” + func.__name__ + “返回:”)
        返回函数(x)
    返回函数_包装器 

我们在以下程序中调用它:

from  greeting_decorator  import  greeting 
@greeting 
def  f ( x ): 
    """ 只是一些愚蠢的函数 """ 
    return  x  +  4 
f ( 10 ) 
print ( "function name: "  +  f . __name__ ) 
print ( "docstring: "  +  f . __doc__ )
打印( "模块名称:"  +  f . __module__ ) 

输出:

嗨,f 返回:
函数名:function_wrapper
文档字符串:问候的函数包装器 
模块名称:greeting_decorator

我们得到了上面的“不需要的”结果。

如果我们在装饰器内部分配它们,我们可以保存函数 f 的原始属性。我们相应地更改我们之前的装饰器并将其保存为 greeting_decorator_manually.py:

定义问候(功能):
def function_wrapper(x):
    """ function_wrapper 的问候 """
    打印(“嗨,” + func.__name__ + “返回:”)
    返回函数(x)
    function_wrapper.__name__ = func.__name__
    function_wrapper.__doc__ = func.__doc__
    function_wrapper.__module__ = func.__module__
    返回函数_包装器 

在我们的主程序中,我们所要做的就是更改 import 语句。

 greeting_decorator_manually 导入 问候语

幸运的是,我们不必将所有这些代码添加到我们的装饰器中以获得这些结果。我们可以从 functools 导入装饰器“包装”,并用它在装饰器中装饰我们的函数:

from  functools  import  wraps 
def  greeting ( func ): 
    @wraps ( func ) 
    def  function_wrapper ( x ): 
        """ function_wrapper of greeting """ 
        print ( "Hi, "  +  func . __name__  +  "returns:" ) 
        return  func ( x )
    返回 function_wrapper

类而不是函数

调用方法

到目前为止,我们使用函数作为装饰器。在将装饰器定义为类之前,必须先介绍__call__类的方法。我们已经提到装饰器只是一个将函数作为输入参数的可调用对象。函数是一个可调用对象,但很多 Python 程序员不知道还有其他可调用对象。一个可调用对象是一个可以使用并且表现得像一个函数但可能不是一个函数的对象。可以以实例是可调用对象的方式定义类。__call__如果实例被称为“像函数一样”,即使用括号,则调用该方法。

class  A : 
    def  __init__ ( self ): 
        print ( "A 的一个实例被初始化了" ) 
    def  __call__ ( self ,  * args ,  ** kwargs ): 
        print ( "Arguments are:" ,  args ,  kwargs ) 
x  =  A () 
print ( "现在调用实例:" ) 
x ( 3 ,  4 ,  x = 11 ,  y =10 )
打印( "让我们再次调用它:" ) 
x ( 3 ,  4 ,  x = 11 ,  y = 10 )

输出:

A 的一个实例被初始化
现在调用实例:
参数是: (3, 4) {'x': 11, 'y': 10}
让我们再次调用它:
参数是: (3, 4) {'x': 11, 'y': 10}

我们可以使用以下__call__方法为斐波那契函数编写一个类:

 斐波那契def  __init__ ( self ): 
        self 缓存 =  {} 
    DEF  __call__ (自, Ñ ):
        如果 ñ   自我缓存:
            如果 n  ==  0 :
                自我缓存[ 0 ]  =  0 
            elif  n  ==  1 : 
                self . 缓存[ 1 ]  =  1
            否则:
                自己缓存[ n ]  =  self __call__ ( n - 1 )  +  self __call__ ( n - 2 )
        返回 self cache [ n ] 
fib  =  Fibonacci () 
for  i  in  range ( 15 ): 
    print ( fib ( i ),  end = ", " )

输出:

0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 

您可以__call__在我们教程的魔术函数一章中找到有关该方法的更多信息。

使用类作为装饰器

我们将以下装饰器重写为一个类:

def  decorator1 ( f ): 
    def  helper (): 
        print ( "Decorating" ,  f . __name__ ) 
        f () 
    return  helper 
@decorator1 
def  foo (): 
    print ( "inside foo()" ) 
foo ()

输出:

装饰 foo
在 foo() 里面

作为类实现的以下装饰器执行相同的“工作”:

 装饰器2 : 
    def  __init__ ( self ,  f ): 
        self f  =  f 
    def  __call__ ( self ): 
        print ( "Decorating" ,  self . f . __name__ ) 
        self . f () 
@decorator2 
def  foo (): 
    print ( "inside foo()" ) 
foo ()    

输出:

装饰 foo
在 foo() 里面

两个版本都返回相同的输出。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值