Skip to content

函数式编程

NOTE

使用纯函数(相同的输入总是产生相同的输出,没有副作用)

避免可变状态和数据变化

函数是一等公民(可以像变量一样传递)

强调递归而非循环

但是我想说,它是能让你的 py 脚本更简洁。类似于 javscript 推出了一系列的数组方法,在处理数据和格式化方面及其方便。不用在自己傻傻的 for 循环了。

开始之前,你应当回顾数据类型转换的问题。

list()、dict() 类型转换

要明确一点,listdict 是试图将可迭代对象变更为字典和列表类型。Python 的原生类型中可迭代对象类型如下:

list, tuple, str, dict, set, renge 函数, 文件对象

字典的转换默认会得到所有的 key,如果想获取 value 则需要使用 dict.values()

py
# 字典转 ...
dic = { "a": 1, "b": 2, "c": 3 }
print(list(dic)) # ['a', 'b', 'c']
print(tuple(dic)) # ('a', 'b', 'c')
print(str(dic)) # "{'a': 1, 'b': 2, 'c': 3}"
print(set(dic)) # {'a', 'c', 'b'}

# 列表转 ...
array = [1, 2, 3, 4, 5]
print(dict(array)) # ❌
print(tuple(array)) # (1, 2, 3, 4, 5)
print(set(array)) # {1, 2, 3, 4, 5}
print(str(array)) # "[1, 2, 3, 4, 5]"

# 字符串转 ...
string = "hello"
print(list(string))  # ['h', 'e', 'l', 'l', 'o']
print(set(string))   # {'h', 'e', 'l', 'o'} 列表
print(tuple(string)) # ('h', 'e', 'l', 'l, 'o')
print(dict(string)) # ❌

# 集合转 ...
set1 = {'h', 'e', 'l', 'o'}
print(list(set1))  # ['h', 'e', 'l', 'o']
print(str(set1))   # "{'h', 'e', 'l', 'o'}"
print(tuple(set1)) # ('h', 'e', 'l', 'o') 
print(dict(set1)) # ❌

# 元组转 ...
tuple1 = ('h', 'e', 'l', 'o')
print(list(tuple1))  # ['h', 'e', 'l', 'o']
print(str(tuple1))   # "('h', 'e', 'l', 'o
print(set(tuple1))   # {'h', 'e', 'l', 'o'}
print(dict(tuple1)) # ❌

想要转字典的前提是这是一个二维结构,可以有任意数据结构组合排除 set。比如

py
list_val = [[1, 2], [3, 4]]
tuple_val = ((1, 2), [3, 4])

print(dict(list_val), dict(tuple_val))

表达式

py 中,简单来说只要是一行能够解决的问题,都叫表达式。像数学运算、条件运算、逻辑运算、三元运算、lambda、生成式。

数学、逻辑、条件、三元运算

py
# 数学运算
result = a + b
# 条件运算 返回比对的结果 True or False
result = a < b

# 逻辑运算 
# 如果 a 存在返回 a,反之返回 b
result = a or b
# 如果 a 和 b 都存在才会返回 True
result = a and b

# 三元运算
result = '正确' if a < b else '错误'
# 可以允许相对复杂的运算,不建议使用,可读性差
result = '优秀' if a >= 90 else '还行' if a >= 80 else '不行'

# 等价于
if a >= 90:
    result = '优秀'
elif a >= 80:
    result = '还行'
else:
    result = '不行'

生成式

py
# 列表生成式
numbers = [1, 2, 3, 4, 5]
squared = [x ** 2 for x in numbers]
# 带条件的列表生成式
even_squared = [x ** 2 for x in numbers if x % 2 == 0]

# 字典生成式
keys = ['a', 'b', 'c']
values = [1, 2, 3]
mapping = {k: v for k, v in zip(keys, values)}
print(mapping)  # {'a': 1, 'b': 2, 'c': 3}
# 带条件的字典生成式
even_squares = {x: x**2 for x in numbers if x % 2 == 0}
print(even_squares)  # {2: 4, 4: 16}

# 集合生成式
numbers = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
unique_squares = {x**2 for x in numbers}
print(unique_squares)  # {16, 1, 9, 4} (顺序可能不同)
# 带条件的集合生成式
even_squares = {x**2 for x in numbers if x % 2 == 0}
print(even_squares)  # {16, 4}


