python基础语法13-装饰器

Python 装饰器详解

装饰器(Decorator)是 Python 中的一种强大且灵活的功能,它允许在不修改原始函数或类代码的前提下,向其添加额外的功能。装饰器本质上是一个函数,它接受一个函数或类作为参数,并返回一个增强版的函数或类。本文将详细介绍装饰器的概念、使用方式,以及如何创建和应用函数装饰器和类装饰器。


1. 函数装饰器(Function Decorators)

函数装饰器是最常见的一种装饰器,它允许我们在不修改函数代码的情况下,给函数增加额外的功能。

1.1 基本语法

一个装饰器函数接受一个函数作为参数,并返回一个增强版的函数。装饰器通常通过 @decorator_name 的语法应用于函数。

装饰器的基本示例
def my_decorator(func):
    def wrapper():
        print("Before function call")
        func()
        print("After function call")
    return wrapper

# 使用装饰器
@my_decorator
def say_hello():
    print("Hello, World!")

say_hello()

输出:

Before function call
Hello, World!
After function call

在这个例子中,my_decorator 是一个装饰器,它在调用 say_hello() 之前和之后分别打印一些信息。

1.2 带参数的装饰器

如果装饰器需要处理有参数的函数,我们可以通过修改 wrapper 函数来实现这一点。装饰器可以接受任意数量的位置和关键字参数,并将它们传递给原始函数。

def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("Before function call")
        result = func(*args, **kwargs)
        print("After function call")
        return result
    return wrapper

@my_decorator
def greet(name):
    print(f"Hello, {name}!")

greet("Alice")

输出:

Before function call
Hello, Alice!
After function call

1.3 functools.wraps 的使用

当我们使用装饰器时,原函数的一些元数据(如文档字符串、函数名称等)会丢失。为了保留这些信息,我们可以使用 functools.wraps 来确保装饰器返回的 wrapper 函数继承原始函数的元数据。

import functools

def my_decorator(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print("Before function call")
        result = func(*args, **kwargs)
        print("After function call")
        return result
    return wrapper

@my_decorator
def greet(name):
    """Greets the person by name."""
    print(f"Hello, {name}!")

print(greet.__name__)  # 输出: greet
print(greet.__doc__)   # 输出: Greets the person by name.

通过使用 @functools.wraps(func),我们确保了装饰器不会丢失原始函数的名称和文档字符串。


2. 类装饰器(Class Decorators)

除了函数装饰器,Python 还支持类装饰器,它允许我们对类进行修改或扩展。类装饰器的工作原理与函数装饰器相似,不同的是它们处理的是类,而不是函数。

2.1 基本语法

类装饰器是一个函数,接受一个类作为参数,并返回一个修改后的类。类装饰器可以用来增强类的功能或修改其行为。

类装饰器示例
def class_decorator(cls):
    class NewClass(cls):
        def greet(self):
            return f"Hello, {self.name}!"
    return NewClass

@class_decorator
class Person:
    def __init__(self, name):
        self.name = name

p = Person("Alice")
print(p.greet())  # 输出: Hello, Alice!

在这个例子中,class_decorator 装饰器接受 Person 类,返回一个新的类 NewClass,它在原始类的基础上添加了一个 greet 方法。

2.2 修改类的属性和方法

类装饰器不仅可以增加新方法,还可以修改现有的方法或属性。下面的示例展示了如何通过装饰器修改类的构造函数。

def add_age(cls):
    original_init = cls.__init__

    def new_init(self, name, age):
        original_init(self, name)
        self.age = age

    cls.__init__ = new_init
    return cls

@add_age
class Person:
    def __init__(self, name):
        self.name = name

p = Person("Bob", 30)
print(p.name)  # 输出: Bob
print(p.age)   # 输出: 30

在这个例子中,add_age 装饰器修改了 Person 类的构造函数,添加了一个 age 属性。


3. 装饰器的实际应用

装饰器在实际开发中有许多应用场景,例如:

  • 日志记录:记录函数的调用日志。
  • 权限控制:检查用户是否有权限执行某些操作。
  • 性能分析:计算函数执行的时间。
  • 缓存:缓存函数的返回结果,提高效率。

3.1 日志装饰器

def log_function_call(func):
    def wrapper(*args, **kwargs):
        print(f"Calling {func.__name__} with arguments {args} and {kwargs}")
        return func(*args, **kwargs)
    return wrapper

@log_function_call
def add(a, b):
    return a + b

add(2, 3)

输出:

Calling add with arguments (2, 3) and {}

3.2 性能分析装饰器

import time

def timer(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f"Function {func.__name__} executed in {end - start:.4f} seconds")
        return result
    return wrapper

@timer
def slow_function():
    time.sleep(2)

slow_function()

输出:

Function slow_function executed in 2.0001 seconds

4. 总结

装饰器是 Python 中非常强大且灵活的功能,能够动态地修改函数或类的行为。它广泛应用于日志记录、权限验证、性能分析、缓存等场景。我们可以通过简单的 @decorator 语法来实现装饰器,使用装饰器时需注意保留函数的元数据,可以借助 functools.wraps 来实现。类装饰器与函数装饰器类似,允许我们动态地修改类的行为和属性。

掌握装饰器的使用,不仅能让你的代码更具灵活性,还能提高代码的可读性和可维护性。

### Python 面向对象编程基础语法 #### 创建类与实例化对象 Python 是一门从设计之初就支持面向对象特性的语言,因此创建类和对象非常简单。定义一个新类型的语句即 `class` 关键字[^1]。 ```python class Dog: """A simple example class""" def __init__(self, name): # 构造函数 self.name = name def bark(self): return f"{self.name} says woof!" ``` 在此例子中,`Dog` 类有一个构造函数 `__init__()` 和一个名为 `bark` 的方法。当创建一个新的 `Dog` 对象时,会自动调用该构造函数来初始化对象属性[^2]。 #### 继承机制 子类可以继承父类的功能并扩展或修改其行为。这允许代码重用以及建立清晰的关系层次结构。 ```python class Animal: def speak(self): raise NotImplementedError("Subclasses must implement this method") class Cat(Animal): def speak(self): return "Meow" ``` 这里展示了如何让 `Cat` 类继承自 `Animal` 基础类,并实现了自己的版本的 `speak` 方法。 #### 不同类型的方法 在 Python 中有三种主要类型的方法:实例方法、类方法和静态方法。每种都有不同的用途: - **实例方法**: 接受第一个参数作为当前实例(`self`)。 - **类方法**: 使用装饰器 `@classmethod` 定义;接收的第一个参数是代表类本身的 `cls` 参数而不是具体的实例。 - **静态方法**: 利用 `@staticmethod` 装饰符声明;既不接受 `self` 也不接受 `cls` 参数,它们就像普通的函数一样工作,只是逻辑上属于某个特定类别[^3]。 ```python from datetime import date class Person: def __init__(self, name, age): self.name = name self.age = age @classmethod def from_birth_year(cls, name, birthYear): return cls(name, date.today().year - birthYear) @staticmethod def is_adult(age): return age >= 18 ``` 在这个例子中,`Person.from_birth_year` 是一个类方法,它提供了一种替代的方式来构建 `Person` 实例。而 `is_adult` 则是一个静态方法,用于判断给定年龄是否成年。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值