locals和globals,函数的嵌套,nonlocal,闭包函数及特点以及匿名函数---day11

1.locals和globals

1.1locals  获取当前作用域中的所有内容

locals 如果在函数外,调用locals(),获取打印的是打印之前的所有变量,返回字典,全局空间作用域
locals 如果在函数内,调用locals(),获取的是调用之前的所有变量,返回字典,局部空间作用域

#例子1

a = 1
b = 2
res = locals()
c = 3 
print(res)  #打印前面所有的变量的值,返回一个字典
d = 4  #不打印

a = 1
def outer():
    def inner():
        return 'www'
    inner()
res = locals()
b = 2
c = 4
print(res) #打印前面所有全局变量,返回一个字典
d = 5  #不打印

#例子2
a = 1
def func():
    b = 2     #这个是调用之前的局部变量
    res =locals()  #这个是调用
    c = 3
    print(res)#打印的是调用之前的局部内的变量是b = 2,返回字典形式{'b':2},
    d = 4
func()


a = 1
def outer():
    b = 2  #不会打印外函数的局部变量b=2
    def inner():
        c = 4  #内函数的局部变量
        e = 6  #内函数的局部变量
        res = locals() 调用
        d =4
        print(res) # 打印内函数的局部变量返回{'c':4,'e':6}
    inner()
outer()

  

1.2globals 获取全局作用域的所有内容

globals 如果在函数外,调用globals(),获取打印的是打印之前的所有全局变量,返回字典,全局空间作用域
globals 如果在函数内,调用globals(),获取打印的是调用之前的所有全局变量,返回字典,全局空间作用域

#例子3
a = 5
b = 6
res = globals()
c = 7
print(res) #打印之前的所有变量 返回字典形式
d = 8 #不打印 该变量在打印之后

a = 1
def outer():
    def inner():
        return 'www'
    inner()
res = globals()
b = 2
c = 4
print(res) #打印前面所有全局变量,返回一个字典
d = 5  #不打印

 #例子4
 a = 10  #全局变量
 def func():
    b = 11
    c =12
    res = globals()  #调用
    d = 13
    print(res)#打印出的是调用之前的所有全局变量{'a':10,'ff':33}
ff = 33  #全局变量
func()   #执行函数
zz = 50  #不打印,因为这是在整个func函数全部执行完才定义的全局全局变量

  

1.3globals返回的是系统的字典

#1.正常方式定义变量
zhangsan = '112233'


#2.通过系统的全局字典添加键值对,可以动态创建全局变量
dic =globals()
print(dic) ##{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000000001DEA2B0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/pythonproject/python_all/ceshi/day_01.py', '__cached__': None, 'dic': {...}}


# 传递字符串 ,创建一个变量
 k = 'liuwei'
 dic[k] = '刘伟'  #键值对添加'liuwei':'刘伟'
 print(liuwei)  #通过键取值


#3.批量创建全局变量 在函数中
def func():
    dic = globals()
    for i in range(1,6):
        dic['p%d'%(i)] = i  #p1 p2 p3 p4 p5 p6
func()
print(p1)  #1
print(p2)  #2
print(p3)  #3
print(p4)  #4
print(p5)  #5

  

2.函数的嵌套

函数的嵌套:
    嵌套在函数的外边叫作外函数
    嵌套在函数的里面叫作内函数
def outer():
    def inner():
        print('我是inner 函数')
    inner()
    
outer()


#inner()
(1)内部函数可以直接在函数外部调用吗?  不可以
(2)调用外部函数后,内部函数可以在函数外部调用吗? 不可以
(3)内部函数可以在函数内部调用吗?  可以
(4)内部函数在函数内部调用时,是否由先手顺序? 有(必须先定义再调用)

#最外层outer,中间层inner,最里层smaller,调用smaller,执行里面的代码
def outer():
    def inner():
        def smaller():
            print(id)  #找的是内置的
            print('我是smaller函数')
        smaller()
    inner()
outer()

# LEGB 原则(即就近找变量的原则)
#找寻变量的调用顺序采用LEGB原则(就近原则)
'''
B —— Builtin(Python) python内置模块的命名空间(内键作用域)
G —— Global(module)  函数外部所在的命名空间  (全局作用域)
E —— Enclosing function locals;外部嵌套函数的作用域 (嵌套作用域)
L —— Local(function); 当前函数内的作用域    (局部作用域) 
依据就近原则,从下往上 从里向外,依次寻找
'''

  

3.nonlocal

nonlocal 关键字 用来更改局部变量
nonlocal  遵循LEGB原则
(1)nonlocal  专门用来修改当前作用域上一级的局部变量
(2)如果上一级找不到,那么就继续向上寻找
(3)全部找不到,直接报错 (不涉及全局变量)

