Python第十三关02(高阶函数,递归函数)

高阶函数

高阶函数特点:
  • 函数的名可以j进行赋值
  • 函数名可以做为函数的参数,可以作为函数的返回值

函数本身是一个对象,函数的名字是一个变量,所以函数的名字可以赋值

现在我们用Python代码实现:

1 def f():
2     print('ok')
3 
4 def bar(a,b,func):
5     func()      #此时的func接收了函数f 所以func() = f()
6     return 1
7 
8 bar(1,2,f)  #将函数名作为参数传入函数bar里面的形参func

函数可以作为函数的返回值

例子1;变量作为返回值

1 def foo2():
2     x = 5
3     return x
4 
5 print(foo2())   #5

例子2,因为上面说到函数的名字是一个变量,所以函数才可以作为返回值

1 def foo3():
2     def inner():
3         return 8
4     return inner
5 
6 print(foo3())  #foo3() 接收的是innet函数对象指向的内存地址    <function foo3.<locals>.inner at 0x7fd263565730>
7 ret = foo3()    
8 print(ret())   #执行foo3()函数里面的内容    8

如果上面都理解后可看下面实例,如果看不懂,请重现看前面的解释:

1 def f(n):
2     return n*n
3 
4 def foo(a,b,func):
5     func(a)+func(b)
6     ret = func(a) + func(b)
7     return ret
8 foo(1,2,f)
9 print(foo(1,2,f))
 1 def f(n):   #1.定义一个函数f
 2     return n*n  #2.函数返回的是函数f的形参n接收实参的积
 3 
 4 def foo(a,b,func):  #3.定义一个函数foo 定义三个形参
 5     func(a)+func(b) #5.因为在调用函数foo把实参1,2,f(f为函数的名字)分别传给a,b,func
 6                     #6.所以此时func(a)+func(b)相当于f(1)+f(2)
 7     ret = func(a) + func(b)
 8     return ret      #7.返回的ret为 1*1 + 2+5 = 5   所以返回值应该
 9 foo(1,2,f)  #4.调用函数foo 把实参1,2,f(f为函数的名字)分别传给a,b,func
10 print(foo(1,2,f))   #8.此时的值应该是 1*1 + 2+5 = 5
带注释的实例
函数的返回值

要想获取函数的执行结果,就可以用return语句把结果返回

注意:

函数在执行过程中只要遇到return语句,就会停止执行并返回结果,所以也可以理解为return语句代表这函数结束

如果未在函数中制定return,那这个函数的返回值为None

return可以返回多个对象,解释器会把多个对象组装成一个元组作为一个整体把结果输出

函数的作用域

Python中的作用域分为四种情况:

  • L  :   local  局部作用域,即函数中定义的变量
  • E  :  enclosing  嵌套的父级函数的局部作用域,即包含此函数的上级函数的局部作用域,但不是全局的:
  • G  :  globa  全局变量,就是模块级别定义的变量;
  • B  :  built-in  系统固定模块里面的变量,比如int,bytearray等,搜索变量的优先级顺序依次是:作用域局部 > 外层作用域 > 当前模块中的全局 > Python内置的作用域,也就是LEGB

例子1:

 1 x = int(2.9)    # int built-in
 2 g_conut = 0     # global
 3 def outer():
 4     o_count = 1 # enclosing
 5     def inner():
 6         i_count = 2 #local
 7         print(o_count)
 8     # print(i_count)找不到
 9     inner()
10 outer()
11 
12 # print(o.count)找不到

当然,local和enclosing是相对的,enclosing变量相对上层来说也是local。

 作用域的产生

在Python中,只有模块,类以及函数才会引入型的作用域,其他的代码块,如if try for 是不会引入新的作用域的,如下代码

1 if 2 > 1:
2     x = 1
3 print(x)    # 1

这个是没有问题的,if并没有引入一个新的作用域,x仍处当前的作用域中,后面的代码可以使用

1 def test():
2     x = 1
3 print(x)    #NameError: name 'x' is not defined

def class lambda是可以引入新的作用域的

变量的修改
 1 x = 3
 2 def f2():
 3     print(x)
 4     x = 5
 5 f2()    #   UnboundLocalError: local variable 'x' referenced before assignment
 6 
 7 #错误原因在于print(x)时,解释器会在局部作用域朝,会找到x=5(函数已经加载到内存),但x使用在声明前了,所以报错:
 8 #local variable 'x' referenced before assignment    如何证明找到了x=5?注释掉x = 5 返回值就为3
 9 #同理
10 x = 6
11 def f2():
12     x += 1  #   UnboundLocalError: local variable 'x' referenced before assignment
13 f2()
global关键字

当局部作用域想修改外部作用域的变量时,就要用到global和nonlocal关键字了,当修改的变量是在局部作用域(global作用域)上的,就要使用global先声明一下,代码如下:

1 count = 10
2 def outer():
3     global count
4     print(count)    # 10
5     count = 100
6     print(count)    # 100
7 outer()
nonlocal关键字

global关键字声明的变量必须在全局作用域上,不能嵌套作用域上,当要修改作用域(enclosing组配用于,外层非全局作用域)中的变量怎么办呢,这是就需要nonlocal关键字

