函数【四】闭包/迭代器/递归

py_闭包、迭代器、递归

 

一、函数名的使用

一、函数名的使用:

返回值 函数名 (返回函数名的时候不能加括号)

函数名可以当容器的元素

函数名可以当做参数被传递

def func():
    print('func')
def func1():
    return func  # 将函数名func作为返回值,返回给了func1()
func1()()
返回值
def func1():
    print('这是func1')
def func2():
    print('这是func2')
def func3():
    print('这是func3')
li = [func1,func2,func3]
for i in li:
    i()
这是func1
这是func2
这是func3

当容器的元素
当容器的元素
def func():
    print('这里打印 func')
def test(k):
    k()
test(func)  # 将函数名当作参数传递
参数

二、闭包

   一、什么是闭包

1.首先有一个嵌套函数
2.嵌套函数内部函数调用非全局的变量
3.将内部函数名当做返回值返回,在全局调用
怎么去查看闭包??
函数名.__closure__ 返回None 就不是闭包;
二、闭包的特点
1.保护变量
2.可以让一个变量常驻内存(比如爬虫,不用每次都去重新请求网址)
三、闭包的应用
和全局变量一样,它不确定什么时间会被调用,所以会常驻内存,随时等候被调用;
例如爬虫,不用每次都去重新请求网址,重新获得数据;第一次爬取就会把你想要的数据驻留内存中,方便以后调用;
四、闭包函数示例
def test():
    url = 'www.baidu.com'
    def func():
        print(url)  # 引用外部作用域的变量
    return func     # 返回func的内存地址
res = test()
res()   # www.baidu.com
print(test())  # <function test.<locals>.func at 0x0000021AE401A950>

def func1():
    a = 10
    def func2(num):
        nonlocal a   # 可以通过关键字进行修改
        a += num
        print(a)
    return func2
func1()(100)
查看是否是闭包函数,打印结果不是None就是闭包
print(func1().__closure__)

示例代码
示例代码

 

三、迭代器

一、什么是可迭代对象

具有__iter__方法就是可迭代对象
li = [1,2,3]
a = li.__iter__()

li具有__iter__方法,所以是可迭代对象

二、什么是迭代器

同时具有__iter__方法和__next__方法的就是迭代器
for循环的机制 就是迭代器;

#优点:
  # - 提供一种统一的、不依赖于索引的迭代方式
  # - 惰性计算,节省内存
#缺点:
  # - 无法获取长度(只有在next完毕才知道到底有几个值)
  # - 一次性的,只能往后走,不能往前退
 

三、迭代器
一、什么是可迭代对象

具有__iter__方法就是可迭代对象
li = [1,2,3]
a = li.__iter__()

li具有__iter__方法,所以是可迭代对象
二、什么是迭代器

同时具有__iter__方法和__next__方法的就是迭代器
for循环的机制 就是迭代器;
#优点:
  # - 提供一种统一的、不依赖于索引的迭代方式
  # - 惰性计算,节省内存
#缺点:
  # - 无法获取长度(只有在next完毕才知道到底有几个值)
  # - 一次性的,只能往后走,不能往前退
普通
li = [1,2,3,4,6,7,87,8,9,90,0,0,0,0,8,7,7,67,]
em = li.__iter__()
while 1:
    try:
        print(em.__next__())

    except StopIteration:
        break

当出现 StopIteration 直接退出循环

异常捕获
异常捕获

四、递归

在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数,记住哦->在函数内部调用其他函数不是函数的嵌套,而在函数内部定义子函数才是函数的嵌套;

举个例子,我们来计算阶乘n! = 1 x 2 x 3 x ... x n,用函数fact(n)表示,可以看出:

fact(n) = n! = 1 x 2 x 3 x ... x (n-1) x n = (n-1)! x n = fact(n-1) x n

所以,fact(n)可以表示为n x fact(n-1),只有n=1时需要特殊处理。于是,fact(n)用递归的方式写出来就是

def fact(n):
    if n==1:
        return 1
    return n * fact(n - 1)

如果我们计算fact(5),可以根据函数定义看到计算过程如下:

复制代码
===> fact(5)
===> 5 * fact(4)
===> 5 * (4 * fact(3))
===> 5 * (4 * (3 * fact(2)))
===> 5 * (4 * (3 * (2 * fact(1))))
===> 5 * (4 * (3 * (2 * 1)))
===> 5 * (4 * (3 * 2))
===> 5 * (4 * 6)
===> 5 * 24
===> 120
复制代码

 递归函数的优点是定义简单,逻辑清晰。理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰。

使用递归函数需要注意防止栈溢出。在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。可以试试fact(1000),递归默认层次,官方说明 1000,实际测试 998/997,

1. 自己玩自己   (自己调用自己本身)
2. 玩的有限制 (有明确结束条件)
修改递归的最大层数
import sys
sys.setrecursionlimit(10000)

 示列:

复制代码
def fun(n):
    print(n)
    if n / 2 == 0:
        return n
    res = fun(int(n/2))
    return res
fun(10)

复制代码
原文地址:https://www.cnblogs.com/youxiu123/p/11480629.html