Python装饰器3-funtools.wraps与property装饰器

简介: funtools.wraps装饰器、property装饰器、多装饰器的执行顺序

一、funtools.wraps装饰器

1.未使用wraps装饰器

Python装饰器在装饰其他函数的的时候,被装饰后的函数的函数名等属性会发生改变。例如:

defwrapper(func):
definner(*args, **kwargs):
"""这是装饰器的文档字符串"""returnfunc(*args, **kwargs)
returninner@wrapperdefbuying(self):
"""这是被装饰函数的文档字符串"""print(f"商品: {self.goods}, 重量: {self.weight}, 价格: {self.price}")
print(buying.__name__)
print(buying.__doc__)
'''inner这是装饰器的文档字符串'''

运行结果如下:

此时,被wrapper装饰器装饰的函数buying,函数名称已经变为了inner,文档字符串也变成了inner函数的文档字符串。

2.使用了wraps装饰器

为了避免这种情况的发生,Python的functools包中提供了一个叫wraps的装饰器来消除这样的副作用。在定义装饰器的时候,可以在装饰器的内函数之前加上functools的wraps,这样它就能保留被装饰函数的名称和函数属性。

fromfunctoolsimportwrapsdefwrapper(func):
@wraps(func)
definner(*args, **kwargs):
"""这是装饰器的文档字符串"""returnfunc(*args, **kwargs)
returninnerprint(buying.__name__)
print(buying.__doc__)

运行结果如下:

内函数inner在被functools.wraps装饰后,此时再装饰其他函数时,被装饰函数的函数名、文档字符串等函数属性就不会再受到影响。

二、property装饰器

@property是python的一种装饰器,是用来修饰方法的,它能够将方法转换为相同名称的只读属性,可以与所定义的属性配合使用,这样可以防止属性被修改;另外,@property装饰器也可以用来创建只读属性。

注意事项:

  • 调用不带property的方法时,需使用正常的方法调用方式,方法后面需要加();
  • 调用带property的方法时,方法后面不需要加();

1.将方法转换为属性

classProperty(object):
def__init__(self):
self.name="test_property"defwithout_property(self):
return"without_property"@propertydefwith_property(self):
return"with property"ppt=Property()
print(ppt.without_property())
print(ppt.with_property)
print(ppt.name)
'''运行结果:without_propertywith propertytest_property'''

通过运行结果可以看出,with_property在被@property装饰器装饰后,已经变成了Property类中的一个属性,被调用时可以直接通过‘对象名.属性名’进行调用,后面不必再带上括号。

2.创建只读属性

用@property装饰器将phone_number函数转换为属性,函数内返回私有属性self.__phone_number, 用户进行属性调用的时候,直接调用phone_number即可,而不用知道属性名__phone_number,因此用户无法更改属性,从而达到了保护类中属性的目的。

classProperty(object):
def__init__(self):
self.name="test_property"self.__phone_number=15252188888@propertydefphone_number(self):
returnself.__phone_numberprint(ppt.phone_number)
'''15252188888'''

3.设置和获取属性值

1)通过函数设置和获取属性值

# 通过函数设置属性值classSetter(object):
defget_score(self):
returnself._scoredefset_score(self, value):
ifnotisinstance(value, int):
raiseValueError("value must be integer!")
ifvalue<0orvalue>100:
raiseValueError("value must between 0~100~")
self._score=valuesetter=Setter()
setter.set_score(88)  # 通过set_score()方法设置属性值print(setter.get_score())  # 通过get_score()方法获取属性值'''88'''

2)通过@property设置和获取属性值

如下,在SetterAttribute类中定义一个score方法,通过@property装饰器装饰器,使其变为了属性;此时的score作为一个属性存在,故第二个score方法也是一个属性,通过@score.setter装饰后,传入的value会作为score的属性值。所以在SetterAttribute实例化后,sa.score既可以设置属性值,也可以读取属性值。但需要先传入score的属性值,此时才能存在score这个属性,才能获取到其属性值。

classSetterAttribute(object):
# 通过@property装饰器将score()方法转换为属性@propertydefscore(self):
returnself._score# 通过@score.setter设置score的属性值@score.setterdefscore(self, value):
ifnotisinstance(value, int):
raiseValueError("value must be integer!")
ifvalue<0orvalue>100:
raiseValueError("value must between 0~100~")
self._score=valuesa=SetterAttribute()
sa.score=99print(sa.score)
'''99'''

三、多装饰器的执行顺序

一个函数可以同时被多个装饰器装饰,它的执行顺序是从里到外,最先调用最里层的装饰器,最后调用最外层的装饰器。

# 多个装饰器执行顺序defdecorator_a(func):
print('Get in A')
definner_a(*args, **kwargs):
print('Get in inner_a')
returnfunc(*args, **kwargs)
returninner_adefdecorator_b(func):
print('Get in B')
definner_b(*args, **kwargs):
print('Get in inner_b')
returnfunc(*args, **kwargs)
returninner_b@decorator_b@decorator_adeff(x):
print('fun a')
returnx*2f(2)
'''运行结果:Get in AGet in BGet in inner_bGet in inner_afun a'''

