飞翔飞翔
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
  • 数据库

    • SQL教程
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
  • 数据库

    • SQL教程
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
  • 学习路径
  • 第1章 Python简介

    • Python是什么
    • 安装与运行
    • 交互式解释器
    • 注释与编码规范
  • 第2章 变量与数据类型

    • 变量与对象
    • 整数 int
    • 浮点数 float
    • 复数 complex
    • 布尔值 bool
    • 字符串 str
    • 空值 None
    • 类型转换
  • 第3章 运算符与表达式

    • 算术运算符
    • 比较运算符
    • 赋值运算符
    • 逻辑运算符
    • 位运算符
    • 身份与成员运算符
    • 海象运算符
    • 运算符优先级
  • 第4章 流程控制

    • if 语句
    • if-else 语句
    • if-elif-else 语句
    • match-case 语句
    • 条件表达式(三元运算符)
    • while 循环
    • for 循环
    • range 函数
    • break 与 continue
    • 循环的 else 子句
    • pass 语句
  • 第5章 数据结构

    • 列表创建与索引
    • 列表方法
    • 列表推导式
    • 元组
    • 序列解包
    • 集合
    • 字典创建与访问
    • 字典方法
    • 字典推导式
    • range 对象
  • 第6章 函数

    • 定义函数
    • 位置参数与关键字参数
    • 默认参数
    • 可变参数
    • 解包实参
    • 函数返回值
    • lambda 表达式
    • 文档字符串与注解
    • 作用域与命名空间
    • global 与 nonlocal
  • 第7章 模块与包

    • 模块导入
    • 模块搜索路径
    • 包与相对导入
    • 标准库概览
  • 第8章 文件与输入输出

    • 文件读写
    • 上下文管理器
    • 字符串格式化
    • JSON 与 CSV
  • 第9章 面向对象

    • 类与对象
    • 方法
    • 实例变量与类变量
    • 私有变量
    • 继承
    • 多重继承
    • 魔术方法
    • 属性装饰器
    • 数据类 dataclass
  • 第10章 异常处理

    • 语法错误与异常
    • try-except
    • 异常链与 raise
    • 清理操作
    • 自定义异常
  • 第11章 迭代器与生成器

    • 迭代器协议
    • 生成器
    • 生成器表达式
    • 迭代工具
  • 第12章 高级特性

    • 装饰器
    • 函数式编程
  • 第13章 工程实践

    • 测试与调试
    • 代码质量
    • 虚拟环境

函数式编程

Python 并非纯函数式语言,但提供了丰富的函数式工具。函数式编程的核心思想是用函数处理数据流,强调不可变数据和函数组合,与命令式的"先创建空列表再逐个 append"风格形成对比。

map、filter 与 reduce

map(function, iterable) 对可迭代对象的每个元素应用函数,返回迭代器而非列表,具有惰性求值特性,适合处理大数据流:

salaries = [18888.0, 232000.0, 8888.0, 15000.0]

# 给所有人加 1000 奖金
new_salaries = map(lambda s: s + 1000.0, salaries)
print(new_salaries)       # <map object ...> —— 迭代器
print(list(new_salaries)) # [19888.0, 233000.0, 9888.0, 16000.0]

# 多序列 map:按最短序列停止
names = ["航仔", "翼王", "图妹"]
for item in map(lambda n, s: f"{n}: {s}", names, salaries):
    print(item)
# 航仔: 18888.0
# 翼王: 232000.0
# 图妹: 8888.0

filter(function, iterable) 保留使函数返回真值的元素,同样返回迭代器。当 function 为 None 时,保留所有真值元素:

# 筛选工资超过 10000 的员工
high_earners = filter(lambda s: s > 10000, salaries)
print(list(high_earners))  # [18888.0, 232000.0, 15000.0]

# 过滤掉空字符串和 None
mixed = ["航仔", "", "翼王", None, "图妹", 0]
print(list(filter(None, mixed)))  # ['航仔', '翼王', '图妹']

functools.reduce(function, iterable[, initializer]) 对序列做累积计算,function 接收两个参数。求和、求积、找最值等场景都可以用它表达:

from functools import reduce

# 求工资总和
 total = reduce(lambda acc, s: acc + s, salaries)
print(total)  # 274776.0

# 带初始值:从 10000 开始累加
 total = reduce(lambda acc, s: acc + s, salaries, 10000.0)
print(total)  # 284776.0

# 找最高工资的员工(配合 zip)
emp_pairs = zip(names, salaries[:3])
richest = reduce(lambda a, b: a if a[1] > b[1] else b, emp_pairs)
print(richest)  # ('翼王', 232000.0)

reduce 在 Python 3 中被移到了 functools 模块,因为它虽然强大,但可读性往往不如显式循环。初学者应优先保证代码可读,在数据流转换场景下再考虑使用。

lambda 的高阶使用与限制

lambda 创建匿名函数,语法上只能包含单个表达式,不能写语句(如赋值、循环、try/except)。它适合作为临时回调传递,但复杂逻辑应使用 def:

# lambda 作为排序 key
employees = [
    {"name": "航仔", "salary": 18888},
    {"name": "翼王", "salary": 232000},
    {"name": "图妹", "salary": 8888},
]
by_salary = sorted(employees, key=lambda e: e["salary"], reverse=True)

