• Python 笔记(22)— 变量解析原则(LEGB)、浅拷贝、深拷贝


    1. 变量解析规则 (LEGB)

    当在函数中使用没有声明过的变量时,Python 的搜索顺序是:

    • 先是在函数内部的本地作用域( local
    • 然后是在上一层的函数的本地作用域(enclosing
    • 然后是全局作用域(global
    • 最后是内置作用域(build-in

    如下例子,

    • 变量 c 在局部作用域 ( local ) 被发现;
    • 变量 bparent 函数和 son 函数间( enclosing )被发现;
    • 变量 a 在全局作用域( global )被发现 ;
    • min 函数属于 Python 中 内置函数 ,所以在搜寻完 LEG 三个区域后,最终在 build-in 域被找到;
    a = 10
    def parent():
        b = 20
        def son():
            c = 30 # c: local 
            print(b + c) # b: enclosing
            print(a + b + c ) # a: global
            print(min(a,b,c)) # min : built-in 
    
        son()
    
    
    In [72]: parent()
    50
    60
    10
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    如下变量 d,在 LEGB 四个域都被搜寻一遍后,还是未找到,就会抛出 d 没有被发现的异常。

    a = 10
    def parent():
        b = 20
        def son():
            c = 30 # c: local 
            print(b + c) # b: enclosing
            print(a + b + c ) # a: global
            print(min(a,b,c)) # min : built-in 
            print(d) # 在 LEGB 四个域都未找到后,报错!
    
        son()
    
    parent()
    
    # NameError: name 'd' is not defined
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    2. 浅拷贝与深拷贝

    当使用下面的操作的时候,会产生浅拷贝的效果:

    • 使用切片操作 [:]
    • 使用工厂函数(如 listdirset
    • 使用 copy 模块中的 copy() 函数,只会复制父对象,而不会复制对象内部的子对象;

    深拷贝

    • 使用 copy.deepcopy 是深拷贝,会复制对象及其子对象;
    In [11]: import copy
    
    In [12]: a = [1,2,3, ['a', 'b']]
    
    In [13]: b = a
    
    In [14]: c = a[:]
    
    In [15]: d = copy.copy(a)
    
    In [16]: e = copy.deepcopy(a)
    
    In [17]: id(a)
    Out[17]: 62660040L
    
    In [18]: id(b)
    Out[18]: 62660040L
    
    In [19]: id(c)
    Out[19]: 62660424L
    
    In [20]: id(d)
    Out[20]: 62519944L
    
    In [21]: id(e)
    Out[21]: 62520776L
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    从上可以看出:

    1. 通过 = 赋值,它的 id 是和 a 本身是一样的;
    2. 通过 [:] 切片赋值和 copy.copy() 赋值的 id 是一样的,它们都是浅拷贝
    3. 通过 copy.deepcopy() 赋值的 id 是和其它都不一样,它是深拷贝;

    为啥叫做深拷贝,看下面。

    In [12]: a[0] = 'aaa'
    
    In [13]: a[3].append('c')
    
    In [14]: a
    Out[14]: ['aaa', 2, 3, ['a', 'b', 'c']]
    
    In [15]: b
    Out[15]: ['aaa', 2, 3, ['a', 'b', 'c']]
    
    In [16]: c
    Out[16]: [1, 2, 3, ['a', 'b', 'c']]
    
    In [17]: d
    Out[17]: [1, 2, 3, ['a', 'b', 'c']]
    
    In [18]: e
    Out[18]: [1, 2, 3, ['a', 'b']]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    增加补充查看 d 和 e 中内部子列表的 id 值。

  • 相关阅读:
    关于漏洞:检测到目标SSL证书已过期【原理扫描】
    Eyeshot 2022.3 Fem Released Crack
    蓝桥杯每日一题2023.11.9
    手把手分析 lv_config.h 文件
    由于找不到mfc100u.dll,无法继续执行代码的详细处理方法分享
    《Linux内核精通》笔记参考目录
    git切换远程仓库源步骤
    epoll 和 reactor 的关系
    RabbitMQ
    2022年全球及中国280Ah磷酸铁锂铝壳电芯行业头部企业市场占有率及排名调研报告
  • 原文地址:https://blog.csdn.net/wohu1104/article/details/125126751