推荐几个比较高阶的函数编程手法
背景:Python宗旨:大道至简;不写一切不必要的代码;需足够干净、简单、纯粹。本次推荐皆是Python内置函数提供的便捷写法。
1、lambda函数
lambda函数是Python提供的语法糖,适合用于相对比较简单的函数。
lambda param_list: expression
func = lambda x:x*2
def func(x):
return x*2
解释:以上两种写法等价;
2、map函数
map:会根据提供的函数对指定序列做映射;map(function, iterable, ...)
res = map(lambda x:x*2,[1,2,3]) # res为map函数返回的迭代器对象,故强转list做容器承接
data = list(res)
==> [2,4,6]
### 等价于
data = list(map(func,[1,2,3]))
3、reduce函数
reduce: 函数会对参数序列中元素的运行结果进行累积
reduce(function, iterable[, initializer])
reduce(lambda x,y:(x+y)*2,[1,2,3])
==>18
解释:(1+2)*2 = 6 ; (6+3)*2 = 18
4、filter条件过滤
filter:内置函数用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表
filter(function, iterable)
list(filter(lambda x: x % 2 == 0, [1,2,3,4,5,6,7,8,9,10]))
==> [[2, 1], [3, 4], [5, 3], [7, 4], [9, 0]]
5、闭包的高级应用
def get_func(a,b):
return lambda x:ax+b
y1 = get_func(1,1) # y1 = lambda x:1x+1
y1(1) # 结果为2
6、列表推导式\字典推导式 + if 过滤
items = [1,2,3,4]
# 列表推导式
timp = [item+2 for item in items]
# 字典推导式
timp = {k:k*2 for k in items}
#列表推导式 + if过滤
timp = [item+2 for item in items if item > 2]
7、enumerate内置函数
对于列表:值与索引同时获取
days=['mon','tus','wed','ths','fri','sat','sun']
for i,day in enumerate(days):
print(i,day)
8、yield:迭代器的自定义以及高级用法详解
为什么说yield是迭代器的自定义,解释如下:range是最常见的迭代器,如图它迭代了1-10的数字。那么对于range而言,迭代1-10的数据就是range函数的规则。那么如何自定义迭代器规则呢,yield就是最好的工具
for i in range(10)
def foo(start,end):
while 1:
res = start*3-1
if res < end:
yield res
start+=1
continue
break
for i in foo(1,10):
print(i)
==> 2 5 8
在上述例子中,我将foo函数的规则该成了 start*3 - 1。我在我另一篇博客中讲过,迭代过程的底层实质上是调用了可迭代对象的next()函数。本事例中也是一样的,假如说for循环本身不调用next函数,那么yield res后面的代码也不会被执行。若没有Python底层关于指针的设计的伙伴可以先不用去深究这个点。我在此推荐一种好用的最佳实践,关于数据库的启停:
def db_connect():
'''数据库连接(省略)'''
return db,cursor
def with_db():
db,cursor = db_connect()
try:
yield db,cursor
finally:
cursor.close()
db.close()
def service():
db,cursor = next(with_db()#此处返回一个迭代器对象,那么调用next函数,指针将定位到db对象
在此例中,service中返回了db实例,可以往下可以执行crud相关操作,执行完毕之后with_db将最后执行db.close(),故将不必在业务代码中关心数据库的启停。小伙伴会问,为什么可以这样!事实上如我所讲yield代码片一直在等待service函数发出next()函数指令,当service发出函数指令后,yield将执行下面的代码,又因为此时service不再发出next()指令,故finally代码片一直处于等待状态。又因为finally底层的特性,注定它将在所有其他动作执行完之后执行,所以当service函数执行完之后,才执行finally中的db.close()。
如果有些经验的朋友会知道,finally的优先级可以在return之后,即函数finally可在函数return之后执行。所以用好finally这一特性,可以有更多的设计可能性
9、with上下文管理器
上面我们介绍了通过yield的特性设计了数据库的启停,其实上下文管理器也可以实现,事实上用上下文管理器实现数据库的启停将更加优雅。我将结合此事例论述上下文管理器的使用以及举例出如何通过上下文管理器更加优雅的设计数据库的启停;
def db_connect():
'''数据库连接(省略)'''
return db,cursor
class dbsession:
def __init__(self):
self.db,self.cursor = db_connect()
def __enter__(self):
return self.db,self.cursor
def __exit__(self, exc_type, exc_value, traceback):
self.cursor.close()
self.db.close()
def service():
with dbsession() as db,cursor:
pass
如上实现了一个上下文管理器,顾名思义。init初始化实例时执行数据库连接,紧接着执行enter函数,等于说实例化之后返回的参数由db,cursor接收。当with作用域的代码片结束执行之后,将执行exit函数,故实现了数据库的自动启停。
拓展说明:
1、with是Python提供的语法糖,专供类使用,因为在Python底层设计上要搭配类的enter、exit函数方能使用
2、enter、exit函数是类自带的内置函数,对于这种内置函数的继承开发,我们称为元编程–元类编程。通常这类函数是用于类在初始化时做的一些动作或进行一些高级封装时使用
3、exit函数的三个参数分别为错误类型、错误值、错误回溯记录。我们在上述函数中已经将其重写。事实上,Python本来自带精确的全局错误控制器,故exit的错误处理可忽略其错误处理,若有需要的伙伴可自行尝试