疫情环境下的网络学习笔记 python 3.20
3.20
上节课复习
- 
名称空间:存放名字的地方 名字存在栈区,值存在堆区,名称空间是对栈区的一种划分,真正存在的是栈区,名称空间只是一种虚拟的划分 - 
内置名称空间:内置的名字 
- 
全局名称空间:只要不是内置的或是函数内的,都在全局里。 if x == 1: y = 2 # y也是全局
- 
局部名称空间:函数内的名字,调用时产生,结束函数就销毁 def func(): # func名字也是全局,不是函数内的名字 a = 1 b = 2
 运行到定义函数的阶段,不会造出名称空间,调用阶段的时候才会 
- 
- 
查找顺序:从当前所外位置,向外查找 
- 
本身名称空间没有嵌套关系,只是有优先级之分 
- 
函数的使用分为定义阶段和调用阶段 名称空间的嵌套关系以定义阶段为准,无论在哪个阶段调用,查找名字都以定义阶段的位置开始 在定义阶段就确定了名字要绑定的值的地址 
- 
作用域:名字的作用范围 全局作用域 - 
包含的名字:内置名称空间,全局名称空间的名字 
- 
存活周期:全局存活,全局有效 
 局部作用域 - 函数内的名字,局部名称空间中的名字
- 临时存活,局部有效
 
- 
- 
global:声明一个名字,告诉解释器不要在局部创建新的名字,而是去操作全局的名字 用于在局部修改全局的不可变的名字,也可以在全局新建名字 
- 
nonlocal:声明一个名字,从当前层的外一层起始开始找 
正课
今日内容
- 
函数对象:可以把函数当成变量去用 
- 
函数嵌套 
- 
闭包函数 = 名称空间与作用域 + 函数嵌套 + 函数对象 核心点:名字的查找关系是以函数定义阶段为准的 
函数对象
可以把函数当作变量去用
- 
可以赋值: f = func,使 f 与func指向同一个内存地址:注意不加括号,否则f 被赋值的是函数的返回值
- 
可以把函数当作参数传入 def func(): pass def foo(x): print(x) foo(func) # 得到func的内存地址实际上是将函数的内存地址当作值传进去了 
- 
可以把函数当作另一个函数的返回值 def foo(x): # x = func的内存地址 return x # return func的内存地址 res = foo(func) print(res) # res = func的内存地址 res() # 内存地址+括号,可以调用这个内存地址里的函数
- 
可以当作容器类型的一个元素 dic = {'k1':func,'k2':func1} # 地址的value后面加括号,就可以运行这个函数 dic['k1']() # 运行func用于改进atm项目中,用字典来装一个个函数,其中字典的key为’1‘,’2‘,...,值为func def login(): pass def register(): pass def withdraw(): pass func_dic = { '1':['登陆',login], '2':['注册',register], '3':['提现',withdraw] } func_dic['1']()在打印菜单的时候用循环遍历改进菜单 while True: for i in func_dic: print(i,func_dic[i][0]) # 这样,加减功能都只用在func_dic 里操作了
函数嵌套
嵌套调用:在调用一个函数的过程中又调用其他函数,把一个大的功能拆分成一个个小的功能,组装在一起。且主程序的代码会比较精简
例子:4个值输出最大值
def max2(x,y):
	if x > y:
		return x
	else:
        return y
	
def max4(a,b,c,d):
	res = max2(a,b)
	res1 = max2(res,c)
    res2 = max(res1,d)
result = max4(1,2,3,4)
嵌套定义:如果几个函数的参数都是一个对象,可以把这些函数都定义在一个函数内,使用一个共同的局部名称空间中:封装
例子:求圆的周长 / 面积
def circle(radius,action=0):
    """
    action参数
        0:求周长
        1:求面积
    """
    # 求圆形的周长=2 * pi * radius
    from math import pi
    def perimiter(radius):
        return 2 * pi * radius
    # 求圆形的面积=pi*(radius**2)
    def area(radius):
        return pi * (radius ** 2)
    if action == 0:
        res=perimiter(radius)
    elif action == 1:
        res=area(radius)
    return res
res=circle(3,action=0)
print(res)
闭包函数
很重要
闭包函数 = 名称空间与作用域 + 函数嵌套 + 函数对象
核心点 / 原理:
- 函数的作用域关系是以函数定义阶段为准
- 将嵌套函数作为返回值输出可以打破函数层级限制来调用函数
什么是
- 定义在函数内部的函数,内嵌函数
- 该函数包含对外层函数中名字的引用,(不是对全局作用域)
- 通常将闭包函数用 return 返回,使之可以在任意位置使用
return 返回的闭包函数不仅仅有函数本身,还带着函数外层的作用域。所以无论在何处调用闭包函数,函数里使用的名字都是定义阶段包裹在其外层的变量
def f1():
	x = 1
	def f2():  # f2是一个闭包函数
		print(x) # 引用了外层的名字x
	f2()
x = 111
f1()
# 无论怎么嵌套,f2都只与他的包相联系
怎么用
可以把闭包函数的使用看作另一种传参的方式
需求:想在任意阶段调用一个内嵌函数
def f1():
    x = 3333
    def f2():
        print(x)
    f2()
    return f2  # f1返回f2函数的内存地址
f = f1  # 于是f在全局得到了局部函数的内存地址
x = 22222
f()  # 因为只与定义阶段的作用域关系有关,所以无论怎么定义x,实际上运算的x只会是f2定义时的 3333
# 3333
应用:request模块得到网页的内容,有两种方式
# 传参方案1,形参中放url
import request
def get(url):
    res = request.get(url)
    print(res.text)
    
get('https://www.baidu.com')
这样定义的时候比较方便,而在要获取不同网页内容的时候需要传入不同的url
# 传参方案2,使用闭包函数
import request
def outter(url):
	# url = 'https://baidu.com'
    def get(url):
        res = request.get(url)
        print(res.text)
    return get
		
baidu = outter('https://www.baidu.com')
baidu()
这样做定义的时候麻烦一些,不过outter的返回值是get函数,调用的时候使用一次 baidu = outter(url) ,那么baidu就相当于一个函数,再使用的时候就可以直接用 baidu()
预习
装饰器
- 
开放封闭原则:对扩展开放,对修改封闭 需要一种解决方案,在不修改源代码及调用方式的前提下为函数添加新功能 
- 
装饰器: - 器:任意可调用对象(就是函数),装饰与被装饰的对象都是函数
- 目的:在遵循开放封闭原则的前提为函数新增功能
 
- 
例子 index() 函数,延迟3秒后,打印一行字 import time def index(): time.sleep(3) print('index')现有一需求,计算index函数的运行时间,要求不改变源代码,且不改变调用方式 def timer(func): # 创建一个闭包函数的包,传入要装饰的函数 def inner(): # 闭包函数中实现新功能 start = time.time func() # 引用外层函数中的名字 func,func是作为形参传入的index 函数 stop = time.time return inner index = timer(index) # 传入参数后给闭包函数的包改名 index() #因为闭包函数使用的名字永远是在其包中的名字,所以现在无论在哪调用都是新功能,执行index实际上是执行了inner所以装饰器其实是闭包函数的一种应用场景 

 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号