# lambda 闭包:工厂函数
def make_multiplier(n):
    return lambda x: x * n
double = make_multiplier(2)
triple = make_multiplier(3)
print(double(5), triple(5))  # 10 15

lambda 的常见陷阱是循环变量绑定问题。在循环中定义的 lambda 会共享同一个变量引用:

# ❌ 错误:所有函数都返回 4
funcs = [lambda: i for i in range(4)]
print([f() for f in funcs])  # [3, 3, 3, 3]

# ✅ 正确:通过默认参数绑定当前值
funcs = [lambda i=i: i for i in range(4)]
print([f() for f in funcs])  # [0, 1, 2, 3]

functools.partial 偏函数

partial(func, *args, **kwargs) 固定函数的部分参数,返回一个参数更少的新函数。它与 lambda 的区别在于保留了原函数的元信息(__name__、__doc__ 等),且对位置参数的绑定更直观:

from functools import partial

def calc_tax(salary, rate, deduction):
    """计算个税"""
    return salary * rate - deduction

# 固定广州地区税率
guangzhou_tax = partial(calc_tax, rate=0.10, deduction=5000)
print(guangzhou_tax(18888.0))   # -3111.2(低于起征点)
print(guangzhou_tax(232000.0))  # 18200.0

# 固定位置参数:创建 int 转换器(base=2)
bin_to_int = partial(int, base=2)
print(bin_to_int("1010"))  # 10

# 对比 lambda:partial 保留原函数信息
print(guangzhou_tax.func)      # <function calc_tax ...>
print(guangzhou_tax.keywords)  # {'rate': 0.1, 'deduction': 5000}

partial 特别适合为回调函数统一上下文(如事件处理中固定某些参数),或在函数式数据流中减少重复代码。

operator 模块

operator 模块提供了与 Python 内置运算符对应的函数,避免为简单操作写 lambda,提升可读性和性能:

import operator

# 算术操作
print(operator.add(3, 4))      # 7
print(operator.mul(3, 4))        # 12

# 获取元素/属性 —— 替代 lambda
data = [("航仔", 18888), ("翼王", 232000), ("图妹", 8888)]
# 按第二个元素(工资)排序
by_salary = sorted(data, key=operator.itemgetter(1))

# 按字典键取值
rows = [
    {"name": "航仔", "age": 28},
    {"name": "翼王", "age": 35},
]
by_age = sorted(rows, key=operator.itemgetter("age"))

# 获取对象属性
class Employee:
    def __init__(self, name, salary):
        self.name = name
        self.salary = salary

staff = [Employee("航仔", 18888), Employee("翼王", 232000)]
richest = max(staff, key=operator.attrgetter("salary"))
print(richest.name)  # 翼王

# 调用对象方法
methodcaller("upper")("hello")  # 'HELLO'

itemgetter 和 attrgetter 支持多字段提取,返回元组,可用于多级排序:

# 先按部门排序,再按工资排序
department_staff = [
    ("技术部", "航仔", 18888),
    ("技术部", "翼王", 232000),
    ("产品部", "图妹", 8888),
]
sorted_staff = sorted(department_staff, key=operator.itemgetter(0, 2))

列表推导式与函数式风格对比

Python 中列表推导式 [expr for x in iterable if cond] 在多数场景下比 map/filter 更易读,且性能通常更好(CPython 对推导式有优化)。但函数式风格在链式操作和复用已有函数时更优雅:

nums = [1, 2, 3, 4, 5, 6]

# 列表推导式:筛选偶数再平方
result = [x ** 2 for x in nums if x % 2 == 0]
print(result)  # [4, 16, 36]

# 函数式风格:用已有函数组合
from functools import reduce
result = list(map(lambda x: x ** 2, filter(lambda x: x % 2 == 0, nums)))
print(result)  # [4, 16, 36]

# 更优雅的函数组合:借助 operator
from operator import mul
result = list(map(lambda x: mul(x, x), filter(lambda x: x % 2 == 0, nums)))

当处理生成器管道时,函数式风格的优势更明显。多个 map/filter 可以惰性串联,不创建中间列表,内存占用极低:

import itertools

# 处理百万级数据:全程迭代器,不占用大量内存
lines = open("salary_data.txt")  # 假设每行是 "name,salary"
parsed = map(lambda line: line.strip().split(","), lines)
valid = filter(lambda parts: len(parts) == 2, parsed)
salaries = map(lambda parts: float(parts[1]), valid)
high = filter(lambda s: s > 10000, salaries)
total = sum(itertools.islice(high, 1000))  # 只取前1000条求和

函数组合思想

虽然 Python 没有内置的函数组合运算符,但可以手动实现,把多个小函数串联成数据处理流水线:

def compose(*functions):
    """从右到左组合函数:compose(f, g, h)(x) == f(g(h(x)))"""
    def inner(arg):
        result = arg
        for f in reversed(functions):
            result = f(result)
        return result
    return inner

strip = lambda s: s.strip()
upper = lambda s: s.upper()
add_prefix = lambda s: f"[LOG] {s}"

process = compose(add_prefix, upper, strip)
print(process("  hello world  "))  # [LOG] HELLO WORLD

这种思想在数据处理、ETL 流程和日志格式化中非常实用:把复杂操作拆成可测试、可复用的小函数,再用组合串联起来。

上一页
装饰器