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的迭代器和可迭代对象

posted @ 2022-05-25 17:52  YTT77  阅读(34)  评论(0编辑  收藏  举报