,
7.1又见函数
1.python中的函数式
函数式编程以函数为中心进行代码封装。函数式编程强调了函数的纯粹性。一个纯函数是没有副作用的,即这个函数的运行不会影响其他函数。进程的先后顺序不同会影响最终结果,这被称为竞跑条件,函数式编程消灭了副作用,即无形中消除了竞跑条件的可能。
2.并行运算
所谓的并行运算是指多条指令同时执行。一个程序运行后,就成为一个进程,进程有自己的内存空间,用来储存自身的运行状态、数据和相关代码。一个进程内部又可以有多个称为“线程”的任务,处理器可以在多个线程之间切换,从而形成并行的多线程处理。线程之间可以共享同一个进程的内存空间。
7.2被解放的函数
1.函数作为参数和返回值
def square_sum(a,b):
return a**2+b**2
def cubic_sum(a,b):
return a**3+b**3
def argument_demo(f,a,b):
return f(a,b)
print(argument_demo(square_sum,3,5))
print(argument_demo(cubic_sum,3,5))
2.函数作为返回值
def line_conf():
def line(x):
return 2*x+1
return line
my_line=line_conf()
print(my_line(5))#打印11
我们在line_conf()函数的隶属范围内定义的函数line(),就只能在line_conf()的隶属范围内调用。
3.闭包
def line_conf():
b=15
def line(x):
return 2*x+b#闭包
b=5
return line
if __name__=="__main__":
my_line=line_conf()
print(my_line(5))#打印15
line()定义的隶属程序块中引用了高层及的变量b。b的定义并不在line()内部,而是一个外部的对象。我们称b为line()的环境变量。尽管b位于line()定义的外部,但当line被函数line_conf()返回时,还是会带有b的信息。一个函数和他的环境变量组合在一起,就构成了一个闭包。在python中,所谓闭包是一个包含环境变量取值的函数对象。
闭包可以提升代码的复用性:
def line_conf(a,b):
def line(x):
return a*x+b
return line
line1=line_conf(1,1)
line2=line_conf(-2,-6)
这个例子中,函数line()与环境变量a、b构成闭包。除了复用代码,闭包还能起到减少函数参数的作用。
7.3小女子的化妆匣
1.装饰器
装饰器可以对一个函数、方法或者类进行加工。
def decorator_demo(old_function):
def new_function(a,b):
print("input",a,b)
return old_function(a,b)
return new_function
@decorator_demo
def square_sum(a,b):
return a**2+b**2
if __name__=="__main__":
print(square_sum(3,4))
定义好装饰器后,我们就可以通过@语法使用了,在函数square_sum()定义之前调用@decorator_demo,实际上是将square_sum()传递给了decorator_demo(),并将decorator_demo()返回的新函数对象赋给原来的函数名square_sum()。
2.带参装饰器
def pre_str(pre=""):
def decorator(old_function):
def new_function(a,b):
print(pre+"input",a,b)
return old_function(a,b)
return new_function
return decorator
@pre_str("^_^")
def square_sum(a,b):
return a**2+b**2
if __name__ =="__main__":
print(square_sum(3,4))
3.装饰类
一个装饰器可以接受一个类,并返回一个类,从而起到加工类的效果P180。
7.4高阶函数
1.lambda与map
能接收其他函数作为参数的函数,被称为高阶函数。
lambda:
lambda_sum=lambda x,y:x+y
print(lambda_sum(3,4))
map:
data_list=[1,3,5,6]
result=map(lambda x:x+3,data_list)
map的第一个参数是一个函数对象,第二个参数是一个可循环对象。对于data_list的每个元素,lamdba函数都会调用一次。那个元素会成为lamdba函数的参数。最终,map()会返回一个迭代器。迭代器中的元素,就是多次调用lamdba函数的结果。
这个函数也可以是一个多参数的函数,这时map()的参数列表中就需要提供相应数目的课循环对象。
2.filter函数
如果函数对象返回的是True,则该次的元素被放到返回的迭代器中。
def larger100(a):
if a>100:
return True
else:
return False
for itemin filter(larger100,[10,56,101,500]):
print(item)
3.reduce函数
reduce()在标准库中的functools包中,使用之前需要引入。reduce()对作为参数的函数对象有一个特殊要求,就是这个作为参数的函数必须能接收两个参数:
from functoolsimport reduce
data_list=[1,2,5,7,9]
result=reduce(lambda x,y:x+y,data_list)
print(result)#打印24
函数reduce()的第一个参数是求和sum()函数,它接收两个参数x和y。上一次运算的结果将作为下一次调用的第一个参数。
4.并行处理
下载的程序就是在多进程条件下使用了多线程的map()方法。这段进程多线程的下载同一个URL下的资源。程序用了第三方包requests来进行HTTP下载P187。从结果可以看到,运行时间能大为缩短。
7.5自上而下
1.便捷表达式
生成器表达式是构建生成器的便捷方法:
gen=(x for x in range(4))
生成表的快捷方式,列表解析:
l=[x**2 for x in range(10)]
除了for,列表解析中还可以使用if:
xl=[1,3,5]
yl=[9,12,13]
l=[x**2 for (x,y)in zip(xl,yl)if y>10]
2.懒惰求值
介绍迭代器时提到过,迭代器的元素是实时计算出来的。在使用该元素之前,元素并不会占据内存空间。与之相对应,列表在建立时,就已经产生了各个元素的值,并保存在内存中。迭代器的工作方式正是函数式编程中的懒惰求值。我们可以对迭代器进行各种各样的操作,但只有在需要时,迭代器才会计算出具体的值。如,,列表提前准备数据的方式,就浪费了很多运算资源。
3.itertools包
这个包提供了更加灵活的生成迭代器的工具,这些工具的输入大都是已有的迭代器。P193