装饰器是Python中一种"化妆师",它能在不修改原函数代码的前提下,给函数动态添加新功能。
工作流程:
hello()
)。 场景 |
作用 |
生活类比 |
权限验证 |
检查用户是否登录再执行函数 |
进小区前刷卡(装饰器是门禁系统) |
日志记录 |
自动记录函数调用时间和参数 |
飞机黑匣子(自动记录飞行数据) |
性能统计 |
计算函数运行耗时 |
跑步时用手表计时 |
缓存结果 |
避免重复计算(如 ) |
备忘录(记下答案直接复用) |
def remind_call(func):
def wrapper():
print("【提醒】开始打电话...")
func() # 执行原打电话函数
print("【提醒】通话结束")
return wrapper
@remind_call
def call_friend():
print("正在和好友通话中...")
call_friend()
输出:
【提醒】开始打电话...
正在和好友通话中...
【提醒】通话结束
__call__
方法让类能像函数一样调用。help(func)
显示的是wrapper函数的信息。functools.wraps
装饰wrapper函数。@decorator1 # 最后执行
@decorator2 # 先执行
def func(): pass
@打包
后的商品功能不变,但多了运输保护。@穿装备
后角色攻击力提升,但角色代码未修改。一句话总结:装饰器是Python的"功能外挂",用@
符号轻松实现代码增强!
类型 |
特点 |
适用场景 |
浅拷贝 |
只复制对象本身,不复制内部的子对象 |
简单对象(如列表嵌套不深) |
深拷贝 |
递归复制对象及其所有子对象 |
复杂嵌套对象(如多层字典/列表) |
import copy
a = [1, [2, 3]]
b = copy.copy(a) # 或 a.copy() / list(a) / slice[:]
a[0]
(不可变类型)不影响 b
a[1][0]
(可变子对象)会影响 b
c = copy.deepcopy(a)
a
的哪一层,c
都完全不受影响a
)和室友(b
)共用客厅的冰箱(子对象)。a
)给你建了完全一样的房子(c
)。import copy
# 原始对象(含可变子对象)
original = [1, {'name': 'Alice'}, [3, 4]]
# 浅拷贝
shallow = copy.copy(original)
# 深拷贝
deep = copy.deepcopy(original)
# 修改原始对象的子对象
original[1]['name'] = 'Bob'
original[2].append(5)
print("原始对象:", original) # [1, {'name': 'Bob'}, [3, 4, 5]]
print("浅拷贝:", shallow) # [1, {'name': 'Bob'}, [3, 4, 5]] (受影响)
print("深拷贝:", deep) # [1, {'name': 'Alice'}, [3, 4]] (不受影响)
a = (1, [2]); b = copy.copy(a)
→ 修改 a[1]
仍会影响 b
__copy__()
和 __deepcopy__()
方法控制拷贝行为总结:
类型 |
特点 |
示例 |
列表(list) |
有序、可变、允许重复 |
|
元组(tuple) |
有序、不可变、允许重复 |
|
集合(set) |
无序、可变、不允许重复 |
|
字典(dict) |
键值对、键不可重复 |
|
字符串(str) |
不可变字符序列 |
|
对比项 |
List |
Set |
顺序 |
保持插入顺序 |
无序(存储顺序不确定) |
重复元素 |
允许重复 |
自动去重 |
查找速度 |
慢(遍历查找,O(n)) |
极快(哈希表实现,O(1)) |
适用场景 |
需要保留顺序或重复数据时 |
去重、快速成员检测 |
示例:
names = ["Alice", "Bob", "Alice"] # List允许重复
unique_names = {"Alice", "Bob"} # Set自动去重
对比项 |
数组 |
链表 |
内存分配 |
连续内存,大小固定 |
非连续内存,动态扩展 |
访问速度 |
极快(O(1),直接索引) |
慢(O(n),需遍历节点) |
插入/删除 |
慢(需移动元素,O(n)) |
快(O(1),修改指针即可) |
适用场景 |
频繁随机访问,数据量固定 |
频繁增删,数据量变化大 |
通俗比喻:
list
(实际是动态数组,非严格数组)array
模块(类型受限但更省内存)import array
arr = array.array('i', [1, 2, 3]) # 整型数组
collections.deque
(双端队列,近似链表特性)class Node:
def __init__(self, val):
self.val = val
self.next = None
list
,除非极端性能需求)总结:Python的list
和set
分别解决顺序存储和快速查询的问题,而数组与链表的区别是内存结构的根本差异。
list
去重最常见的几种方式如下:
1. 使用set()
去重(简单快捷,但会打乱顺序):
my_list = [1, 2, 2, 3, 1]
unique_list = list(set(my_list))
2. 保持顺序去重(常用于有序数据)
my_list = [1, 2, 2, 3, 1]
unique_list = []
seen = set()
for item in my_list:
if item not in seen:
seen.add(item)
unique_list.append(item)
3. 使用dict.fromkeys()
(保持顺序,适合Python 3.7+)
my_list = [1, 2, 2, 3, 1]
unique_list = list(dict.fromkeys(my_list))
类型 |
描述 |
是否有序 |
是否可重复 |
常用语言中的名称 |
list |
有序元素集合,支持增删改查 |
✅ |
✅ |
Python list, Java List |
vector |
动态数组,自动扩容,支持随机访问 |
✅ |
✅ |
C++ vector, Java ArrayList |
map |
键值对集合,key唯一,用于快速查找 |
❌(通常无序) |
key❌ value✅ |
Python dict, C++ map, Java HashMap |
list
或vector
存储。map
(如Python中的dict
)。list
去重、排序后显示。总结:
去重方法要结合“是否保留顺序”来选,三种数据结构各有用途,理解它们的特性可以帮助你在实际开发或测试中选择合适的数据结构。
使用递归的主要原因是为了让代码更简洁、结构更清晰,尤其适合处理具有“自相似”特征的问题,比如树结构、分形结构、回溯搜索、数学归纳等场景。
递归是指一个函数调用自身来解决问题,适用于下面这些情况:
对比点 |
for 循环 |
递归 |
代码结构 |
适合线性问题,步骤明确 |
适合分治、树形或图形问题 |
可读性 |
简单任务更直观 |
复杂结构更直观(如树的遍历) |
性能开销 |
更高效,无额外栈空间 |
每次调用会消耗栈空间 |
可维护性 |
复杂问题不易扩展 |
思路清晰,符合数学表达逻辑 |
错误易发点 |
循环条件控制 |
容易造成栈溢出、忘记递归出口 |
假设你在游戏里写一个技能树系统,每个技能点可能有多个子技能。
用递归写:
def traverse(skill_node):
print(skill_node.name)
for child in skill_node.children:
traverse(child)
用 for + 栈写:
stack = [root]
while stack:
node = stack.pop()
print(node.name)
stack.extend(node.children)
递归的写法更短,更符合“每个技能点都做同样的事”的逻辑,可读性强,代码更贴近问题本身的结构。
递归虽然优雅,但也容易出错:
递归的好处是:代码更简洁、逻辑更自然,特别适合解决自结构问题;但它在性能和稳定性上不如循环,需要谨慎使用。
在实际工作中,如果功能简单、可控,推荐优先用 for;如果是多层结构、递归定义的问题,就大胆用递归。
Python2 和 Python3 的主要区别集中在语法、标准库、字符编码和底层实现等方面。Python3 是 Python 官方推荐使用的版本,Python2 已在 2020 年正式停止支持。
下面从几个核心角度来对比这两个版本:
print
是一个语句print "Hello, world"
print
是一个函数print("Hello, world")
str
是字节串,unicode
是独立类型s = "你好" # 报错,默认 ASCII
str
就是 Unicode,bytes
用于字节s = "你好" # 正常,默认 unicode
print(5 / 2) # 输出 2
print(5 / 2) # 输出 2.5
若要地板除:使用 //
xrange
与 range
range
返回的是列表xrange
返回的是生成器(节省内存)range
就是生成器,xrange
被取消了input()
的行为input()
会执行输入的表达式,容易有安全风险raw_input()
才是读取字符串input()
始终返回字符串,语义更清晰urllib
→ 拆分成 urllib.request
, urllib.parse
等Queue
→ queue
except Exception as e:
f""
格式化字符串async/await
原生支持异步编程 功能/特性 |
Python2 |
Python3 |
打印语法 |
|
|
字符编码 |
默认 ASCII,需手动处理 Unicode |
默认 Unicode,字符串更统一 |
除法行为 |
5 / 2 = 2 |
5 / 2 = 2.5 |
/ |
是列表, 是生成器 |
是生成器,没有 |
输入函数 |
|
|
官方支持 |
已停止支持 |
持续更新和优化 |
如果你正在做任何新项目或测试框架搭建,一定要用 Python3。
Python2 已经是历史版本,虽然一些老项目可能还在维护,但新系统已经不推荐再使用。