1 def outer():
2     count = 10
3     def inner():
4         nonlocal count
5         count = 20
6         print(count)    #20
7     inner()
8     print(count)    #20
9 outer()
小结

变量查找顺序:LEGB,局部作用域 > 外层作用域 > 当前模块总的全局 > Python内置作用域

只有模块,类,函数才能引入型的作用域

对于一个变量,内部作用域先声明就会覆盖外部变量,不声明直接使用,就会使用外部作用域的变量

内部作用域要修改外部作用域变量值时,全局变量要使用global关键字,嵌套作用域变量要使用nonlocal关机中,nonlocal关键字是Python3中新增的关键字,有了这个关键字就能完美的闭包了 

递归函数

  • 必须有一个明确的结束条件
  • 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
  • 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返     回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。)

但凡可以用递归写出的都可以用循环解决,递归的效率,在很多时候会很低,你可以不用,但你得会!

实例1(阶乘)

 1 def factorial(n): #根据下面调用函数传入的实参 此时 n = 5
 2     result = n  #result = n = 5
 3     for i in range(1,n):    #循环 i的值为1~5 不包括5 也就是1,2,3,4
 4         result *= i         #第一次循环为 5*1    第二次循环为5*2 第三次循环为10*3  最后一次循环为30*4
 5     return result           #第一次循环返回值为5     第二次循环值为10   第三次循环的值为30  最后一次返回值为120
 6 print(factorial(5))         #打印结果为120
 7 
 8 #------------递归----------
 9 def factorial_new(n):   #根据下面调用函数传入的实参 此时n = 3
10     if n == 1:          #判断n=1时
11         return 1        #返回1
12                        #因为递归函数函数必须要有一个明确的结束条件
13     return n*factorial_new(n-1) #返回 3*(3-1)
14 print(factorial_new(3))     #6

实例2(斐波那契数列)

 1 def fibo(n):    #调用函数是传入的实参此时的 n = 3
 2     before = 0
 3     after = 1
 4     for i in range(n - 1): #循环i的次数 3-1=2
 5         ret = before + after #第一次循环  ret = 0 + 1 = 1    第二次循环 ret = 1 = 1 = 2
 6         before = after        #第一次循环 before = 1         第二次循环   berore = 2
 7         after = ret           #第一次循环    after = 1        第二次循环  after = 2
 8     return ret      #返回的是ret的值 所以为2
 9 
10 print(fibo(3))  #2
11 #-----------递归------------
12 def fibo_new(n):    #根据下面调用函数传入的实参 此时n = 3
13     if n <= 1:      #判断n=1或<1时
14         return n    #返回n
15     return (fibo_new(n - 1) + fibo_new(n - 2))  #返回 (3-1)*(3-2)
16 
17 print(fibo_new(3))  #2

内置函数

 Built-in Functions  
abs()dict()help()min()setattr()
all()dir()hex()next()slice()
any()divmod()id()object()sorted()
ascii()enumerate()input()oct()staticmethod()
bin()eval()int()open()str()
bool()exec()isinstance()ord()sum()
bytearray()filter()issubclass()pow()super()
bytes()float()iter()print()tuple()
callable()format()len()property()type()
chr()frozenset()list()range()vars()
classmethod()getattr()locals()repr()zip()
compile()globals()map()reversed()__import__()
complex()hasattr()max()round() 
delattr()hash()memoryview()set() 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

重要的内置函数

1.filter(function,sequence)

1 def fun1(s):
2     if s != 'a':
3         return s
4 
5 ret = filter(fun1,str)
6 print(list(ret))    #ret是一个迭代器对象

对sequence中的item一次执行function(item),并将结果为Ture的item做成一个filter object的得带去返回,可以看做是过滤函数

2.map(function,sequence)

1 str = [1,2,'a','b']
2 
3 def fun2(s):
4     return s , 'dai'
5 
6 ret  = map(fun2,str)
7 print(ret)  #<map object at 0x7f496baa4898>
8 print(list(ret))    #[(1, 'dai'), (2, 'dai'), ('a', 'dai'), ('b', 'dai')]

对sequence中的item依次执行function(item),将结果组合成mao object迭代器返回,map也支持多个sequence,这就要求function特支持相应数量的参数输入

def add(x,y):
    return x+y

print(list(map(add,range(10),range(10))))

3.reduce(function,sequence,strting_value)

1 from functools  import reduce
2 def add1(x,y):
3     return x + y
4 
5 print(reduce(add1,range(1,101)))    #5050   (1+2+3....+100)
6 print(reduce(add1,range(1,101),20)) #5070   (1+2+3....+100+20)

对sequence中的item顺序迭代调用function,如果starting_value,还可以作为初始值使用

4.lambda

普通函数与匿名函数的对比

1 #普通函数
2 def add(a,b):
3     return a + b
4 
5 print(add(2,3))
6 
7 #匿名函数
8 add = lambda a,b : a + b
9 print(add(2,3))

匿名函数的命名规则,用lambda关键字标示,冒号(:)左侧表示函数接收的参数(a,b),冒号(:)右侧表示函数的返回值(a + b)

因为lambda在创建时不需要命名,所以,叫匿名函数

转载于:https://www.cnblogs.com/shuiliandong/p/8005502.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值