#(1) nonlocal 专门用来修改当前作用域上一级的局部变量
def outer():
    a = 10
    def inner():
        nonlocal a
        a = 20
    inner()
    print(a)  #a = 20
outer()

#(2) 如果上一级找不到,那么久继续向上寻找
'''nonlocal 只能修改局部变量'''
def outer():
    a = 41
    def inner():
        def smaller():
            nonlocal a
            a = 42
            print(a)
        smaller()
        print(a)  #42
    inner()
    print(a) #42
outer()

#(3) 全部找不到,直接报错
a = 41
def outer():
    def inner():
        def smaller():
            nonlocal a  #找不到局部变量a  报错
            print(a)
        smaller()
        print(a)
    inner()
    print(a)
outer()


#(4) 不使用nonlocal 是否可以修改局部变量呢?
def outer():
    lst = [1,2,3]
    def inner():
        lst[-1] = 52
    inner()
    print(lst)
outer()

#当局部中有可变数据类型时,可以不使用nonlocal来修改全局变量
def outer():
    dic = {'a'1,'b':2}
    def inner():
        dic['a'] = 5
    inner()
    print(dicvar)
outer()


#注意点  两者之间的区别
#第一种  这种是在函数内修改局部变量
def outer():
    a = 10
    def inner():
        nonlocal a
        a = 2
        print(a)  #a = 2
    inner()
    print(a)  # a = 2
outer()
#第二种  这种是在函数内自己又定义了一个变量a,与外函数的局部变量不是同一个
def outer():
    a = 10
    def inner():
        a = 2
        print(a)  # a = 2
    inner()
    print(a)  # a = 10
outer()

  

4.闭包函数

闭包函数:
闭包函数:
    内函数使用了外函数的局部变量
    外函数将内函数返回出来的过程 叫作闭包
    里面的内函数叫作闭包函数
#(1) 闭包函数用法
def wz_family():
    father = '马云'
    def mayun_hobby():
        print('{0}不在乎钱'.format{father})
    return mayun_hobby
# res = mayun_hobby  <====> res() = mayun_hobby() 
res = wz_family()
print(res)  #打印出来的是一个函数内存地址
res()  #加括号相当于调用函数
解析:
wz_family调用函数拿一个变量res接收,返回mayun_hobby,res = mayun_hobby,
内部函数mayun_hobby需要mayun_hobby加()执行,就可以用res()执行内部函数

#(2) 升级
def liuwei_familt():
    father = '刘德华'
    jiejie = '刘亦菲'
    meimei = '杨颖'
    money = 1000
    
    def jiejie_hobby():
        nonlocal money
        money  -= 600
        print('穷的没钱了,还剩%s元'%(money))
        
    def meimei_hobby():
        nonlocal money
        money -=200
        print('我比你还穷,只剩下%s元'%(money))
        
    def big_master():
        return [jiejie_hobby,meimei_hobby]
        
    return big_master
    
func = liuwei_familt()  #返回的big_master
print(func)
res = func() #相当于调用了big_master()
print(res)  #返回回来的是[jiejie_hobby,meimei_hobby]
    
#分别获取姐姐,妹妹这两个函数
jiejie = res[0]
jiejie() #相当于调用jiejie_hobby函数
meimei =res[1]
meimei()#相当于调用meimei_hobby函数

    
# ### 获取闭包函数使用的变量 __closure__,cell_contents(了解)
tup = func.__closure__
print(tup)
#(<cell at 0x0000000001E15618: function object at 0x0000000001E99AE8>,
# <cell at 0x0000000001E15678: function object at 0x0000000001E99B70>)

#cell_contents  #功能获取单元对象里面的内容
jiejie = tup[0].cell_contents
meimei = tup[1].cell_contents
print(jiejie)
#<function weifuqiang_family.<locals>.jiejie_hobby at 0x0000000001E99AE8>
jiejie()
meimei()

  

5.闭包特点

闭包特点:
  内函数使用了外函数的局部变量,该局部变量与内函数发生绑定,延长该变量的生命周期
#函数的定义处
def outer(var):  #var = 5
    def inner(num):
        return num+var #num = 4
    return inner
    
# 函数的调用处
func = outer(5)
res = func(4) # ==> inner()
print(res)
解析:
1.实参5 和形参var一一对应  进行接收val = 5
因为内函数inner 和 val进行绑定,延长了val变量的生命周期,不释放
func = outer(5)  <====> func = inner
2,实参4  和形参num一一对应 进行接收num= 4
return num + val <===> 4+5 = 9

