百独托管7500 紫田网络超高转化播放器收cps[推荐]速盾CDN 免实名免备防屏蔽阿里云 爆款特卖9.9元封顶提升alexa、IP流量7Q5团队
【腾讯云】中小企福利专场【腾讯云】多款产品1折起高防 随时退换 好耶数据小飞国外网赚带你月入万元炎黄网络4H4G10M 99每月
香港带宽CN2/美国站群优惠中客数据中心 服务器租用联盟系统移动广告平台 中易企业专场腾讯云服务器2.5折九九数据 工信部正规资质
腾讯云新用户大礼包代金券高价收cpa注册量高价展示【腾讯云】2核2G/9.93起租服务器找45互联 随时退换阿里云 短信服务 验证秒达

[其它内容] 如何在Python中高效使用装饰器提高代码复用性 [复制链接]
查看:104 | 回复:1

1477

主题

1656

帖子

9

积分

落伍者(一心一意)

Rank: 1

贡献
685
鲜花
0
注册时间
2016-6-22

落伍者落伍微信绑定落伍手机绑定

发表于 2024-8-16 16:59:41 | 显示全部楼层 |阅读模式 来自 中国江苏淮安
华科云商丑图1.jpg
在Python编程中,装饰器(Decorator)是一个非常强大的功能,它允许你在不修改函数或类的情况下,添加额外的功能或行为。装饰器可以用于很多场景,如记录日志、验证输入、性能计时、缓存结果等。通过合理使用装饰器,你可以大大提高代码的复用性和可维护性。本文将介绍如何高效使用装饰器,帮助你写出更简洁、易读且可复用的代码。

1. 什么是装饰器?

装饰器本质上是一个函数或类,它接受一个函数或类作为输入,并返回一个新的函数或类。这个新的函数或类通常是原始输入的增强版,具备了额外的功能。

一个最简单的装饰器例子如下:

```python

def simple_decorator(func):

  def wrapper():

      print("装饰器: 函数执行前")

      func()

      print("装饰器: 函数执行后")

  return wrapper

@simple_decorator

def my_function():

  print("原始函数")

my_function()

```

输出结果为:

```

装饰器: 函数执行前

原始函数

装饰器: 函数执行后

```

在这个例子中,`simple_decorator`装饰了`my_function`,在函数执行的前后添加了打印语句。

2. 装饰器的实际应用场景

装饰器的强大之处在于它可以广泛应用于各种场景,下面是几个常见的应用:

2.1 记录日志

记录函数的输入、输出和执行时间是开发中常见的需求。你可以使用装饰器来自动记录这些信息。

```python

import time

def log_execution(func):

  def wrapper(*args, **kwargs):

      start_time = time.time()

      result = func(*args, **kwargs)

      end_time = time.time()

      print(f"函数 {func.__name__} 执行时间: {end_time - start_time} 秒")

      print(f"函数 {func.__name__} 的输入参数: {args}, {kwargs}")

      print(f"函数 {func.__name__} 的返回值: {result}")

      return result

  return wrapper

@log_execution

def add(x, y):

  return x + y

add(3, 5)

```

2.2 输入验证

在函数执行前,使用装饰器验证输入的有效性,避免重复的验证代码。

```python

def validate_input(func):

  def wrapper(x, y):

      if not isinstance(x, (int, float)) or not isinstance(y, (int, float)):

          raise ValueError("输入必须是数字")

      return func(x, y)

  return wrapper

@validate_input

def add(x, y):

  return x + y

add(3, 'a')  # 将引发 ValueError

```

2.3 缓存结果

对于计算量较大的函数,可以使用装饰器缓存结果,以提高性能。

```python

from functools import lru_cache

@lru_cache(maxsize=None)

def fibonacci(n):

  if n < 2:

      return n

  return fibonacci(n - 1) + fibonacci(n - 2)

print(fibonacci(10))

print(fibonacci(20))

```

3. 编写通用的装饰器

为了提高代码复用性,装饰器应尽量编写得通用和灵活,能够适应不同的场景。

##### 3.1 使用 `*args` 和 `**kwargs`

通过`*args`和`**kwargs`,装饰器可以应用于任意函数,而不受参数数量和类型的限制。

```python

def universal_decorator(func):

  def wrapper(*args, **kwargs):

      print("执行前的通用操作")

      result = func(*args, **kwargs)

      print("执行后的通用操作")

      return result

  return wrapper

@universal_decorator

def some_function(a, b, c=1):

  print(f"函数体执行: {a}, {b}, {c}")

some_function(1, 2, c=3)

```