# 生成器表达式 使用 () 返回的是一个生成器,需要手动转数据类型。
# 数据量比较大时,使用此方式提高执行速度
# 基本语法:(表达式 for 项目 in 可迭代对象)
numbers = [1, 2, 3, 4, 5]
squared_gen = (x**2 for x in numbers)
print(squared_gen)  # <generator object <genexpr> at 0x...>

lambda 匿名函数

这是一种简洁的定义函数的方式,一行代码定义简单的函数,不需要命名,特别适合一次性使用的函数。 lambda [参数]: 函数体

lambda 后只能跟表达式

py
# 无参数
greet = lambda: 'hello world'
print(greet()) # hello world

# 带参数, 一个或多个和 def 函数一样
get_count = lambda x, y: x + y
print(get_count(1, 2)) # 3

# 默认参数
get_diff = lambda x, y=[2, 4]: [i for i in x if i not in y]
print(get_diff([1, 2, 3, 4])) # Output: [1, 3]

# 可变参数
sum_all = lambda *args: sum(args)
print(sum_all(1, 2, 3, 4)) # 10

# 关键字参数
create_person = lambda **kwargs: kwargs
print(create_person(name="alice", age=25)) # { 'name': 'alice', 'age': 25 }

# 立即调用
result = (lambda x, y: x * y)(1, 2) # 2

数据格式化方法

经常用到方法有很多,大致可以分为两类,像 map filter zip reversed 返回的是一个可迭代对象,必须通过 list 等类型转换方法进行进行。

map

常用于基于一个可迭代对象,生成另一个新的可迭代对象。

py
list_val = [1, 2, 3, 4, 5]
list(map(lambda item: item % 2 == 0, list_val))

filter

常用于基于一个可迭代对象,过滤出来一个新的可迭代对象

py
list_val = [1, 2, 3, 4, 5]
list(filter(lambda item: item % 2 ===0, list_val))

reduce

对一个可迭代对象做累计操作,第一个参数是

py
from functools import reduce

list_val = [1, 2, 3, 4, 5]
print(reduce(lambda x, y: x + y, list_val)) # 15

zip

将两个可迭代对象进行合并,以短的为准

py
list_val = [1, 2, 3, 4, 5]
list_val1 = [6, 7, 8, 9, 10, 11]

print(list(zip(list_val, list_val1)), dict(zip(list_val, list_val1)))
# [(1, 6), (2, 7), (3, 8), (4, 9), (5, 10)] 
# {1: 6, 2: 7, 3: 8, 4: 9, 5: 10}

# 解压缩, 解压时只能对列表进行操作
first, second = zip(*list(zip(list_val, list_val1)))

reversed

翻转可迭代对象

py
dic = { 'a': 1, 'b': 2, 'c': 3}
print(list(reversed(dic)))  # ['c', 'b', 'a']

any、all

py
list_val = [1, 2, 3, 4, 5]
# any 任何元素为 True 就返回 True
print(any(list(map(lambda item: item >= 3, list_val)))) # True
# all 全部元素为 True 才返回 True
print(all(list(map(lambda item: item >= 3, list_val)))) # False

数学及排序方法

py
print(sum([1, 2, 3])) # 6

print(max([1, 2, 3])) # 3

print(min([1, 2, 3])) # 1

print(round(3.14159, 2))  # 3.14

print(abs(-10))  # 10

print(divmod(10, 3))  # (3, 1)  3 余 1

print(pow(2, 3))  # 8  2 的 3次方

print(sorted([3, 1, 2]))  # [1, 2, 3]
print(sorted([3, 1, 2], reverse=True))  # [3, 2, 1]
# 也可以针对字符串进行排序
# 优先级为 大写首字母, 小写首字母,汉字
print(sorted(['apple', 'Xiaomi', 'huawei', '看见']))  # ['Xiaomi', 'apple', 'huawei', '看见']
# 可以通过字母大小写转换排序
print(sorted(['apple', 'Xiaomi', 'huawei', '看见'], key=str.lower)) # ['apple', 'huawei', 'Xiaomi', '看见']