闭包的意义
闭包可以优先使用外函数的局部变量
局部变量在函数外部不能被直接使用
对局部变量实现了保护的作用,外部无法访问

#模拟鼠标点击操作

#方法一
click_num = 0
def click_func():
    global click_num
    click_num +=1
    print(click_num)
    
click_func()  #1
click_func()  #2
click_func()  #3
click_num = 100  #在函数内部声明click_num为全局变量并修改,所以在函数外部也可以修改这个全局变量
click_func()  #101

#方法二
def outer():
    click_num = 0
    def inner():
        nonlocal click_num  #定义click_num是一个局部变量,在函数局部内有这个变量
        click_num +=1
        print(click_num)
    return inner
#click_func = inner
click_func = outer()
click_func()  #1
click_func()  #2
click_func()  #3
click_num = 100  #在函数外部不能修改局部内变量
click_func()  #4
解析:
闭包函数:
首先外函数的局部变量click_num为0,内函数想修改外函数的局部变量就需要用nonlocal声明
然后才能修改
click_num = 100在函数外部不能修改函数内部的局部变量

  

6.匿名函数

匿名函数 lambda 表达式
用一句话来表达只有返回值的函数  特点:简洁,高效,方便
语法结构:
    lanbda 参数:返回值

#(1)  无参的lambda表达式
def func():
    return '我是大哥'

#改成lambda表达式
func = lambda : '我是大哥'
res  =  func()
print(res)

#(2) 有残的lambda 表达式
def func(n):
    return type(n)
    
#用lambda表达式
func = lambda n : type(n)
res =func()
print(res)

#(3) 带有判断条件的lambda表达式
def func(n):
    if n%2 == 0:
        return '偶数'
    else:
        return '奇数'

三元(三目)运算符
真值 if 条件表达式 else 假值
如果条件表达式成立 为真 返回真值
如果条件表达式不成立 为假 返回假值

n = 20
res '偶数' if n%2 == 0 else '奇数'
print(res)

#lambda表达式
func = lambda n : '偶数' if n %2==0 else '奇数'
res = func()
print(res)

#练习
def func(x,y):
    if x>y:
        return x
    else:
        return y

func = lambda x,y : x if x>y else y
res = func(22,5)
print(res)

  

总结:今天主要讲了以下个点,locals和globals的用法,函数的嵌套,nonlocal,闭包函数及其特点以及匿名函数

locals:获取当前作用域中的所有内容

locals 如果在函数外,调用locals(),获取的是打印之前的所有变量,返回字典,全局空间作用域

locals 如果在函数内,调用locals(),获取的是调用之前的所有变量,返回字典,局部空间作用域

globals  获取全局作用域的所有内容

globals 如果在函数外,调用globals(),获取的是打印之前的所有全局变量,返回字典,全局空间作用域

globals 如果在函数内,调用globals(),获取的是调用之前的所有全局变量,返回字典,全局空间作用域

用globals可以通过系统的全局字典添加键值对,可以动态创建全局变量,也可以批量创建全局变量

函数的嵌套:

嵌套在函数的外边叫作外函数

嵌套在函数的里面叫作内函数

内部函数不可以直接在函数外部调用

调用外部函数后,内部函数不可以在函数外部调用

内部函数可以在函数内部调用

内部函数在函数内部调用时,有先后顺序(必须先定义再调用)

还讲了LEGB原则就是就近变量的原则,从下往上,从里向外

nonlocal 通用遵循LEGB原则:

专门用来修改当前作用域上一级的局部变量

如果上一级找不到,那么就继续向上寻找

全部找不到,直接报错 (不涉及全局变量)

不使用nonlocal可以修改局部变量,当外函数的局部变量是可变数据类型时,内函数可以不用nonlocal来修改局部变量

闭包函数:

内函数使用了外函数的局部变量

外函数将内函数返回出来的过程 叫作闭包

里面的内函数叫作闭包函数

还讲了两个获取闭包函数的函数,__closure__,cell_contents

闭包的特点:

内函数使用了外函数的局部变量 该局部变量与内函数发生绑定 延长该变量的生命周期

闭包可以优先使用外函数的局部变量
局部变量在函数外部不能被直接使用
对局部变量实现了保护的作用,外部无法访问

匿名函数:用一句话来表达只有返回值的函数  特点:简洁,高效,方便

语法结构:
lanbda 参数:返回值

三元运算符:

真值 if 条件表达式 else 假值
如果条件表达式成立 为真 返回真值
如果条件表达式不成立 为假 返回假值

原文地址:https://www.cnblogs.com/weiweivip666/p/12886126.html