• python 内存地址赋值


    python 没有同 cpp 一样的指针地址,所以使用起来其实蛮简单的

    int, string, tuple不可变类型

    i = 9
    str = 'te'
    print(id(i), id(str))
    
    j = i
    str2 = str
    print(id(j),id(str2))
    
    94728568118848 139677717183600
    94728568118848 139677717183600
    

    可以看出,python对普通变量的处理,是直接将引用的物理地址赋值给另一个变量

    如果修改其中的值,则该类型变量会重新分配空间,

    str = '111'
    print(id(str))
    
    str2 = str
    str2 = '222'
    print(f'str={str},str2={str2}')
    print(id(str), id(str2))
    
    139737600922096
    str=111,str2=222
    139737600922096 139737601153136
    

    dict, list 可变类型

    该类型略有不同。举例说 a = [1,2] 列表,内存有“两层”地址,一层针对 a 通过id(a) 查看,另一层针对值 通过id(a[0]) 查看——
    我况且暂称为这是“二级地址”

    而我们使用简单的 y = a 这样的赋值语句的时候,python会直接赋值一级地址,使得 id(y)=id(a), 避免了重复开辟内存复制一份
    看例子:

    mylist = [2,3,4]
    mylist2 = mylist
    
    print(id(mylist), id(mylist2))  # 两者是相同的, 即mylist2指向了mylist的内存地址
    
    mylist[2] = 999  # 所以可以看到修改了list2, 也修改了原有list
    print(mylist)
    print(mylist2)
    
    print(id(mylist[2]), id(mylist2[2]))  # 两者地址是相同的
    
    140101330826944 140101330826944
    [2, 3, 999]
    [2, 3, 999]
    140101573246704 140101573246704
    

    再看一个例子以更好的理解:

    mylist = [2,3,4]
    mylist2 = mylist
    
    mylist[2] = 999  # 所以可以看到修改了list2, 也修改了原有list
    
    mylist2 = [-1, -2]  # mylist2 指向新的内存地址, 不影响原来的
    print(mylist)  # [2, 3, 999]
    print(mylist2)  # [-1, -2]
    
    [2, 3, 999]
    [-1, -2]
    

    继续举例:
    下面这个例子使用 copy.copy() 方法实现浅拷贝。浅拷贝(t = copy.copy(y))和直接复制 (t=y) 是有区别的。直接复制,即后者以及在上一个例子中阐述了,它会直接修改t指向y的物理地址,这样就不用再开辟内存重新复制了。而浅拷贝,是重新开辟内存,将值重新复制一份。
    那为什么叫做 “浅”呢?——相对的肯定会有“深”
    因为复制拷贝的不够充分。即值拷贝列表的一级地址,而不拷贝(开辟内存拷贝)二级地址的值。
    比如,y = [1,2,3,['str','we']] ,t=copy.copy(y)浅拷贝只会为1,2,3 开辟内存,而['str','we']则使用偷懒的直接改变地址引用。
    也就是说,一级地址我会开辟内存,面对二级地址(['str','we'])则偷懒,直接改地址指向的目标
    具体看下:

    import copy
    lst = [1,2,3]
    sourcelst = [9,99,lst]
    copylst = copy.copy(sourcelst)  # 浅拷贝
    
    print(id(sourcelst), '  ',id(copylst))  # 首id 不同,一级地址相同
    print(id(sourcelst[0]), id(copylst[0]))  # 实际值内存相同,"二级地址"
    
    print(sourcelst, '  ',copylst)
    
    # test 1
    lst.append(0)
    print('===test 1:
    ',sourcelst, copylst,'
    ===')  # 均修改了, 因为lst[4] 是“二级地址”, 是公用的
    
    # test 2
    copylst.append('test 2')
    print('===test 2:
    ',sourcelst, copylst,'
    ===')  # 因为浅拷贝, 而修改的是一级地址, 所以两个结果不同
    
    139683722987456    139683722987584
    94417646587456 94417646587456
    [9, 99, [1, 2, 3]]    [9, 99, [1, 2, 3]]
    ===test 1:
     [9, 99, [1, 2, 3, 0]] [9, 99, [1, 2, 3, 0]] 
    ===
    ===test 2:
     [9, 99, [1, 2, 3, 0]] [9, 99, [1, 2, 3, 0], 'test 2'] 
    ===
    

    所以,为了避免以上问题,可以使用深拷贝,deepcopy

    参考

    https://www.cnblogs.com/Liubit/p/7668476.html
    https://blog.csdn.net/dudu3332/article/details/103259085

  • 相关阅读:
    [译]async/await中使用阻塞式代码导致死锁
    C# 对象与JSON字符串互相转换的三种方式
    C# form 传参数的几个方法
    C# 跨线程调用控件的4中方法
    Task的取消
    Task总结
    一个开发10年程序员论:学习Python最正确的步骤
    阿里大神总结的Python基础知识实例,超详细
    十条Python面试题陷阱,看看你是否会中招
    Python程序员编程10大原则,请牢牢记住,避免吃亏
  • 原文地址:https://www.cnblogs.com/KongHuZi/p/13693951.html
Copyright © 2020-2023  润新知