2024年最新一篇文章掌握 Python 中的装饰器(1),2024年最新Python常见面试题

最后

不知道你们用的什么环境,我一般都是用的Python3.6环境和pycharm解释器,没有软件,或者没有资料,没人解答问题,都可以免费领取(包括今天的代码),过几天我还会做个视频教程出来,有需要也可以领取~

给大家准备的学习资料包括但不限于:

Python 环境、pycharm编辑器/永久激活/翻译插件

python 零基础视频教程

Python 界面开发实战教程

Python 爬虫实战教程

Python 数据分析实战教程

python 游戏开发实战教程

Python 电子书100本

Python 学习路线规划

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

‘’’

def sleeps(seconds):

print(’ sleeps begin:')

time.sleep(seconds)

print(’ sleep %d seconds.\n sleeps over.'%seconds)

return seconds

sleeps = timethis(sleeps)

@语法只是装饰器调用的便捷方式:将被装饰函数sleeps作为参数传给装饰器函数,再将装饰器返回值重新绑定到原sleeps变量上。理解了装饰器的使用方法,我们一步步来理解其定义过程。

二、装饰器是一个函数
  • 根据上文timethis装饰器的定义,它毫无疑问是一个函数。名称是timethis,参数是func,返回值是inner。

  • 根据 sleeps = timethis(sleeps) ,可知参数func是被装饰的函数sleeps。

  • 根据 return inner ,可知返回值inner是嵌套定义在装饰器中的一个函数。

综上,装饰器本身是一个函数,参数也是函数,返回值还是函数。之所以函数可以作为装饰器的参数和返回值,是因为函数在Python中是一等对象。

三、函数是一等对象

编程语言中的一等对象定义为:运行时创建,可赋值给变量或数据结构,可作为参数传递,可作为返回值返回。

Python中整数、字符串、字典类型是一等对象,具备以上四点特性,理解起来没有任何困难。但函数作为一等对象,需要我们举例说明。

3.1运行时创建

在Python控制台中定义一个函数reverse,实现对word这个序列类型的反转。

def reverse(word):

… return word[::-1]

reverse

<function reverse at 0x027A4C40>

reverse(‘hello world!’)

‘!dlrow olleh’

因其是在控制台会话中定义的,符合第一条运行时创建的要求。

3.2可赋值给变量或数据结构

可以将reverse函数赋值给另外的变量,再调用。如

backward=reverse

backward(‘hello world!’)

‘!dlrow olleh’

输出结果同上。所以函数符合第二条可赋值给变量的要求。

3.3函数作为参数传递

当使用高阶函数,如sorted时,高阶函数的key关键字接受一个单参数函数,对每个元素进行迭代,依照这个key函数作为排序依 据。

cars = [‘Honda’,‘toyota’,‘hyundai’,‘byd’,‘ford’,‘suzuki’,‘peuguot’,‘nissan’,‘citroen’,‘kia’,‘vw’,‘gm’,‘audi’,‘bmw’,‘beniz’]

print(sorted(cars,key=reverse))

输出

[‘Honda’, ‘kia’, ‘toyota’, ‘ford’, ‘byd’, ‘hyundai’, ‘audi’, ‘suzuki’, ‘gm’, ‘nissan’, ‘citroen’, ‘peuguot’, ‘bmw’, ‘vw’, ‘beniz’]

此时所有的car是依照结尾字符的先后排序的。reverse作为参数传入高阶函数。符合第三条函数可作为参数传递。

3.4函数作为返回值返回

为验证第四点,我们将reverse函数包装起来,让他在一个函数中返回。

‘’’

遇到问题没人解答?小编创建了一个Python学习交流QQ群:531509025

寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!

‘’’

def cmpLib():

def reverse(word):

return word[::-1]

return reverse

我们仍用上例中排序函数,key参数必须为一个单参函数。而函数backward的执行结果是一个函数,所以我们把它的调用结果作为key值。

print(sorted(cars,key=cmpLib())

结果

[‘Honda’, ‘kia’, ‘toyota’, ‘ford’, ‘byd’, ‘hyundai’, ‘audi’, ‘suzuki’, ‘gm’, ‘nissan’, ‘citroen’, ‘peuguot’, ‘bmw’, ‘vw’, ‘beniz’]

可见,结果正确。所以第四条函数可作为结果返回也成立。

综上,函数是一等对象。除了可调用性之外,函数和其他如字典、字符串、列表对象并没有本质区别。

理解装饰器我们需要的是函数一等性定义的后三点:函数可赋值,可作参数,可作返回结果。

我们再来分析与@timethis等价的sleeps = timethis(sleeps)语句:右侧函数先调用。timethis是装饰器函数,被装饰函数sleeps作为参数传入装饰器中;返回结果是装饰器中定义的inner函数;右侧计算结果重新赋值给变量sleeps。完美符合以上三点。也就是说sleeps函数实际上已经指向inner函数了。

理解了函数一等性,就理解了函数可以作为参数传递和作为结果返回。那么新定义的内部函数inner为什么采用 def inner(*args,**kwargs): 的参数命名形式呢?

四、可接受任意数量参数的函数

当我们定义不特定数量参数的函数时,可使用*开头的参数作可接受任意数量位置参数的参数,此时该参数作为一个元组使用。

同理,可以使用**开头的关键字参数接受任意数量的关键词参数,此时该参数作为一个字典使用。

如果同时接受任意数量的位置参数和关键字参数,那么只要联合使用***就可以。而 def inner(*args,**kwargs): 是约定俗成的固定写法。来看个例子就可以理解这种写法了。

def star(*args,**kwargs):

print(args,kwargs)

star(1,2,3)

star(4,5,name=‘zhang’)

star(7,name=‘lisi’,gender=‘m’)

输出结果:

(1, 2, 3) {}

(4, 5) {‘name’: ‘zhang’}

(7,) {‘name’: ‘lisi’, ‘gender’: ‘m’}

args搜集所有位置参数,kwargs搜集所有关键字参数。这个技术应用在inner函数上,恰如其分:当我们调用@语法时,只有被装饰函数sleeps作为func参数传入timethis装饰器中,sleeps的参数并没有传入装饰器函数中。装饰器不知道sleeps函数的参数数量和具体值,若在其中func调用参数,则相当于调用不特定名称和数量的参数。

接受任意参数的inner函数,进一步将参数传给在其中执行的func函数。func函数是被装饰的原函数sleeps,传给inner函数的*args,**kwargs参数,直接传递给了被装饰函数func。这样就实现了func(*args,**kwargs)相当于sleeps(3)的效果。

在完成调用原函数的基础上,如何添加计时功能的呢?

五、增强被装饰函数的行为

以下语句实现了统计函数执行时间的功能 ,当然也可以实现比如日志记录,建立撤销环境之类的功能,大同小异。

print(‘start timer:’)

start = time.time()

result = func(*args,**kwargs)

end = time.time()

print(‘end timer:%fs.’%(end - start))

很简单,就是在调用原函数的语句 result = func(*args,**kwargs)前后,包裹上相应的计时功能。

此处func参数得以在inner内部访问到,还牵涉到一个不太好理解的话题——闭包,而理解闭包需要先弄清python中变量的作用域规则。

六、变量作用域

在这里插入图片描述

感谢每一个认真阅读我文章的人,看着粉丝一路的上涨和关注,礼尚往来总是要有的:

① 2000多本Python电子书(主流和经典的书籍应该都有了)

② Python标准库资料(最全中文版)

③ 项目源码(四五十个有趣且经典的练手项目及源码)

④ Python基础入门、爬虫、web开发、大数据分析方面的视频(适合小白学习)

⑤ Python学习路线图(告别不入流的学习)

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 20
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一些常见Python 装饰器面试问题及其回答: 1. 什么是装饰器装饰器Python 一种高级的语法结构,它允许在不修改原函数代码的情况下,对函数进行增强或修改。装饰器本质上是一个函数,它接收一个函数作为参数,并返回一个函数。 2. 装饰器有哪些应用场景? 装饰器可以用于实现各种功能,如: - 日志记录:记录函数的调用时间、输入参数、输出结果等信息。 - 计时器:统计函数的运行时间。 - 缓存:缓存函数的输出结果,避免重复计算。 - 权限验证:验证用户是否有权调用函数。 - 接口限流:限制函数的调用频率。 3. 装饰器的语法是什么? 装饰器的语法如下: ```python @decorator def func(): pass ``` 其,`decorator` 是装饰器函数,`func` 是被装饰函数。装饰器函数可以在函数执行前后对函数进行修改或增强。如果需要传递参数,可以使用带参数的装饰器,如: ```python @decorator(arg1, arg2, ...) def func(): pass ``` 4. 装饰器的执行顺序是怎样的? 多个装饰器会按照从下往上的顺序依次执行,即先执行最外层的装饰器,然后执行内层的装饰器,最后执行被装饰的函数。例如: ```python @a @b @c def func(): pass ``` 执行顺序为 `func = a(b(c(func)))`。 5. 装饰器如何传递参数? 装饰器可以使用带参数的形式,例如: ```python def my_decorator(arg1, arg2): def decorator(func): def wrapper(*args, **kwargs): # 在这里对函数进行增强或修改 return func(*args, **kwargs) return wrapper return decorator @my_decorator(arg1, arg2) def my_func(): pass ``` 在这个例子,`my_decorator` 是一个带参数的装饰器,它接收两个参数 `arg1` 和 `arg2`。`decorator` 是一个不带参数的装饰器函数,它接收一个函数作为参数,并返回一个函数。`wrapper` 是被返回的函数,它接收任意数量的位置参数和关键字参数,并在其对函数进行增强或修改。最后,使用 `@my_decorator(arg1, arg2)` 语法将装饰器应用到函数上。 6. 装饰器如何保留被装饰函数的元信息? 当使用装饰器时,有时候需要保留被装饰函数的元信息,例如函数名、文档字符串等。为了实现这个功能,可以使用 `functools.wraps` 装饰器,它可以将被装饰函数的元信息复制到装饰器函数。例如: ```python import functools def my_decorator(func): @functools.wraps(func) def wrapper(*args, **kwargs): # 在这里对函数进行增强或修改 return func(*args, **kwargs) return wrapper @my_decorator def my_func(): """这是一个示例函数""" pass ``` 在这个例子,使用 `@functools.wraps(func)` 语法将被装饰函数的元信息复制到 `wrapper` 函数。这样,当调用 `help(my_func)` 时,可以看到函数的文档字符串和函数名。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值