#<center style=color:red>高阶函数的定义:一个函数可以接收另一个函数作为参数
 ##闭包是函数编程中最重要的内容
     def test():
         print('函数')
     # test()  #正常的函数调用
     #高阶函数的调用
     a=test
     a()
 ####<center style=color:gray>创建 函数后会生成一个地址,也会生成一个变量test,它接收的就是这个函数对象的地址,创建的a也是变量,等同test的对象地址!所以也能这样去调用,对象传递的也就是地址,将地址传给别人让别人来进行操作
 ##<center style=color:orange>test2就是高阶函数
     def test():
         print('函数')
     #接收参数 func是形参地址 test是实参地址
     def test2(func):
         print('先执行')
         #调用test函数
         func()
     #地址赋值给变量a
     a=test
     #调用test2函数并传递a的地址
     test2(a)
 #将函数作为参数的传递
     def test():
         print('函数')
     #接收参数 func是形参地址 test是实参地址
     def test3(a,b):
         print(f'a的值为:{a},b的值为:{b}')
     def test2(func,*args):
         print('先执行')
         #func是调用的test函数
         func(*args)
     #地址赋值给变量a
     a=test
     #调用test2函数并传递a的地址
     test2(a)
     #调用test3,并传递两个参数
     test2(test3,100,200)

 ##复习lambda表达式
 ##基本语法 lambda也是高阶函数
 ## lambda args1,args2……:表达式
     f=lambda a,b:a+b
     print(f(1,2))
 #<center style=color:blue>闭包!!重点!!
 ##<center style=color:green>闭包就是一个封闭的包,它是由若干个自由变量和内部函数组成的
 ##<center style=color:orange>自由变量:就是内部函数使用外部函数的变量就变为了自由变量
 #<center style=color:red>闭包的特点
 ####<span style=color:blue>1:闭包是一个函数,而且存在于另一个函数当中
 ####<span style=color:blue>2:闭包可以访问到父级函数的变量,且该变量不会销毁

 #####闭包的概念 
 #函数作用域是封闭的 外部的执行是访问不了它的 但闭包具有这个能力和权限
 #闭包是一个函数,只不过可以访问到另一个函数的作用域
 #函数的自由变量的总和就是一个闭包
 #<center style=color:orange>简单闭包 原理 
     def outer():
         print('外部函数')
         def inner():
             print('内部函数')
         return inner
     #这里给的是执行后的结果
     a=outer()
     print('_'*20)
     a()

 #第一个闭包 程序 
     def outer():
         print('外部函数')
         #这里定义的是自由变量
         aa=1
         def inner():
             nonlocal aa
             print('内部函数')
             print(f'a:{aa}')
             aa+=1
         return inner
     #这里给的是执行后的结果
     a=outer()
     print('_'*20)
     a()
     a()
     a()
 #闭包函数返回值详解
     def outer(num1):
         def inner(num2):
             # 这里的返回值给了inner
             return num1+num2
         return inner
     a=10
     b=20
     inner=outer(a)
     resp=inner(b)
     print(resp)
 #这里nonlocal
     内部函数和外部函数使用同一个变量,就不能声明成本地变量。
     nonlocal的意思是外部函数和内部函数使用的变量相同。
     如果不使用nonlocal内部的aa就是内部变量,和外部不会产生关联。
 #闭包的作用
 ####1:起到全局变量的作用,隐藏变量,避免全局污染
 ##2:可以读取函数内部的变量
 #示例:使用全局变量自增后污染了全局变量
     a = 10
     def add():
         global a
         a+=1
         print("a:",a)
     def print_ten():
         if a==10:
             print("ten!")
         else:
             print("全局变量a,不等于10")
     if __name__=='__main__':
         add()
         add()
         add()
         print_ten()
 #定义局部变量,但无法实现自增
     a = 10
     def add():
         a = 10
         a += 1
         print("a:",a)
     
     def print_ten():
         if a==10:
             print("ten!")
         else:
             print("全局变量a,不等于10")
     
     add() #每次调用都会清空内存 所以 无法实现自增效果
     add()
     add()
     print_ten()
 ###<span style=color:blue>通过闭包,可以是函数内部局部变量递增,也不会影响全部变量
     a = 10
     def add():
         a=10
         def inner():
             #声明自由变量
             nonlocal a
             print(f'a:{a}')
             a+=1
         #这里注意不能去调用
         return inner    
     def print_ten():
         if a==10:
             print(f"ten!{a}")
         else:
             print("全局变量a,不等于10")
     
     inner=add()
     inner()
     inner()
     inner()
     print_ten()

 #闭包实现不修改源码实现添加功能_装饰器的基础(重要)
     def outer(func):  #接收func1的形参
         def inner():
             func()
             print('新增功能')
         return inner #返回内部函数名
     def func1():
         print('原有功能')
     #讲func1的地址赋给fun
     fun=outer(func1)
     #调用函数
     fun()  #这里就是内部函数名

 #map函数的使用
 ###map将传入的函数依次作用到序列的每个元素,并把结果作为新的list返回
 ###函数接收:一个是函数,多个序列
 #map函数示例
     def f(x):
         return x * x
     L=map(f,[1, 2, 3, 4, 5, 6, 7, 8, 9])
     print(type(L))
     #因为是map类型所以要转换为列表
     print(list(L))
 ###不用map函数也可以做到同样的效果
     l=[]
     def a():
         for i in range(10):
             l.append(i*i)
     a()
     print(l)
 ##map函数列表相加 
     def f2(x,y):
         return x+y
     L=map(f2,[1,2,3,4],[10,20,30,40])
     print(list(L))
 #在不修改源代码的前提下 增加新的功能 闭包的高级用法
 #开闭功能
     import time
     def writedun():
         try:
             f=open('log.txt', 'a', encoding='utf-8')
             f.write(__name__)
             f.write('\t')
             f.write(time.asctime())
             f.write('\n')
         except Exception as e:
             print(e.args)
         finally:
             f.close()
             #fun这个形参接收的是func1这个实参函数 只是赋给了地址信息
     def funcout(fun):
         def funcin():
             writedun()
             fun()
         return funcin
     def func1():
         print('我是功能1')
     def func2():
         print('我是功能2')
     #闭包的调用  #我是傻逼
     a=funcout(func1) #把func1重新赋值
     b=funcout(func2)
     #开始调用 闭包中的funcin函数 走writedun函数之后调用func1函数打印功能
     a()
     b()