#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @File : cp6_3_1.py
# @Author: WRH
# @Date : 2021/4/22
# @Edition:Python3.8.6
# 6.3 匿名函数
'''
匿名函数就是没有实际名称的函数。Python使用lambda来创建匿名函数,
在lambda表达式中封装简单的逻辑,其主体仅是一个表达式而不需要使用代码块。
匿名函数适合于处理不再需要在其他位置复用代码的函数逻辑,可以省去函数的定义过程和考虑函数的命名,
让代码更加简洁,可读性更好。其语法格式为:
函数对象名 = lambda 形式参数列表:表达式
'''
def add(x,y):
return x+y
# 可定义为匿名函数:
func = lambda x, y: x+y
# 函数对象名可以作为函数直接调用,对于上例,可以这样调用:
a, b = 2.5, 3.6
sum = func(a, b)
print(sum)
# 或直接调用:
print((lambda x, y: x+y)(2.5, 3.6))
# 匿名函数也可嵌套条件分支,完成较为复杂的逻辑,例如,返回x和y中的较大值:
mymax = lambda x, y: x if x >= y else y
print(mymax(2, 3))
# 6.4 函数的递归
'''
递归(recursion)是一种直接或者间接调用函数自身的算法,其实质是把问题分解成规模缩小的同类子问题,然后递归调用表示问题的解。
能够设计成递归算法的问题必须满足两个条件:
1.能找到反复执行的过程(调用自身)
2.能找到跳出反复执行过程的条件(递归出口)
'''
# 例6-8 设n为大于等于1的正整数,用函数递归的方法求阶乘n!,本例求解5!。
'''
阶乘:一个正整数的阶乘(factorial)是所有小于及等于该数的正整数的积,并且0的阶乘为1。
某正整数的阶层可表示为:n!
如果n等于1,n!等于1;如果n大于1,n!等于n乘于(n-1)!
'''
def recursive(n):
if n == 1:
return 1
else:
return n*recursive(n-1)
a = 5
print('%d!=%d' % (a, recursive(a)))
# 例6-9 计算Fibonacci数列第15项的值。
'''
Fibonacci数列:又称黄金分割数列,除前两项值为1外,后面每项的值均等于前两项之和。
由此可设计函数Fibonacci(i)用递归表达:Fibonacci(i-1)+Fibonacci(i-2)。
'''
def Fibonacci(i):
if i == 0:
return 0
elif i == 1:
return 1
else:
return Fibonacci(i-1)+Fibonacci(i-2)
n = 15
print('Fibonacci数的第%d项为%d' % (n, Fibonacci(n)))
# 例6-10 辗转相除法(欧几里德法)求最大公约数
'''
用循环编程的思路为:两个正整数a b,且a>b,设其中a作为被除数,b作为除数,求a/b的余数temp,若temp为0
则b为最大公约数,若temp不为0,则把赋值给a,temp赋值给b,重新求a/b的余数,直至余数为0。
'''
a = 162
b = 189
temp = 100 # 可设任意非0整数
if b > a:
b, a = a, b
while temp != 0:
temp = a % b
if temp == 0:
print('最大公约数是', b)
break
else:
a, b = b, temp
# 用递归实现以上过程则更为简洁
def gcd(a, b):
if b == 0:
return a
else:
return gcd(b, a % b)
a = 162
b = 189
print('%d与%d的最大公约数是%d' % (a, b, gcd(a, b)))
# 6.5 函数的高级应用
# 6.5.1 生成器
'''
生成器(generator)是能够按照解析表达式逐次产生出数据集合中数据项元素的函数。
在Python语言中,利用生成器,可不必创建完整的数据集合,从而节省存储空间。
生成器函数与普通函数的差别主要在于:
1.生成器函数体中用yield关键字生成数据项,而不是用print输出数据项。
2.生成器函数用循环遍历时,可以用__next__()方法获取yield生成的数据项(此处next的两侧分别为两个半角下画线)。
3.生成器函数与普通函数的执行流程不同:
a.普通函数是顺序执行的,遇到return语句或最后一行语句就返回。
b.而生成器函数在每次调用__next__()方法的时候才执行,遇到yield语句返回,
再次执行时不是从头开始,而是从上次返回的yield语句处继续执行。
'''
# 例6-11 用生成器产生连续偶数序列并输出三次测试运行结果。
def generator_even():
for i in range(1, 11):
print('第%d步' % i)
yield i*2
g = generator_even()
print(g.__next__())
print(g.__next__())
print(g.__next__())
# 以上连续执行三次,结果可见,并非每次从头开始,而是从上次执行yield语句处继续执行
# 6.5.2 装饰器与闭包
# 对已有函数
def add(x, y):
return x+y
'''
如果需要添加返回原始数据的功能,则必须重写return语句,并且会改变返回值的类型。而且
对于已经编写完成的程序,改动一处可能会造成其他相关部分出错。
为了避免这种现象出现,可以使用装饰器
'''
# 装饰器
'''
python装饰器就是用于拓展原来函数功能的一种函数,这个函数的特殊之处在于它的返回值也是一个函数,
使用python装饰器的好处就是在不用更改原函数的代码前提下给函数增加新的功能。
装饰器经常被用于事务处理、日志记录、验证权限、调试测试等有需求的场景。
'''
def decorator(f): # 定义一个装饰器函数
def new_f(x, y): # 定义了一个新函数new_f来包装传入的函数f
print('参数1为%d,参数2为%d' % (x, y))
return f(x, y) # 用return f(x,y)在不改变原调用结果的前提下,添加了输出原始参数数据的功能。
return new_f # 返回新添加的函数
# 例6-12 利用装饰器为前述add函数添加输出原始数据功能并进行测试。
def decorator(f):
def new_f(x, y):
print('参数1为%d,参数2为%d' % (x, y))
return f(x, y)
return new_f
@decorator # 调用装饰器时,只需要在原函数定义前面用@引导装饰器即可
def add(x, y):
return x+y
print(add(2,3))
'''
语法糖(syntactic sugar):
类似于使用装饰器这种对功能没有影响,却能方便程序员使用的语法称为语法糖(syntactic sugar)
语法糖能增强程序的可读性,减少代码的出错概率
'''
# 闭包
'''
若调用某函数时,该函数将内部定义的函数作为返回值,则所返回的函数称为闭包(closure)
或者说,如果在一个内部函数里,对在外部作用域中的变量(非全局变量)进行引用,这个内部函数就是闭包
闭包是将函数的语句和执行环境打包在一起得到的对象,当执行嵌套函数时,
闭包将获取内部函数所需的整个环境,嵌套函数可以使用外层函数中的变量而不需要通过参数引入
装饰器也是闭包的一种形式
'''
def outer(x):
def inner(y):
return x+y
return inner # inner函数为闭包
f = outer(5)
# 我们在调用外函数 f = outer(5) 的时候,outer返回了inner,返回5+y,inner是一个函数的引用,这个引用被存入了f中。
# 所以接下来我们再进行f(20) 的时候,相当于运行了inner函数,返回5+20。
print(f(20))
'''
其中,inner(y)是嵌套于outer(x)中的内部函数,inner引用了外层作用域变量x,这个内部函数inner就是一个闭包。
当闭包执行完后,仍然能够保持当前的运行环境,并且可以根据外部作用域的变量得到不同的结果。
'''