3.2 处理带参数的装饰器

有时你可能需要编写带参数的装饰器,这样可以更灵活地控制装饰器的行为。

```python

def repeat(times):

  def decorator(func):

      def wrapper(*args, **kwargs):

          for _ in range(times):

              result = func(*args, **kwargs)

          return result

      return wrapper

  return decorator

@repeat(3)

def greet(name):

  print(f"Hello, {name}!")

greet("Alice")

```

这个装饰器会让`greet`函数执行3次。

4. 装饰器的组合

多个装饰器可以组合在一起,为函数添加多个层次的功能。装饰器的执行顺序是从内到外,即最先定义的装饰器最后执行。

```python

def decorator1(func):

  def wrapper(*args, **kwargs):

      print("装饰器1: 前置操作")

      result = func(*args, **kwargs)

      print("装饰器1: 后置操作")

      return result

  return wrapper

def decorator2(func):

  def wrapper(*args, **kwargs):

      print("装饰器2: 前置操作")

      result = func(*args, **kwargs)

      print("装饰器2: 后置操作")

      return result

  return wrapper

@decorator1

@decorator2

def say_hello():

  print("Hello!")

say_hello()

```

输出结果为:

```

装饰器1: 前置操作

装饰器2: 前置操作

Hello!

装饰器2: 后置操作

装饰器1: 后置操作

```

5. 类装饰器

除了函数装饰器外,还可以编写类装饰器,它允许你装饰类中的所有方法或添加类级别的行为。

```python

def class_decorator(cls):

  class WrappedClass(cls):

      def method(self, *args, **kwargs):

          print("类装饰器: 方法执行前")

          result = super().method(*args, **kwargs)

          print("类装饰器: 方法执行后")

          return result

  return WrappedClass

@class_decorator

class MyClass:

  def method(self):

      print("原始方法")

obj = MyClass()

obj.method()

```

输出结果为:

```

类装饰器: 方法执行前

原始方法

类装饰器: 方法执行后

```

6. 使用 `functools.wraps` 保持函数元数据

在使用装饰器时,原函数的元数据(如函数名、文档字符串)可能会被装饰器覆盖。为了避免这种情况,可以使用`functools.wraps`来保留原函数的元数据。

```python

import functools

def simple_decorator(func):

  @functools.wraps(func)

  def wrapper(*args, **kwargs):

      print("执行装饰器")

      return func(*args, **kwargs)

  return wrapper

@simple_decorator

def my_function():

  """这是一个示例函数"""

  print("执行函数体")

print(my_function.__name__)  # 输出: my_function

print(my_function.__doc__)   # 输出: 这是一个示例函数

```

装饰器是Python中一个非常强大的工具,它能够在不修改原始代码的情况下,为函数或类添加额外的功能。通过合理使用装饰器,可以显著提高代码的复用性、可读性和可维护性。在编写装饰器时,应尽量保持其通用性,并使用`functools.wraps`来保留函数的元数据。装饰器不仅能应用于函数,还可以用于类,进一步增强代码的灵活性。无论是记录日志、验证输入、缓存结果,还是其他常见需求,装饰器都能帮助你以更加优雅和高效的方式实现功能。
企业专线拨号VPS动态IP派克斯ADSL本地拨号,联系QQ174629754
回复

使用道具 举报

372

主题

1万

帖子

647

积分

落伍者(一心一意)

Rank: 1

贡献
2388
鲜花
0
注册时间
2020-6-17

落伍手机绑定落伍者

发表于 2024-8-19 11:23:51 | 显示全部楼层 来自 中国河南开封
愿收录[url=http://www.ytllck.com/news/gongsi/]超声波流量计[/url]
[url=http://www.ytllck.com/products/]流量计厂家[/url]
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

论坛客服/商务合作/投诉举报:2171544 (QQ)
落伍者创建于2001/03/14,本站内容均为会员发表,并不代表落伍立场!
拒绝任何人以任何形式在本论坛发表与中华人民共和国法律相抵触的言论!
落伍官方微信:2030286 邮箱:(djfsys@gmail.com|tech@im286.com)
© 2001-2014

浙公网安备 33060302000191号

浙ICP备11034705号 BBS专项电子公告通信管[2010]226号

  落伍法律顾问: ITlaw-庄毅雄

手机版|找回帐号|不能发帖?|Archiver|落伍者

GMT+8, 2024-11-25 00:30 , Processed in 0.053620 second(s), 34 queries , Gzip On.

返回顶部