%
格式化print("My name is %s and I am %d years old." % (name, age))
str.format()
print("My name is {} and I am {} years old.".format(name, age))
print(f"My name is {name} and I am {age} years old.")
print(f"In 10 years, I will be {age + 10} years old.")
==检查两个变量存储的数据是否相同,调用对象的 __eq__()
方法(可被重载)
is
(身份运算符)比较两个对象的内存地址是否相同(即是否是同一个对象)
一个可调用对象(通常是函数或类),它接受一个函数作为参数,并返回一个新的函数
def repeat(num_times):
def decorator_repeat(func):
def wrapper(*args, **kwargs):
for _ in range(num_times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator_repeat
@repeat(num_times=3)
def greet(name):
print(f"Hello {name}")
greet("Alice")
输出:
Hello Alice
Hello Alice
Hello Alice
装饰器也可以是一个类:
class CountCalls:
def __init__(self, func):
self.func = func
self.num_calls = 0
def __call__(self, *args, **kwargs):
self.num_calls += 1
print(f"调用次数: {self.num_calls}")
return self.func(*args, **kwargs)
@CountCalls
def say_hello():
print("Hello!")
say_hello()
say_hello()
输出:
调用次数: 1
Hello!
调用次数: 2
Hello!
Python提供了一些内置装饰器:
@property
- 将方法转换为属性@classmethod
- 定义类方法@staticmethod
- 定义静态方法当多个装饰器应用于同一个函数时,它们是从下往上执行的:
@decorator1
@decorator2
@decorator3
def func():
pass
等同于:func = decorator1(decorator2(decorator3(func)))
使用装饰器后,原函数的__name__
、__doc__
等元信息会被覆盖。可以使用functools.wraps
来保留:
from functools import wraps
def my_decorator(func):
@wraps(func) #将原始函数的元信息复制到包装函数上,这样装饰后的函数会保留原始函数的名称、文档字符串等元数据。
def wrapper(*args, **kwargs):
"""Wrapper docstring"""
print("装饰器操作")
return func(*args, **kwargs)
return wrapper
@my_decorator
def say_hello():
"""原始函数文档"""
print("Hello!")
print(say_hello.__name__) # 输出: say_hello
print(say_hello.__doc__) # 输出: 原始函数文档
装饰器是Python中非常强大且灵活的特性,合理使用可以大大提高代码的可重用性和可维护性。
指 一个函数 能够 记住并访问其定义时的作用域,即使该函数在定义的作用域之外执行。闭包允许函数访问其创建时的环境变量,即使这些变量在函数执行时已经不在当前作用域中。
闭包通常由 嵌套函数 构成:
outer
)定义了一个变量(x
)。inner
)引用了这个变量(x
)。return inner
)。def outer(x): # 1. 外层函数定义变量 x
def inner(y): # 2. 内层函数引用 x
return x + y # 3. 内层函数可以访问 x
return inner # 4. 返回内层函数
closure = outer(10) # 调用 outer,返回 inner,此时 x=10
print(closure(5)) # 输出 15(10 + 5)
解释:
outer(10)
执行后返回 inner
,此时 x=10
被闭包记住。outer
已经执行完毕,inner
仍然可以访问 x
。closure(5)
相当于 inner(5)
,计算 10 + 5 = 15
。def counter():
count = 0
def increment():
nonlocal count # 声明 count 不是局部变量
count += 1
return count
return increment
c = counter()
print(c()) # 1
print(c()) # 2
print(c()) # 3
count 的初始化(count = 0)只在 counter() 被调用时执行一次(即 c = counter() 时)。
之后每次调用 c() 都是调用 increment,而 increment 不会重新初始化 count,它只是修改闭包中已经存在的 count。
闭包机制使得 count 的状态在函数调用之间得以保留。
解释:
counter()
返回 increment
,count
被闭包记住。c()
,count
都会递增,而不是重新初始化。def cache(func):
memo = {}
def wrapper(n):
if n not in memo:
memo[n] = func(n)
return memo[n]
return wrapper
@cache
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(10)) # 55(缓存优化,避免重复计算)
解释:
cache
是一个装饰器,它用闭包记住 memo
字典。fibonacci
的计算结果会被缓存,避免重复计算。闭包可以实现类似 类的私有变量 的功能:
# 用闭包实现类似类的功能
def person(name):
age = 0
def get_age():
return age
def set_age(new_age):
nonlocal age
age = new_age
return get_age, set_age
get_age, set_age = person("Alice")
set_age(25)
print(get_age()) # 25
对比类实现:
class Person:
def __init__(self, name):
self.name = name
self._age = 0
def get_age(self):
return self._age
def set_age(self, new_age):
self._age = new_age
p = Person("Alice")
p.set_age(25)
print(p.get_age()) # 25
区别:
nonlocal
关键字**:如果要在闭包内修改外部变量,必须用 nonlocal
声明(Python 3+)。特性 | 闭包 | 类 |
---|---|---|
数据封装 | ✅(通过闭包变量) | ✅(通过 self.xxx ) |
状态保持 | ✅(变量不会被销毁) | ✅(实例变量) |
适用场景 | 简单逻辑、函数式编程 | 复杂逻辑、面向对象 |
性能 | 更轻量级 | 稍重(需要实例化) |
闭包的核心思想:函数 + 环境变量,让函数可以记住定义时的作用域。