python和装饰器相关的问答题
以下是与 Python 装饰器相关的常见面试题,以及每个问题的答案和示例代码。
1. 什么是 Python 装饰器?它的作用是什么?
回答:
装饰器是一个高阶函数,它接受一个函数作为输入并返回一个新函数(或修改后的函数)。装饰器通常用于在不修改原函数代码的情况下,扩展或增强函数的功能。
示例代码:
def decorator(func):
def wrapper():
print("Before the function call")
func()
print("After the function call")
return wrapper
@decorator
def say_hello():
print("Hello!")
say_hello()
输出:
Before the function call
Hello!
After the function call
2. 如何为函数添加多个装饰器?执行顺序是什么?
回答:
多个装饰器可以堆叠在函数定义上,装饰器的执行顺序是从内到外(从离函数最近的装饰器开始)。
示例代码:
def decorator1(func):
def wrapper():
print("Decorator 1")
func()
return wrapper
def decorator2(func):
def wrapper():
print("Decorator 2")
func()
return wrapper
@decorator1
@decorator2
def say_hello():
print("Hello!")
say_hello()
输出:
Decorator 1
Decorator 2
Hello!
3. 如何向装饰器传递参数?
回答:
可以通过在装饰器外部再嵌套一层函数,将参数传递到装饰器内部。
示例代码:
def repeat(times):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(times):
func(*args, **kwargs)
return wrapper
return decorator
@repeat(3)
def say_hello():
print("Hello!")
say_hello()
输出:
Hello!
Hello!
Hello!
4. 如何保留被装饰函数的元信息?
回答:
使用 functools.wraps
来保留被装饰函数的元信息(如名称和文档字符串)。
示例代码:
from functools import wraps
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
print("Calling decorated function")
return func(*args, **kwargs)
return wrapper
@decorator
def say_hello():
"""This function says hello."""
print("Hello!")
print(say_hello.__name__) # 输出: say_hello
print(say_hello.__doc__) # 输出: This function says hello.
5. 如何创建一个类装饰器?
回答:
通过实现 __call__
方法的类可以用作装饰器。
示例代码:
class Decorator:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("Before the function call")
result = self.func(*args, **kwargs)
print("After the function call")
return result
@Decorator
def say_hello():
print("Hello!")
say_hello()
输出:
Before the function call
Hello!
After the function call
6. 什么是 functools.lru_cache
?
回答:
functools.lru_cache
是一个内置装饰器,用于缓存函数的返回值,从而提高性能。适用于纯函数。
示例代码:
from functools import lru_cache
@lru_cache(maxsize=3)
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(10)) # 55
7. 装饰器如何处理带有参数的函数?
回答:
通过使用 *args
和 **kwargs
,装饰器可以处理任意参数的函数。
示例代码:
def decorator(func):
def wrapper(*args, **kwargs):
print(f"Arguments: {args}, {kwargs}")
return func(*args, **kwargs)
return wrapper
@decorator
def greet(name, age):
print(f"Hello, {name}! You are {age} years old.")
greet("Alice", age=30)
输出:
Arguments: ('Alice',), {'age': 30}
Hello, Alice! You are 30 years old.
8. 如何创建一个可以作用于类方法的装饰器?
回答:
类方法的第一个参数是 self
,装饰器需要能够处理它。
示例代码:
def method_decorator(func):
def wrapper(self, *args, **kwargs):
print(f"Calling method {func.__name__}")
return func(self, *args, **kwargs)
return wrapper
class MyClass:
@method_decorator
def greet(self, name):
print(f"Hello, {name}!")
obj = MyClass()
obj.greet("Alice")
输出:
Calling method greet
Hello, Alice!
9. 装饰器能否装饰类?如何实现?
回答:
装饰器可以作用于类,通过返回一个修改后的类。
示例代码:
def class_decorator(cls):
class NewClass(cls):
def greet(self):
print("Decorated!")
super().greet()
return NewClass
@class_decorator
class MyClass:
def greet(self):
print("Hello!")
obj = MyClass()
obj.greet()
输出:
Decorated!
Hello!
10. 装饰器可以用于异步函数吗?如何实现?
回答:
可以为异步函数创建装饰器,但需要用 await
调用装饰函数。
示例代码:
import asyncio
def async_decorator(func):
async def wrapper(*args, **kwargs):
print("Before async function")
result = await func(*args, **kwargs)
print("After async function")
return result
return wrapper
@async_decorator
async def say_hello():
print("Hello, async world!")
asyncio.run(say_hello())
输出:
Before async function
Hello, async world!
After async function
总结
装饰器是 Python 面试中的高频考点,可以从以下方面准备:
- 装饰器的基础知识和使用场景。
- 处理带参数函数、多装饰器和类装饰器。
- 异步函数、元信息保留(
functools.wraps
)、缓存装饰器等高级应用。
如果有更多问题或需要更详细的解释,可以进一步探讨!