Python基础知识
函数式编程
定义
所谓函数式编程,是指代码中每一块都是不可变的(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()
函数 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()
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()
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…循环,例如:集合,列表,元祖,字典,字符串,迭代器等。
- 在python中如果一个对象实现了 __iter__方法,我们就称之为可迭代对象,可以查看set\list\tuple…等源码内部均实现了__iter__方法
- 如果一个对象未实现__iter__方法,但是对其使用for…in则会抛出TypeError: ‘xxx’ object is not iterable
- 可以通过isinstance(obj,Iterable)来判断对象是否为可迭代对象。如:
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
迭代器:对可迭代对象进行迭代的方式或容器,并且需要记录当前迭代进行到的位置。
- 在python中如果一个对象同时实现了__iter__和__next__(获取下一个值)方法,那么它就是一个迭代器对象。
- 可以通过内置函数next(iterator)或实例对象的__next__()方法,来获取当前迭代的值
- 迭代器一定是可迭代对象,可迭代对象不一定是迭代器。
- 如果可迭代对象遍历完后继续调用next(),则会抛出:StopIteration异常。
自己实现一个迭代器对象:
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)
# 还记得前文讲的引用吗?我们还可以换种写法达到跟👆一样的效果
dec_obj = decorator_get_function_name(test_func_sub) # 这里等同于wrapper对象
dec_obj(3,5) # 这里等同于wrapper(3,5)
# 输出:
# 当前运行方法名:test_func_sub with params: (3, 5)
# -2
魔法函数
@staticmethod
参考资料:
Python函数-函数式编程
python中的迭代器,生成器与装饰器详解
python之迭代器、生成器、装饰器
详解python三大器——迭代器、生成器、装饰器
python 装饰器的使用与要点
魔法函数
python中@staticmethod
python的多线程
3-可迭代对象 迭代器 生成器的原理剖析
一文看懂python的迭代器和可迭代对象