执行过程分析:

  1. 执行f()函数会先调用最里层的装饰器@decorator_a,再调用最外层的装饰器@decorator_b;
  2. 执行@decorator_a时,会先执行语句print('Get in A')打印得到'Get in A',接着得到返回值inner_a函数,由于只是接收了这个函数、并没有调用它,因此不会执行inner_a函数的内部逻辑;
  3. 接着会执行装饰器@decorator_b的逻辑,打印‘Get in B’,执行decorator_b的时候会得到返回值函数inner_b;
  4. 用f来接收inner_b函数,调用f(),也就等于调用了inner_b(),f=decorator_b(decorator_a(f))、f()=inner_b(),从而执行inner_b的内容:打印'Get in inner_b';
  5. 执行完inner_b函数的内容会再继续执行inner_a函数的内容:打印'Get in inner_a',最后再返回func(*args, **kwargs),也就是执行f(2),打印'fun a'。

小结

1.装饰器在装饰其他函数的的时候,被装饰后的函数的函数名等属性会随着装饰器而发生改变,可以通过functools.wraps装饰内函数inner,从而避免此类情况的产生。

2.@property是python的一种装饰器,它既可以将类中的方法变为属性,也可以设置只读属性。

3.一个函数可以同时被多个装饰器装饰,它的执行顺序是从里到外,最先调用最里层的装饰器,最后调用最外层的装饰器。

相关文章
|
17天前
|
开发者 Python
探索Python中的装饰器:从基础到高级应用
本文将带你深入了解Python中的装饰器,这一强大而灵活的工具。我们将一起探讨装饰器的基本概念,它们如何工作,以及如何使用它们来增强函数和类的功能,同时不改变其核心逻辑。通过具体代码示例,我们将展示装饰器的创建和使用,并探索一些高级应用,比如装饰器堆栈和装饰带参数的装饰器。无论你是初学者还是有经验的开发者,这篇文章都将为你提供新的视角,帮助你更有效地使用装饰器来简化和优化你的代码。
|
18天前
|
测试技术 数据安全/隐私保护 开发者
探索Python中的装饰器:从基础到高级应用
装饰器在Python中是一个强大且令人兴奋的功能,它允许开发者在不修改原有函数代码的前提下增加额外的功能。本文将通过具体代码示例,带领读者从装饰器的基础概念入手,逐步深入到高级用法,如带参数的装饰器和装饰器嵌套等。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的见解和技巧。
|
18天前
|
开发框架 数据建模 中间件
Python中的装饰器:简化代码,增强功能
在Python的世界里,装饰器是那些静悄悄的幕后英雄。它们不张扬,却能默默地为函数或类增添强大的功能。本文将带你了解装饰器的魅力所在,从基础概念到实际应用,我们一步步揭开装饰器的神秘面纱。准备好了吗?让我们开始这段简洁而富有启发性的旅程吧!
26 6
|
6天前
|
缓存 数据安全/隐私保护 Python
python装饰器底层原理
Python装饰器是一个强大的工具,可以在不修改原始函数代码的情况下,动态地增加功能。理解装饰器的底层原理,包括函数是对象、闭包和高阶函数,可以帮助我们更好地使用和编写装饰器。无论是用于日志记录、权限验证还是缓存,装饰器都可以显著提高代码的可维护性和复用性。
20 5
|
16天前
|
测试技术 开发者 Python
探索Python中的装饰器:从入门到实践
装饰器,在Python中是一块强大的语法糖,它允许我们在不修改原函数代码的情况下增加额外的功能。本文将通过简单易懂的语言和实例,带你一步步了解装饰器的基本概念、使用方法以及如何自定义装饰器。我们还将探讨装饰器在实战中的应用,让你能够在实际编程中灵活运用这一技术。
36 7
|
16天前
|
Python
探索Python中的装饰器:简化代码,增强功能
在Python的世界里,装饰器就像是给函数穿上了一件神奇的外套,让它们拥有了超能力。本文将通过浅显易懂的语言和生动的比喻,带你了解装饰器的基本概念、使用方法以及它们如何让你的代码变得更加简洁高效。让我们一起揭开装饰器的神秘面纱,看看它是如何在不改变函数核心逻辑的情况下,为函数增添新功能的吧!
|
16天前
|
程序员 测试技术 数据安全/隐私保护
深入理解Python装饰器:提升代码重用与可读性
本文旨在为中高级Python开发者提供一份关于装饰器的深度解析。通过探讨装饰器的基本原理、类型以及在实际项目中的应用案例,帮助读者更好地理解并运用这一强大的语言特性。不同于常规摘要,本文将以一个实际的软件开发场景引入,逐步揭示装饰器如何优化代码结构,提高开发效率和代码质量。
42 6
|
16天前
|
存储 缓存 Python
Python中的装饰器深度解析与实践
在Python的世界里,装饰器如同一位神秘的魔法师,它拥有改变函数行为的能力。本文将揭开装饰器的神秘面纱,通过直观的代码示例,引导你理解其工作原理,并掌握如何在实际项目中灵活运用这一强大的工具。从基础到进阶,我们将一起探索装饰器的魅力所在。
|
16天前
|
测试技术 开发者 Python
深入理解Python装饰器:从基础到高级应用
本文旨在为读者提供一个全面的Python装饰器指南,从其基本概念讲起,逐步深入探讨其高级应用。我们将通过实例解析装饰器的工作原理,并展示如何利用它们来增强函数功能、控制程序流程以及实现代码的模块化。无论你是Python初学者还是经验丰富的开发者,本文都将为你提供宝贵的见解和实用的技巧,帮助你更好地掌握这一强大的语言特性。
29 4
|
18天前
|
开发者 Python
Python中的装饰器:从入门到实践
本文将深入探讨Python的装饰器,这一强大工具允许开发者在不修改现有函数代码的情况下增加额外的功能。我们将通过实例学习如何创建和应用装饰器,并探索它们背后的原理和高级用法。
34 5
下一篇
DataWorks