一、变量的作用域
1.出现的原因
变量的作用域:变量可以被使用【被访问】的范围
程序中的变量并不是在任意的语句中都可以被访问,访问权限取决于这个变量被定义在哪个位置
在python中 分支语句 if..else if.. 和 循环for 等 是不存在变量作用域问题的.
if5>4:a=11print(a)foriinrange(10):b=32print(b)# 在 分支结构中if.. if..esle 和 循环中for in 不存在作用域的问题.# 在他们的外面可以直接访问里面定义的变量.deffn():c=99# print(c) # name 'c' is not defined
2.作用范围划分
局部作用域:L【Local】
函数作用域:E【Enclosing】 将变量定义在闭包外的函数中
全局作用域:G【Global】
內建作用域:B【Built-in】
代码演示:
deffn():c=99# print(c) # name 'c' is not defined# 1.函数内部定义的变量在函数外部不能访问.# 全局作用域:num1=12# 全局作用域,在函数内部和外部可以直接访问deftest():num2=87# 函数作用域print(num1)# print(num3) # name 'num3' is not defineddefinner():num3=55# 局部作用域# 在内部函数中,可以访问全局作用域\函数作用域\局部作用域的变量print(num1,num2,num3)returninnertest()print(num1)# print(num2)fn=test()fn()n=int("28") # builins 内置函数在调用的时候的作用域,这是python解释器自己定义的.总结:1.在分支结构中if.. if..esle和循环中forin不存在作用域的问题.在他们的外面可以直接访问里面定义的变量.2.作用域主要体现在函数中, 函数内部定义的变量在函数外部不能访问.3.函数内部可以访问函数外部的变量.3.全局变量和局部变量
全局变量:将变量定义在函数的外面
局部变量:将变量定义在函数的内部
注意:局部变量只能在其被声明的当前函数中使用,而全局变量可以在整个程序中使用
4.global和nonlocal关键字的使用
使用场景:当内部作用域【局部作用域,函数作用域】想要修改全局变量的作用域的时候
1.global
代码演示:
num=11deftest():num=78print(num)test() # 78print(num) # 11# 若想在函数的内部,对全局变量进行修改,需要使用global关键字num1=11deftest1():# 通过global关键字将函数内部声明变量变为了全局变量globalnum1num1=75print(num1)test1() # 75print(num1) # 75
nonlocal
代码演示:
# nolocal 关键字主要用于闭包函数中 # nolocal关键字用于闭包函数中x=15# 全局变量defouter():x=19definner():# x = 23# global x # 使用的是 x = 15nonlocalx# 这时候使用的变量是 x = 19x+=1print("inner:",x)returninner# 闭包会保存住当前的运行环境test=outer()test() # 20test() # 21test() # 22num=11defdemo():print(num)demo() # 11demo() # 11demo() # 11二、闭包和装饰器
如果在一个函数的内部定义另外一个函数,外部的函数叫做外函数,内部的函数叫做内函数
如果在一个外部函数中定义一个内部函数,并且外部函数的返回值是内部函数,就构成了一个闭包,则这个内部函数就被称为闭包【closure】
实现函数闭包的条件:
1.必须是函数嵌套函数
2.内部函数必须引用一个定义在闭合范围内的外部函数的变量,----内部函数引用外部变量
3.外部函数必须返回内部的函数
代码演示:
1.闭包
# 闭包: 如果在一个外部函数中定义一个内部函数,并且外部函数的返回值是内部函数,就构成了一个闭包,则这个内部函数就被称为闭包【closure】# 最简单的闭包# 外部函数defouter():# 内部函数definner():print("lala")returninner# 将内部函数返回fn=outer() # fn =====> inner函数fn() # 相当于调用了inner函数 输出 lala# 内部函数使用外部函数的变量defouter1(b):a=10definner1():# 内部函数可以使用外部函数的变量print(a+b)returninner1fun1=outer1(12)fun1()'''注意:1.当闭包执行完毕后,仍然能够保存住当前的运行环境2.闭包可以根据外部作用域的局部变量得到不同的效果,类似于配置功能,类似于我们可以通过修改外部变量,闭包根据变量的改变实现不同的功能.应用场景: 装饰器'''2 装饰器:
在代码运行期间,可以动态增加函数功能的方式,被称为装饰器【Decorator】 通过闭包函数实现
也就是说,在不修改原函数的基础上,给原函数增加功能
好处:在团队开发中,如果两个或者两个以上的程序员会用到相同的功能,但是功能又有细微的差别,采用装饰器:相互不影响,代码简化
2.1装饰器
代码演示:
# 原函数deftest():print("你好啊!")# 需求: 给上面的函数test增加一个功能, 输出 我很好# 第三种方式: 通过装饰器的方式给函数追加功能 装饰器使用闭包实现'''闭包函数:1.函数嵌套函数2.内部函数使用外部函数的变量3.外部函数中返回内部函数'''# a.书写闭包函数 此处的outer函数就是装饰器函数defouter(fn): # b. fn表示形参, 实际调用的时候传递的是原函数的名字definner():fn() # c.调用原函数# d. 给原函数添加功能, 注意:添加的功能可以写在原函数的上面也可以写在原函数的下面print("我很好")returninnerprint("添加装饰器之前:",test,__name__) test=outer(test)print("添加装饰器之后:",test,__name__) # test()# 总结:# 1.在装饰器中,给原函数添加的功能,可以写在原函数的上面,也可以写在原函数的下面# 2.outer 函数就是我们的装饰器函数2.2系统的简写
代码演示:
# a.书写闭包函数 此处的outer函数就是装饰器函数defouter(fn): # b. fn表示形参, 实际调用的时候传递的是原函数的名字definner():fn() # c.调用原函数# d. 给原函数添加功能, 注意:添加的功能可以写在原函数的上面也可以写在原函数的下面print("我很好") returninner# test = outer(test)# 装饰器的简写方式 @ + 装饰器名称@outer# 等价于 =====>test = outer(test)deftest():print("你好啊!")test()'''注意:1.在使用装饰器的简写方式的时候,原函数必须在装饰器函数的下面2.outer就是装饰器函数. @outer等价于 test = outer(test)'''2.3不定长参数的装饰器(通用装饰器)
代码演示:
# 同一个装饰器装饰多个函数defjisuan(fn):definner(*args):print("数学运算的结果是:",end=" ")fn(*args)returninner@jisuandefadd(a,b):print(a+b)add(12,34)@jisuandefcha(a,b,c):print(a-b-c)cha(100,23,26)