You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This discussion was converted from issue #21 on June 09, 2023 03:08.
Heading
Bold
Italic
Quote
Code
Link
Numbered list
Unordered list
Task list
Attach files
Mention
Reference
Menu
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
-
保存元数据
元数据(MetaData)是关于数据的数据,是用来描述数据信息。
查看这些元数据的函数是
dir(func)
:执行结果:
很显然元数据的数量与函数的复杂程度无关。
其中有几个重要的元数据:
在使用装饰器时,闭包默认不会保存原函数的元数据:
执行结果:
很显然原函数的
__name__
为 func,__doc__
为 func test,但经过装饰后已经被修改为装饰器内部函数的元数据。要使函数被装饰后仍保留原来的元数据可以使用以下两种方法定义装饰器:
两者取其一即可,装饰后重新执行刚才的函数:
带参数的装饰器
除了接收被装饰函数的参数以外,装饰器本身也可以传入参数,下面的例子是利用装饰器参数对被装饰函数接收的参数类型进行判断:
执行结果:
在装饰器内部已经对原函数参数执行判断并抛出异常。
属性可修改的装饰器
装饰器内部的参数影响装饰效果,可以在装饰器内部定义一个函数用于修改这个参数,这个函数可以看作被装饰函数的内置方法使用。
下面的例子是定义一个计时装饰器,当被装饰函数运行超过超时时间则输出日志(而这个超时时间是可以动态修改的):
第一次执行时函数运行需要 1 秒,超时时间为 2 秒,所以没有日志输出;
第二次执行时函数运行同为 1 秒,但超时时间改为 0.5 秒,所以有日志输出。
类的装饰器
除了函数以外,类也可以使用装饰器,其中最典型的应用是实现设计模式中的单例模式(同时也是装饰器模式):
执行结果:
虽然两次创建了 Student 对象,但执行的效果却是同一个 Student 对象,因为根据闭包的特性,函数执行完毕其内部的 instances 字典仍然保留在内存中,所以下次调用 Student 类实例化时会从 instances 取用。
递归与缓存
在 Python 中使用程序计算 Fibonacci 数列只需要一行代码:
但这种方式计算效率不是一般的低(我家电脑 i5-6200U + 8G DDR4 计算到 40 项左右就已经很吃力了......),缺点在于求任意一项都需要前面两项的值,充斥着大量的重复计算(例如计算第 5 项需要第 3 和第 4 项,计算第 4 项需要第 2 和第 3 项的值,光是这两步第 3 项就被算了两次了 = =)。
如果在计算的同时把中间结果保留到缓存中,下次直接从缓存获取就不需要重新计算了,测试:
之前已经说过因为闭包的特性 cache 里面的元素会一直保存在内存中,所以下次递归时就能先尝试从 cache 中取值,就能大幅度提高效率:
执行结果:
装饰器的用法灵活多变(例如还可以把类的实例方法作为装饰器函数,此时在被装饰函数中就可以持有实例对象,便于修改实例的属性、拓展功能),在这里无法一一列出,更多细节和有趣的用法还需要在日常开发中发现和积累。
Beta Was this translation helpful? Give feedback.
All reactions