• python中的值传递和引用传递(可变对象与不可变对象)也就是赋值的原理-python全部是引用传递


    python中的值传递和引用传递(可变对象与不可变对象)也就是赋值的原理-python全部是引用传递

    20141215 Chenxin

    猜测:
    1.属于同一个类生成的对象,其默认属性指向同一个引用.这样当你修改一个对象的时候,会影响到其他对象,除非你通过类中的其他方法加以修改.实际上应该都是指针指向的概念.
    2.基本"变量",就是不可变"对象",是调用的值传递.则当你重新通过"="赋值的时候,python内部是创建了一个新的值(对象)给它.(这里也就是通常所说的值传递).不用关心是哪种传递,说白了,python中都是引用传递.
    3.对于"可变对象",如list,dict以及默认对象,完全是引用传递的方式.是内存中一个地址的引用,像指针一样.
    4.如果想拷贝一个对象到其他对象(副本形式),那么只能通过python的copy模块来实现.
    5.python有个缓存的概念,缓存的整数范围为(-5,256).其他类型的不会缓存.比如x=1,y=1,x is y;x=257,y=257,x is not y; id(*)来检查内存地址.

    试验:
    关于函数参数传递的解释如下(3个例子):<<python基础教程 第二版>>P93
    def ChangeInt(a):
    a=10
    b=2
    ChangeInt(b)
    print b # ->2
    翻译为非函数的样子:
    b=2
    a=b #a的内存地址跟b是一样的,说明这里是内存地址拷贝,因此赋值可以理解为指针指向
    a=10 #将a指向了新创建的10对象,a的内存地址发生了改变.
    print b

    def ChangeList(a):
    a[0]=10
    b=[2]
    ChangeList(b)
    print b # ->[10]
    翻译为非函数:
    b=[2]
    a=b #a的内存地址跟b是一样的,说明这里是内存地址拷贝,因此赋值可以理解为指针指向
    a[0]=10 #将a指向的列表的第一个元素值指向内存新创建的10对象,a的内存地址没有改变,仍然跟b的内存地址一致.这里改变的只是列表内部第一个元素的地址,并未改变a的地址(也就是a指向的列表整体的地址).
    print b

    def ChangeList(a):
    a=[10]
    b=[2]
    ChangeList(b)
    print b # ->[2]
    翻译为非函数:
    b=[2]
    a=b #a的内存地址跟b是一样的,说明这里是内存地址拷贝,因此赋值可以理解为指针指向
    a=[10] #重新创建了一个新的列表,a指向这个新列表,a的内存地址发生了改变.
    print b

    结论:
    总结以上3个例子,可以理解为:
    1.python中的赋值"="语句,可以理解为指针的指向.
    2.由于指针指向问题,故才衍生出"作用域"的概念,而不是因为有作用域的"人为限制"造成的以上结果,是吧?!
    3.注意区分可变对象与不可变对象的区别.list,dict,int,char,tuple...
    4.以此也推出了值传递与引用传递的概念,可以统一理解为python中都是引用传递.

    说明:
    int不可变的实际情况:

    list可变的实际情况:

    类对象与实例对象引用传递的方式:

    !/bin/env python

    class class_a():
    num_a='abc' #当字符串足够长的时候呢?会不会是python的缓存呢?效果是一样的,不是缓存
    a=class_a
    b=class_a
    a.num_a='xyz' #无论字符串长短,都一样
    print a.num_a,b.num_a #输出xyz xyz
    print id(a.num_a),id(b.num_a) #输出相同的内存地址
    在这个类中,无论怎样去改变a对象,b对象都会跟着改变.
    说明该对象为可变对象.类对象只是一个初始的内存空间,之后生成实例对象会把值填充进去.???

    <<完>>
    知识

    其实到了python中差别不大.最主要的是python是通过赋值来创建一个对象的.
    所以对于python中的对象,a='1'这样不能叫修改,只能叫创建.如果你认为这样就是修改的话,就错了.
    一旦使用了赋值语句,就基本上与原对象无关了.#实际上是一个指针重新的指向

    而且python还有可变对象和不可变对象:
    象简单类型,整数,字符串,tuple都是不可变的.
    而象list, dict, object都是可变的.所以对于它们的修改一般是调用相应的方法,如对于list,你要a.append(b),对于dict你要a['b'] = '1'等.
    对象本身是没有什么变化,它的属性或值发生变化.对于这种种情况,传值还是引用都是一样的.

    不过,可能说引用更准确一些,比如:
    def b(c):
    print id(c)
    a = [2]
    print id(a)
    b(a)
    你会看到两次打印出来的id值是一样的.说明是引用传递.
    也就是说函数b中的参数所指的对象就是a.
    理解为传值也无所谓,因为从赋值的角度来说,在函数中的赋值会创建新的对象,不会影响到原参数.

    用指针的概念去理解更合理一些吧.

    其实在python中变量名与真正的对象是一种绑定关系,或引用的关系.所以理解为引用更为合适.

    和其他语言不一样,传递参数的时候,python不允许程序员选择采用传值还是传引用。Python参数传递采用的肯定是“传对象引用”的方式。实际上,这种方式相当于传值和传引用的一种综合。如果函数收到的是一个可变对象(比如字典或者列表)的引用,就能修改对象的原始值--相当于通过“传引用”来传递对象。如果函数收到的是一个不可变对象(比如数字、字符或者元组)的引用,就不能直接修改原始对象--相当于通过“传值'来传递对象。

    python一般内部赋值变量的话,都是传个引用变量,和C语言的传地址的概念差不多。可以用id()来查询内存地址.
    如果a=b的话, a和b的地址是相同的;
    如果只是想拷贝,那么就得用 b=a[:],这样a和b的内存地址就不同了;

    a=[1,2];b=a[:]; #这里a和b均指向一个叫做list的内存地址,list存储的,才是具体各个值对应的内存地址.列表是双层地址;
    id(a)
    140337215511368
    id(b)
    140337215510288 #不同

    a='abc';b=a[:]; #这里是字符串形式,a指向的是'abc'的内存地址,b=a[:]后(相当于b=a),b同样是指向'abc'的内存地址.字符串是单层地址;这里的写法,有点多态的概念.
    id(a)
    140337216460600
    id(b)
    140337216460600 #相同

    引用是指保存的值为对象的地址。在 Python 语言中,一个变量保存的值除了基本类型保存的是值外,其它都是引用,因此对于它们的使用就需要小心一些。下面举个例子:
    问题描述:已知一个列表,求生成一个新的列表,列表元素是原列表的复制
    a=[1,2]
    b=a
    这种做法其实并未真正生成一个新的列表,b指向的仍然是a所指向的对象。这样,如果对a或b的元素进行修改,a,b的值同时发生变化。
    解决的方法为:
    a=[1,2]
    b=a[:]
    这样修改a对b没有影响,修改b对a没有影响。(列表的复制,也就是副本.不是引用传递)
    但这种方法只适用于简单列表,也就是列表中的元素都是基本类型,如果列表元素还存在列表的话,这种方法就不适用了。原因就是,象a[:]这种处理,只是将列表元素的值生成一个新的列表,如果列表元素也是一个列表,如:a=[1,[2]],那么这种复制对于元素[2]的处理只是复制[2]的引用,而并未生成 [2]的一个新的列表复制。
    如果解决这一问题,可以使用copy模块中的deepcopy函数。修改测试如下:
    import copy
    a=[1,[2]]
    b=copy.deepcopy(a)
    print b -->[1, [2]]
    a[1].append(3)
    print a -->[1, [2, 3]]
    print b -->[1, [2]]
    有时候知道这一点是非常重要的,因为可能你的确需要一个新的列表,并且对这个新的列表进行操作,同时不想影响原来的列表。

  • 相关阅读:
    酷商城新闻客户端源码
    一款类似塔防类的保卫羊村游戏android源码
    躲避球游戏ios源码
    卡通投掷游戏ios源码
    爱拼图游戏源码完整版
    newsstand杂志阅读应用源码ipad版
    linux下proxy设定的一般方法
    android中调用App市场对自身App评分
    Android AChartEngine
    设计模式之单例模式
  • 原文地址:https://www.cnblogs.com/chanix/p/12737696.html
Copyright © 2020-2023  润新知