所谓函数式编程,是指代码中每一块都是不可变的(immutable),都由纯函数(pure function)的形式组成。这里的纯函数,是指函数本身相互独立、互不影响,对于相同的输入,总会有相同的输出,没有任何副作用。
def multiply_2(l): for index in range(0, len(l)): l[index] *= 2 return l
这段代码就不是一个纯函数的形式,因为列表中元素的值被改变了,如果多次调用 multiply_2() 这个函数,那么每次得到的结果都不一样。
要想让它成为一个纯函数的形式,就得写成下面这种形式,重新创建一个新的列表并返回。
def multiply_2_pure(l): new_list = [] for item in l: new_list.append(item * 2) return new_list
优点:其纯函数和不可变的特性使程序更加健壮,易于调试(debug)和测试;
缺点:限制多,难写。
Python 主要提供三个函数:map()、filter() 和 reduce(),通常结合匿名函数 lambda 一起使用。
函数 map(function, iterable) 的第一个参数是函数对象,第二个参数是一个可以遍历的集合
作用:对 iterable 的每一个元素,都运用 function 这个函数。
l = [1, 2, 3, 4, 5] new_list = map(lambda x: x * 2, l) # [2, 4, 6, 8, 10] print(type(new_list)) print(list(new_list)) # 输出 <class 'map'> [2, 4, 6, 8, 10]
filter(function, iterable) 函数,和 map 函数类似,function 同样表示一个函数对象。
作用:对 iterable 中的每个元素,都使用 function 判断,并返回 True 或者 False,最后将返回 True 的元素组成一个新的可遍历的集合。
l = [1, 2, 3, 4, 5] new_list = filter(lambda x: x % 2 == 0, l) # [2, 4] print(type(new_list)) print(list(new_list)) # 输出 <class 'filter'> [2, 4]
reduce(function, iterable) 函数,它通常用来对一个集合做一些累积操作。
作用:function 有两个参数,表示对 iterable 中的每个元素以及上一次调用后的结果,运用 function 进行计算,所以最后返回的是一个单独的数值。
from functools import reduce l = [1, 2, 3, 4, 5] product = reduce(lambda x, y: x * y, l) # 1*2*3*4*5 = 120 print(type(product)) print(product) # 输出 <class 'int'> 120
从一个对象中依次取出数据,这个过程叫做遍历,这个手段称为迭代(重复执行某一段代码块,并将每一次迭代得到的结果作为下一次迭代的初始值)。
可迭代对象(iterable):是指该对象可以被用于for…in…循环,例如:集合,列表,元祖,字典,字符串,迭代器等。
from collections.abc import Iterable a: int = 1 print(isinstance(a, Iterable)) # False b: str = "lalalalala" print(isinstance(b, Iterable)) # True c: set = set([1, 2]) print(isinstance(c, Iterable)) # True
迭代器:对可迭代对象进行迭代的方式或容器,并且需要记录当前迭代进行到的位置。
自己实现一个迭代器对象:
from collections.abc import Iterator, Iterable class MyIterator: def __init__(self, array_list): self.array_list = array_list self.index = 0 def __iter__(self): return self def __next__(self): if self.index < len(self.array_list): val = self.array_list[self.index] self.index += 1 return val else: raise StopIteration # 父类如果是迭代器,子类也将是迭代器 class MySubIterator(MyIterator): def __init__(self): pass myIterator = MyIterator([1, 2, 3, 4]) # 判断是否为可迭代对象 print(isinstance(myIterator, Iterable)) # True # 判断是否为迭代器 print(isinstance(myIterator, Iterator)) # True # 子类实例化 mySubIterator = MySubIterator() print(isinstance(mySubIterator, Iterator)) # True # 进行迭代 print(next(myIterator)) # 1 print(myIterator.__next__()) # 2 print(next(myIterator)) # 3 print(next(myIterator)) # 4 print(next(myIterator)) # raise StopIteration
- 优点:迭代器对象表示的是一个数据流,可以在需要时才去调用next来获取一个值;因而本身在内存中始终只保留一个值,对于内存占用小可以存放无限数据流。优于其他容器需要一次将所有元素都存放进内存,如:列表、集合、字典...等
- 缺点:1.无法获取存放的元素长度,除非取完计数。2.取值不灵活,只能向后取值,next()永远返回的是下一个值;无法取出指定值(无法像字典的key,或列表的下标),而且迭代器对象的生命周期是一次性的,元素被迭代完则生命周期结束。
一边循环一边计算的机制,称为生成器:generator;同时生成器对象也是迭代器对象,所以他有迭代器的特性;例如支持for循环、next()方法…等
作用:对象中的元素是按照某种算法推算出来的,在循环的过程中不断推算出后续的元素,这样就不必创建完整的list,从而节省大量的空间。
简单生成器:通过将列表生成式[]改成()即可得到一个生成器对象
# 列表生成式 _list = [i for i in range(10)] print(type(_list)) # <class 'list'> print(_list) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] # 生成器 _generator = (i for i in range(10)) print(type(_generator)) # <class 'generator'> print(_generator) # <generator object <genexpr> at 0x7fbcd92c9ba0> # 生成器对象取值 print(_generator.__next__()) # 0 print(next(_generator)) # 1 # 注意从第三个元素开始了! for x in _generator: print(x) # 2,3,4,5,6,7,8,9
含有yield指令的函数可以称为生成器,它可以将函数执行对象转化为可迭代的对象。这样就可以像debug一样一步一步推进函数。可以实现让函数内部暂停,实现了程序的异步功能,这样可以及进行该函数与外部构件的信息交互,实现了系统的解耦。
对象引用 :对象名仅仅只是个绑定内存地址的变量
def func(): # 函数名仅仅只是个绑定内存地址的变量 print("i`m running") # 这是调用 func() # i`m running # 这是对象引用,引用的是内存地址 func2 = func print(func2 is func) # True # 通过引用进行调用 func2() # i`m running
闭包:定义一个函数A,然后在该函数内部再定义一个函数B,并且B函数用到了外边A函数的变量
def out_func(): out_a = 10 def inner_func(inner_x): return out_a + inner_x return inner_func out = out_func() print(out) # <function out_func.<locals>.inner_func at 0x7ff378af5c10> out_func返回的是inner_func的内存地址 print(out(inner_x=2)) # 12
装饰器和闭包不同点在于:装饰器的入参是函数对象,闭包入参是普通数据对象
def decorator_get_function_name(func): """ 获取正在运行函数名 :return: """ def wrapper(*arg): """ wrapper :param arg: :return: """ print(f"当前运行方法名:{func.__name__} with params: {arg}") return func(*arg) return wrapper # @func_name是python的语法糖 @decorator_get_function_name def test_func_add(x, y): print(x + y) def test_func_sub(x, y): print(x - y) test_func_add(1, 2) # 输出: # 当前运行方法名:test_func_add with params: (1, 2) # 3 # 不使用语法糖的话也可以用以下方法,效果是一样的 decorator_get_function_name(test_func_sub)(3, 5) # 还记得前文讲的引用吗?我们还可以换种写法达到跟