Python Decorators入门 (一)_decorators to python

当编译器经过这段代码时,aFunction()被编译然后将结果函数对象传递给myDecorator代码,后者创建一个类函数对象并取代原来的aFunction()。

myDecorator代码长什么样呢?大多数介绍性的例子都将其作为函数给出,但我发现对于decoration机制使用类而非函数来理解decorators会更容易些,而且也更强大。

Decorator所返回的对象唯一的约束是它可以作为函数使用–也就意味着它必须是可调用的。因此,作为decorators使用的任何一个类必须实现__call__。

decorator该做什么呢?它什么都能做,只是你常常期望在某些地方能够使用原来的函数代码。其实没有这个必要:

class myDecorator(object):

def __init__(self, f):

print “inside myDecorator.__init__()”

f() # Prove that function definition has completed

def __call__(self):

print “inside myDecorator.__call__()”

@myDecorator

def aFunction():

print “inside aFunction()”

print “Finished decorating aFunction()”

aFunction()

当运行这段代码时,会看见:

inside myDecorator.__init__()

inside aFunction()

Finished decorating aFunction()

inside myDecorator.__call__()

注意,myDecorator的构造器(constructor)在函数的decoration处执行。由于我们可以在__init__()里面调用f(),它意味着在调用decorator前就完成了f()的创建。另外需注意,decorator构造器接收到decorated的函数对象。你将在构造器中得到函数对象,之后在__call__()方法中进行使用(当使用类时,decoration和调用是两个泾渭分明的阶段,这也是我为何说它更简单、更强大的原因)。

当decorated之后再调用aFunction(),它的行为就完全不一样了:不再用原来的代码而开始调用myDecorator.__call__()方法。原因是decoration过程是将decoration结果取代原先的函数–在我们的例子中,myDecorator对象取代了aFunction。实际上,加入decorators之前,为了达到同样效果你需要编写十分晦涩的代码:

def foo(): pass

foo = staticmethod(foo)

有了‘@’这个decoration操作符的加入,你可以这样做:

@staticmethod

def foo(): pass

这也是有人为何反对decorators的原因。因为‘@’实在有点像一块语法糖(syntax sugar,意指指那些没有给计算机语言添加新功能,而只是对人类来说更“甜蜜“的语法。语法糖往往给程序员提供了更实用的编码方式,有益于更好的编码风格,更易读。不过其并没有给语言添加什么新东西。–译者注):通过另外一个函数传递函数对象,然后将结果赋给原来的函数。

我认为,decorator之所以产生如此大影响,就是因为其带着一点点语法糖的味道改变了人们思考程序设计的方式。事实上,当成一种语言概念对其进行形式化,这种方法使“将代码应用到其他代码之中”(比如宏)的思想出现在主流思想之中。

更多用处

现在,让我们回过头来实现第一个例子。这里我们实现一些更常规的东西,并在decorated函数中实际使用这些代码:

class entryExit(object):

def __init__(self, f):

self.f = f

def __call__(self):

print “Entering”, self.f.__name__

self.f()

print “Exited”, self.f.__name__

@entryExit

def func1():

print “inside func1()”

@entryExit

def func2():

print “inside func2()”

func1()

func2()

输出是:

Entering func1

inside func1()

Exited func1

Entering func2

inside func2()

Exited func2

现在可以看见,在整个调用期间decorated函数拥有了“Entering”和“Exited”跟踪语句。

构造器保存着自变量,即函数对象。在调用中,我们使用函数的__name__属性来显示函数名称,然后调用函数本身。

作为Decorators使用函数

对于一个decorator结果,其唯一的约束是必须是可调用的。这样它就可以完全取代decorated函数。在上面的例子中,我用包含一个__call__()方法的类的一个对象替代原有的函数。但函数对象仍是可调用的。因此我们可以使用函数(而非类)重写上一个例子,即:

def entryExit(f):

def new_f():

print “Entering”, f.__name__

f()

print “Exited”, f.__name__

return new_f

@entryExit

def func1():

print “inside func1()”

@entryExit

def func2():

print “inside func2()”

func1()

func2()

print func1.__name__

new_f()在entryExit()里定义,所以在调用entryExit()时它就创建并返回了。注意,new_f()是一个闭包(closure),因为它获得的是f的实际值。

只要定义过new_f(),它就从entryExit()返回,这样decorator机制就可以将结果作为decorated函数进行赋值了。

‘print func1.__name__’一行的输出是new_f,因为new_f函数在decoration期间已取代原函数。如果还有疑问,可以在函数返回前改变decorator函数的名字:

def entryExit(f):

def new_f():

print “Entering”, f.__name__

f()

print “Exited”, f.__name__

new_f.__name__ = f.__name__

return new_f

动态获得有关函数的信息、对函数的修改能力,都是Python的强大之处。

更多例子

既然你有一定基础了,在这里可以看到更多一些decorators的例子。注意使用类作为decorators的例子数量远多于使用函数的例子。

在本文中我有意避开含有自变量的decorated函数,在下一篇文章中我将重点讨论它。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python decorators是一种用于修改或增强函数功能的语法结构。它们允许开发者在不修改原始函数代码的情况下,通过在函数定义之前使用特殊符号(@)和装饰器函数来对函数进行包装或修饰。装饰器函数接受被装饰函数作为参数,并可以在原始函数执行之前或之后添加额外的逻辑或功能。这种技术可以用来实现缓存、日志记录、身份验证等功能。 Python decorators的使用方法可以根据具体需求进行定义和实现。常见的方法包括使用装饰器函数、使用类作为装饰器、使用带参数的装饰器等。装饰器函数是最常见的一种方式,它接受一个函数作为参数并返回一个新的函数,新函数会替换原始函数。这样,在调用原始函数时,实际上是调用了被装饰的函数,从而在不修改原始函数的情况下添加了额外的功能。 除了使用Python内置的装饰器语法,还可以使用第三方库来简化装饰器的编写和使用。例如,可以使用decorator模块来定义和使用装饰器。这个模块提供了一种更简洁的语法,可以直接在函数定义之前使用@decorator语法来应用装饰器。该模块的使用方法如下所示: ```python from decorator import decorator @decorator def hint(func, *args, **kwargs): print('{} is running'.format(func.__name__)) return func(*args, **kwargs) ``` 上述代码定义了一个名为hint的装饰器函数,它接受一个函数作为参数,并在函数执行之前打印出函数名。然后,通过在函数定义之前使用@hint语法,将装饰器应用到目标函数上。这样,在调用目标函数时,实际上会先执行装饰器函数内部的逻辑,然后再执行目标函数本身的逻辑。 总结来说,Python decorators是一种用于修饰函数的语法结构,可以通过装饰器函数在不修改原始函数代码的情况下增强函数功能。它可以通过Python内置的装饰器语法或第三方库来实现。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Python Decorator](https://blog.csdn.net/weixin_30951231/article/details/96490117)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [Python系列之装饰器(decorator)](https://blog.csdn.net/ikxyang/article/details/121995824)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值