Python 基础 / 03
函数:把一段逻辑变成可复用工具
函数接收输入,完成一项明确任务,并返回输出。刷题时,题目通常已经给出函数签名,你需要补全函数体。
def add(a, b):
result = a + b
return result
answer = add(3, 5) # 8
函数的四个部分
def find_max(nums): # 1. 函数名与参数
best = nums[0] # 2. 局部变量
for value in nums: # 3. 函数体
if value > best:
best = value
return best # 4. 返回值
- 函数名说明它做什么,通常使用小写下划线命名。
- 参数是调用者传入的数据。
- 函数体只在调用函数时执行。
- return 把结果交还给调用者,并立即结束函数。
return 与 print 不一样
def wrong_add(a, b):
print(a + b) # 只显示,调用结果是 None
def correct_add(a, b):
return a + b # 可以继续参与计算
x = wrong_add(2, 3) # 屏幕显示 5,但 x 是 None
y = correct_add(2, 3) # y 是 5
LeetCode 核心代码模式要求 return;ACM 模式通常在 solve() 中计算,最后 print()。
参数的传递方式
位置参数与关键字参数
def power(base, exponent):
return base ** exponent
power(2, 3)
power(base=2, exponent=3)
power(2, exponent=3)
默认参数
def clamp(value, lower=0, upper=100):
return max(lower, min(value, upper))
clamp(120) # 100
clamp(-5, lower=-2) # -2
默认参数必须写在非默认参数后面。不要把可变对象作为默认值:
# 错误:多次调用会共享同一个列表
def append_value(value, result=[]):
result.append(value)
return result
# 正确
def append_value(value, result=None):
if result is None:
result = []
result.append(value)
return result
可变数量参数
def total(*numbers):
return sum(numbers)
total(1, 2, 3) # numbers 是元组 (1, 2, 3)
def show(**options):
return options
show(color="red", size=10) # options 是字典
刷题中不常定义 *args、**kwargs,但阅读库函数时会遇到。
多返回值与解包
Python 实际返回的是一个元组:
def min_max(nums):
return min(nums), max(nums)
smallest, largest = min_max([3, 1, 8])
left, right = right, left
可变对象与引用
Python 参数传递的是对象引用。整数和字符串不可变;列表、字典、集合可变。
def change_number(number):
number += 1 # 创建新的整数,不影响外部
def change_list(nums):
nums.append(99) # 修改同一个列表,外部可见
x = 10
values = [1, 2]
change_number(x) # x 仍是 10
change_list(values) # values 变成 [1, 2, 99]
原地题目要求修改传入数组;其他题目如果不希望影响输入,应先复制:
copied = nums[:]
copied = list(nums)
作用域
函数内部定义的变量默认是局部变量。
count = 10
def work():
count = 3 # 新的局部变量
return count
work() # 3
count # 10
递归和回溯中常用闭包保存答案:
def tree_sum(root):
total = 0
def dfs(node):
nonlocal total
if node is None:
return
total += node.val
dfs(node.left)
dfs(node.right)
dfs(root)
return total
能用返回值表达时优先使用返回值,减少 global 和 nonlocal 带来的状态混乱。
Lambda 与 key 函数
Lambda 是只包含一个表达式的匿名函数:
square = lambda x: x * x
square(4) # 16
intervals = [(1, 5), (2, 3), (1, 2)]
intervals.sort(key=lambda item: (item[0], item[1]))
复杂逻辑应写普通函数:
def sort_key(item):
start, end = item
return start, -end
intervals.sort(key=sort_key)
注意传递函数时不加括号:key=sort_key 是把函数交给排序;key=sort_key() 是立刻调用。
递归
递归函数直接或间接调用自己。必须有:
- 终止条件:最小问题直接返回。
- 递归关系:把当前问题缩小。
def factorial(n):
if n <= 1:
return 1
return n * factorial(n - 1)
执行 factorial(4) 时,调用栈为:
factorial(4)
factorial(3)
factorial(2)
factorial(1) -> 1
-> 2
-> 6
-> 24
递归处理树
def max_depth(root):
if root is None:
return 0
left_depth = max_depth(root.left)
right_depth = max_depth(root.right)
return max(left_depth, right_depth) + 1
递归深度过大可能触发 RecursionError。链式结构或大图优先考虑显式栈。
核心代码模式与 ACM 模式
LeetCode 核心代码
def two_sum(nums, target):
seen = {}
for index, value in enumerate(nums):
if target - value in seen:
return [seen[target - value], index]
seen[value] = index
return []
平台负责构造参数、调用函数和检查返回值。
ACM 完整程序
import sys
def solve():
data = list(map(int, sys.stdin.buffer.read().split()))
n = data[0]
nums = data[1:1 + n]
print(sum(nums))
if __name__ == "__main__":
solve()
你需要自己读取输入、构造数据、调用算法并输出答案。输入输出教程会完整讲解。
函数设计检查表
- 一个函数是否只做一件事?
- 参数名是否表达含义?
- 所有分支是否都有正确返回值?
- 是否无意修改了传入列表?
- 递归是否一定能到达终止条件?
- 函数返回的是结果,还是只打印了结果?
自测
- 写
count_even(nums)返回偶数个数。 - 写
divide(a, b),当b == 0时返回None。 - 写递归函数求列表元素和。
- 分别用返回值和
nonlocal实现二叉树节点计数,比较可读性。
| ← 返回 Python 基础 | 上一篇:控制流 | 下一篇:集合类型 → |