Python全栈之作用域和闭包
作者:熬夜泡枸杞
这篇文章主要为大家介绍了Python作用域和闭包,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
1. return返回值
# ### return 自定义函数的返回值 """ 概念:return 把函数内部的数据返回到函数的外面,返回到函数的调用处 1.return + 六大标准数据类型 , 除此之外还可以返回函数 或者 是类对象 2.return 在执行时,意味着终止函数,后面的代码不执行. 3.如果不定义return返回值,默认返回None """ # (1) return + 六大标准数据类型 def func(): # return 111 # return 6.89 # return "你好帅啊,我爱死你乐" # return [1,2,3] # return {"a":1,"b":2} return 1,2,3 # 返回元组 res = func() print(res) # (2) return 在执行时,意味着终止函数,后面的代码不执行. def func(): print(1) print(2) return 3 print(4) res = func() print(res) def func(): for i in range(5): if i == 3: return 4 print(i) res = func() print(res) # (3) 如果不定义return返回值,默认返回None def func(): pass res = func() print(res) # None # 注意点 打印的数据和返回的数据不是等价的,返回的数据是可以自定义的; res = print(1234) print(res) # None # 模拟+-*/计算器 """ 功能: 完成计算 参数: 2个数字和运算符 返回值: 计算后的结果 """ def calc(num1,num2,sign): if sign == "+": return num1 + num2 elif sign == "-": return num1 - num2 elif sign == "*": return num1 * num2 elif sign == "/": if num2 == 0: return "除数不能为零" return num1 / num2 else: return "抱歉,超出了我的运算范围." res = calc(3,5,"+") res = calc(3,5,"-") res = calc(3,5,"*") res = calc(3,0,"/") res = calc(3,0,"&") print(res)
2. 全局变量_局部变量
# ### 全局变量和局部变量 """ 1.概念 局部变量:在函数内部定义的变量就是局部变量 全局变量:在函数外部定义的变量或者在函数内部使用global关键字声明是全局变量 2.作用域: 局部变量的作用范围仅仅在函数的内部 全局变量的作用范围横跨整个文件 3.生命周期:该变量的作用时长 内置命名空间 -> 全局命名空间 -> 局部命名空间 (开辟空间顺序) 内置属性 > 全局属性 > 局部属性 (作用时长:长->短) """ # 1 局部变量 def func(): # 定义一个局部变量 a = 1 # 获取当前的局部变量 print(a) # 修改一个局部变量 a = 2 print(a) func() # print(a) error # 2.全局变量 # 定义一个全局变量 b = 10 # 获取当前的全局变量 print(b) # 修改一个全局变量 b = 20 print(b) def func(): print(b) func() # 3.函数内部定义全局变量 def func(): global c c =30 func() print(c) # 4.函数内部修改全局变量 d = 50 def func(): global d d = 51 func() print(d) """ 总结:global的使用 如果当前不存在全局变量,可以在函数内部通过global关键字来定义全局变量 如果当前存在全局变量,可以在函数内部通过global关键字来修改全局变量 """
3. 函数名的使用
# ### 函数名的使用 """ # python中的函数可以像变量一样,动态创建,销毁,当参数传递,作为值返回,叫第一类对象.其他语言功能有限 """ def func(): print( "我是func函数") # (1)动态创建 a = 1 print(a) a = func a() # (2)动态销毁 del a # a() # func() # (3)当参数传递 def func2(): return "我是func2函数" def func1(f): return f() # "我是func2函数" res = func1(func2) print(res) # (4)作为值返回 def func3(): print( "我是func3函数" ) def func4(f): return f res = func4(func3) print(res) res() print("<===>") # (5)函数名可以作为容器类型数据的元素 lst = [func,func3] for i in lst: i() print("<=========>") # ### __doc__ 或者help查看文档 def big_chang_cishen(something): """ 功能: 教你怎么吃大肠 参数: 吃的内容 返回值: 是否满意 """ print("把{}洗一洗".format(something)) print("直接找肠子头,放嘴里,吸一下") print("擦擦嘴,满意的放下肠子头") return "吃完了,真好吃~" big_chang_cishen("生肠子") # 方法一 res = big_chang_cishen.__doc__ print(res) # 方法二 help(big_chang_cishen)
4. 函数的嵌套
4.1 函数的嵌套
# ### 函数的嵌套 """ 互相嵌套的两个函数![请添加图片描述](https://img-blog.csdnimg.cn/f3ab3fd8502e43eebd473306c0e28633.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA54as5aSc5rOh5p645p2e,size_20,color_FFFFFF,t_70,g_se,x_16) : 包裹在外层的叫做外函数,内层的就是内函数 """ def outer(): # inner() def inner(): print("我是inner函数") """""" # (1)内部函数可以直接在函数外部调用么 不行 # inner() # (2)调用外部函数后,内部函数可以在函数外部调用吗 不行 # outer() # inner() # (3)内部函数可以在函数内部调用吗 可以 outer() # (4)内部函数在函数内部调用时,是否有先后顺序 有的 # 先定义在调用 # 在其他语言中有预加载的机制,提前把函数驻留到内存中,然后再去编译脚本内容 # python没有预加载函数的机制,只能先定义在调用; # 外函数是outer 中间函数是inner 最里层是smaller ,调用smaller函数 def outer(): def inner(): def smaller(): print("我是smaller函数") smaller() inner() outer() # LEGB 原则 def outer(): def inner(): def smaller(): print(a) smaller() inner() outer() """ LEGB原则(就近找变量原则) #找寻变量的调用顺序采用LEGB原则(即就近原则) B —— Builtin(Python);Python内置模块的命名空间 (内建作用域) G —— Global(module); 函数外部所在的命名空间 (全局作用域) E —— Enclosing function locals;外部嵌套函数的作用域(嵌套作用域) L —— Local(function);当前函数内的作用域 (局部作用域) 依据就近原则,从下往上 从里向外 依次寻找 """
4.2 nonlocal的使用
# ### nonlocal的使用 (用来修改局部变量) """ nonlocal遵循LEGB原则 (1) 它会找当前空间上一层的变量进行修改 (2) 如果上一层空间没有,继续向上寻找 (3) 如果最后找不到,直接报错 """ # (1)它会找当前空间上一层的变量进行修改 def outer(): a = 10 def inner(): nonlocal a a = 20 print(a) inner() print(a) outer() # (2)如果上一层空间没有,继续向上寻找 def outer(): a = 20 def inner(): a = 15 def smaller(): nonlocal a a = 30 print(a) smaller() print(a) inner() print(a) outer() # (3)如果最后找不到,直接报错 """nonlocal 只能修改局部变量,""" """ a = 20 def outer(): def inner(): def smaller(): nonlocal a a = 30 print(a) smaller() print(a) inner() print(a) outer() error """ # (4) 不通过nonlocal 是否可以修改局部变量呢?ok def outer(): lst = [1,2,3] def inner(): lst[-1] = 3000 inner() print(lst) outer()
5. 闭包函数的定义
# ### 闭包函数 """ 互相嵌套的两个函数,如果内函数使用了外函数的局部变量 并且外函数把内函数返回出来的过程,叫做闭包 里面的内函数叫做闭包函数 是不是闭包? 1.内函数用了外函数的那个局部变量 2.外函数返回内函数 """ # 1.基本语法形式 def zhaoshenyang_family(): father = "马云" def hobby(): print("我对钱没有一丝丝的兴趣,我不看重钱,这是我爸爸{}说的".format(father)) return hobby func = zhaoshenyang_family() func() print("<==1==>") tup = func.__closure__ print(tup[0].cell_contents) # 马云 print(tup) print("<==2==>") # 2.闭包的复杂形式 def zhaowanli_family(): gege = "王思聪" didi = "鞋王,高振宁" money = 1000 def gege_hobby(): nonlocal money money -= 500 print("我交朋友不在乎他有没有钱,反正都没有我有钱.我就喜欢交女朋友... 钱物还剩下{}".format(money)) def didi_hobby(): nonlocal money money -= 400 print("家里有鞋柜,各式各样的奢侈鞋,一双大概20~30万,钱物还剩下{}".format(money)) def big_master(): return [gege_hobby,didi_hobby] return big_master func = zhaowanli_family() print(func) lst = func() print(lst) # 获取哥哥函数 gege = lst[0] gege() # 获取弟弟函数 didi = lst[1] didi() # 3.使用 __closure__ , cell_contents 判定闭包 """如果返回的元组中有数据说明是闭包,谁的生命周期被延长就打印谁""" tup = func.__closure__ print(tup) # 先获取第一个单元格 cell_contents获取对象中的内容 func1 = tup[0].cell_contents print("<11111>") """打印闭包函数didi_hobby中,生命周期被延长的属性""" print(func1.__closure__[0].cell_contents) func1() # 在获取第二个单元格 cell_contents获取对象中的内容 func2 = tup[1].cell_contents print("<22222>") """打印闭包函数gege_hobby中,生命周期被延长的属性""" print(func2.__closure__[0].cell_contents) func2()
6. 闭包的特点_意义
# ### 闭包特点 """ 特点:在闭包函数中,内函数使用了外函数的局部变量, 该变量会与内函数发生绑定,延长该变量的生命周期, 持续到脚本执行结束. """ def outer(val): def inner(num): return val + num return inner func = outer(10) res = func(15) print(res) # ### 闭包的意义 """全局变量的作用域大,容易被篡改""" num = 0 def click_num(): global num num += 1 # num = num + 1 print(num) click_num() click_num() click_num() num = 100 click_num() click_num() # 改造,用闭包来实现 """ 闭包的意义: 闭包可以优先使用外函数中的变量,并对闭包中的值起到了封装保护的作用.外部无法访问. """ def outer(): x = 0 def click_num(): nonlocal x x += 1 print(x) return click_num click_num = outer() click_num() click_num() click_num() x = 100 click_num() click_num()
小提示:
def outer(): a = 10 def inner(): a = 20 print(a) inner() print(a) outer() 这里的输出结果是20 10,嵌套里的两个a变量互不干扰 列表可以直接可以在内外函数直接传递值,修改列表 的时候不需要使用nolocal来修改变量的值。 闭包可以延长局部变量的周期 没办法在函数的内部去修改一个全局变量的,必须通过一个global(跟nonlocal一个道理的)
7. 小练习
# # 1.定义函数:接收任意个参数,打印其中的最小值 def func(*args): lst = [] for i in args: if isinstance(i , (float,int)): lst.append(i) print(lst) return lst[0] res = func(-100,1,2,423,"sdf") print(res) # 2.定义函数:传入一个参数n,返回n的阶乘(5! = 5*4*3*2*1) def func(n): total = 1 for i in range(n,0,-1): total *= i return total print(func(5)) # 3.写函数,传入函数中多个实参(均为可迭代对象如字符串,列表,元祖,集合等) # # 将容器中的每个元素依次添加到新的列表中返回 #例:传入函数两个参数[1,2,3] (22,33)最终args为(1,2,3,22,33) # 方法一 def func(*args): lst =[] for i in args: for j in i: lst.append(j) return lst res = func([1,2,3],(5,6,7),"abc") print(res) # 方法二 def func(*args): return list(args) res = func(*[1,2,3],*(5,6,7),*"abc") print(res) # 4.写函数,用户传入要修改的文件名,与要修改的内容,执行函数,修改操作 # 方法一 def func(filename,str1,str2): with open(filename,mode="r+",encoding="utf-8") as fp: strvar = fp.read() print(strvar) res = strvar.replace(str1,str2) with open(filename,mode="w+",encoding="utf-8") as fp: fp.write(res) func("ceshi2.py","内置函数","外置函数") # 方法二 def func(filename,str1,str2): with open(filename,mode="r+",encoding="utf-8") as fp: strvar = fp.read() res = strvar.replace(str1,str2) # print(fp.tell()) fp.seek(0) # 清空 fp.truncate() fp.write(res) func("ceshi2.py","外置函数","内置函数") # 5.写函数,计算传入字符串中【数字】、【字母】、【空格] 以及 【其他】的个数 # 方法一 def func(strvar): dic = {"num":0,"word":0,"space":0,"other":0} for i in strvar: if i.isdecimal(): dic["num"] += 1 # dic["num"] = dic["num"] + 1 elif i.encode().isalpha(): dic["word"] += 1 elif i.isspace(): dic["space"] += 1 else: dic["other"] += 1 return dic # strvar = input("请输入字符串") # print(func(strvar)) """ print("你".isalpha()) # 中文 => False print("你".encode().isalpha()) # 字母 => True print("a".encode().isalpha()) """ # 方法二 def func(strvar): dic = {"num":0,"word":0,"space":0,"other":0} lst = [] for i in range(97,123): lst.append(chr(i)) lst.append(chr(i-32)) for i in strvar: if i in "0123456789": dic["num"] += 1 elif i in lst: dic["word"] += 1 elif i == " ": dic["space"] += 1 else : dic["other"] += 1 return dic # strvar = input("请输入字符串") # print(func(strvar)) # 6.写函数,检查字典的每一个value的长度,如果大于2,那么仅保留前两个长度的内容,返回处理后的结果. #例:参数为:dic = {"k1": "v1v1", "k2": [11,22,33,44]} def func(dic): if isinstance(dic,dict): for k,v in dic.items(): print(k,v) dic[k] = v[:2] return dic else: return "不是字典" dic = {"k1": "v1v1", "k2": [11,22,33,44]} print(func(dic)) print(func([1,23,42,34,23,4234])) # 7传入多个容器类型数据,计算所有元素的个数 def func(*args): total = 0 for i in args: print(i) total += len(i) return total res = func("123",[5,6,7],("你好","123423")) print(res) # 改造,不去判断字符串本身的长度 def func(*args): total = 0 for i in args: print(i) if isinstance(i,str): total += 1 elif isinstance(i,(tuple,list,set,dict)): total += len(i) return total res = func("123",[5,6,7],("你好","123423")) print(res)
总结
本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注脚本之家的更多内容!