• python 参数内存地址相关


    查看下某个值的在内存中的地址

    v1 = 'vincent'
    print(id(v1))
    
    v2 = [11,22,33]
    v3 = [11,22,33]
    print( id(v2) )
    print( id(v3) )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    我们需要知道的是当函数执行传参时,传递的是内存地址。验证:

    def func(data):
        print(data, id(data)) # vincent 2398921260720
    
    v1 = 'vincent'
    func(v1)
    
    print(id(v1)) # 2398921260720 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    可以看出传递的是内存地址。

    Python参数传递的特性好处是什么?

    • 主要是可以节省内存。如果执行函数时,每执行一次都要创建一个数据进行传递,那么有可能会将同一个数据创建很多遍,浪费内存空间。
    • 当传递内存地址的时候,可以让函数帮我们对值的修改。例如:
    def func(data):
        data.append(44)
    
    v = [11,22,33]
    func(v)
    print(v)  # [11, 22, 33, 44]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    因为vdata指向了同一块内存,所以v的值发生了变化。

    不过需要注意的是,要想实现对值的修改,参数必须是可变类型(list/dict/set),在函数内部只能对内部元素进行修改。

    例如:

    def func(data):
        data.upper() # str是不可变类型,无法进行修改
    
    v = 'vincent'
    func(v)
    print(v) # vincent
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    def func(data):
        data = [44,55] # 不是对内部元素进行修改,而是重新赋值
    
    v = [11,22,33]
    func(v)
    print(v) # [11, 22, 33]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    深拷贝

    如果想实现传值而不是传地址,那么可以使用深拷贝。

    import copy
    
    def func(data):
        data = [44,55]
    
    v = [11,22,33]
    new_v = copy.deepcopy(v) # 重新开辟一块地址空间,不影响v的值
    func(new_v)
    print(v)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    函数的返回值也是内存地址

    def func():
        data = [11, 22, 33]
        print(id(data))  # 2875971195072
        return data
    
    v1 = func()
    print(v1, id(v1)) # [11,22,33] 2875971195072
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    上述代码的执行过程:

    • 执行func函数
    • data = [11, 22, 33] 创建一块内存区域,内部存储[11,22,33],data变量指向这块内存地址。
    • return data 返回data指向的内存地址
    • v1接收返回值,所以 v1 和 data 都指向 [11,22,33] 的内存地址(两个变量指向此内存,引用计数器为2)
    • 由函数执行完毕之后,函数内部的变量都会被释放。(即:删除data变量,内存地址的引用计数器-1)

    所以,最终v1指向的函数内部创建的那块内存地址。

    如果两个函数进行调用,将返回不一样的内存地址:

    def func():
        data = [11, 22, 33]
        print(id(data))
        return data
    
    
    v1 = func()
    print(v1, id(v1))  # [11,22,33] 2187125510336
    
    v2 = func()
    print(v2, id(v2))  # [11,22,33] 2187126308352
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    需要注意的是,如果data是字符串或者整型时,会返回的地址是一样的,涉及到Python的缓存机制,这里不表

    参数的默认值

    当我们在函数中定义了一个参数默认值之后,在函数定义之后,还未执行函数时,Python解释器会帮助我们为函数创建一块区域,存储参数的默认值。

    def func(a1,a2=18):
        print(a1,a2)
    
    • 1
    • 2

    原理:Python在创建函数(未执行)时,如果发现函数的参数中有默认值,则在函数内部会创建一块区域并维护这个默认值。

    • func("root"): 执行函数未传值时,则让a2指向 函数维护的那个值的地址。
    • func("admin",20):执行函数传值时,则让a2指向新传入的值的地址。

    在特定情况【默认参数的值是可变类型 list/dict/set】 & 【函数内部会修改这个值】下,参数的默认值 有坑 。

    # 在函数定义的时候,a2初始化了,后面将不会重新初始化
    def func(a1,a2=[1,2]):
        a2.append(666)
        print(a1,a2)
    
    func(100) # 100 [1, 2, 666]
    func(200) # 200 [1, 2, 666, 666] 
    func(99, [77,88]) # 99 [77, 88, 666] a2重新指向了一个新的内存地址,但不影响刚初始化的那块地址
    func(300) # 300 [1, 2, 666, 666, 666] a2继续用函数初始化的那块地址
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
  • 相关阅读:
    螺母的工作原理以及应用优势
    企业云盘软件世界排行榜:提升企业文件管理效率的最佳工具
    Solidus Labs欢迎香港前金融创新主管赵嘉丽担任战略顾问
    内存管理篇——线性地址的管理
    5232: 【J1】【pair】平面上的最接近点对
    机械转计算机,成功上岸鹅厂。白菜价年薪40w
    C++特殊类设计
    vue+echarts可视化大屏,全国地图下钻,页面自适应
    1.求指定宽度的文本的高度,2.ubuntu下ping ipv6,3.git提示:终止提交因为提交说明为空
    java计算机毕业设计基于ssm的高校普法系统(源代码+数据库+Lw文档)
  • 原文地址:https://blog.csdn.net/vincent_duan/article/details/125553573