鱼C论坛

 找回密码
 立即注册
查看: 2220|回复: 0

[技术交流] 没那么简单:对象无名,请找引用。改掉c思维

[复制链接]
发表于 2015-11-17 10:38:26 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 无名似名 于 2015-11-17 10:50 编辑

        此贴为系列帖子《没那么简单》之对象无名,请找引用,改掉c思维。

        学习小甲鱼《python基础教程》中,有许多思考,觉得有必要记录下来,一方面备查,一方面同鱼油讨论,共同进步。

        今天讨论的主题是:对象,引用,改掉c思维,python设计哲学。

        先上代码,看看问题:

  1. def fun():
  2.     a=[1,2,3]
  3.     print('id(a):','id(a))
  4.     return a

  5. b=fun()
  6. print('id(b)',id(b))
复制代码


        此代码的用意在于查看函数中的变量生存时间,学过c的人习惯思维是:a列表的生存周期为整个函数的生存期,当运行完fun()以后a被自动销毁然后把其值在传出去付给b,理论上a的id地址和b的id地址不同,但结果呢
    结果:'id(a)' 5691872
              'id(b)' 5691872
        为什么居然一样啊,难道是a在销毁的时候a对象清空,恰巧建立b的对象也用同样的地址么。多试验几次,结果居然地址都一样。

        再贴一段代码:
  1. a=[1,2,3]

  2. print(a,'id(a)',id(a))

  3. def fun():
  4.     a.append(4)
  5.     print(a,'id(a)',id(a))
  6.     return a

  7. b=fun()

  8. print(b,'id(b)',id(b))
复制代码


        结果:[1, 2, 3] id(a) 6885824
                  [1, 2, 3, 4] id(a) 6885824
                  [1, 2, 3, 4] id(b) 6885824

        都是同一个内存,他们肯定都是对一个对象在操作,那函数的return到底返回的是什么,以c思维是返回‘值’但这里明显是返回原对象。

        结论:c中往往会盯着变量的内存来思维,但是在python中却不是这样,因为你根本找不到对象,你时刻打交道的是对象的引用,在第一个函数例子中,a对象自从被创建后从未被销毁过,函数结束后销毁的是a这个引用名,a的引用名生存期是整个函数的生存期,同样第二个例子中,只是把a对象的引用引进函数里,操作的还是同一个对象。

        重要结论:python中对象与引用是分离的,对象的操作都是通过引用。

        用上边的结论来讨论函数的按‘值’传参和按‘址’传参就不会乱了

        下边上代码,得结论:

  1. a=[1,2,3]

  2. print(a,'id(a)',id(a))

  3. def fun(arg_a,arg_b):
  4.     a=arg_a
  5.     b=arg_a[:]              #此处不是引用复制而是对象复制,新建了一个对象   
  6.    
  7.     a.append(3)             #此处对外部a对象进行加3操作,看打印地址可知
  8.     del b[0]                #把新建对象b删除一个项目,看后边地址可知

  9.     print(a,'id(fun.a)',id(a))
  10.     print(b,'id(fun.b)',id(b))

  11.     return a,b

  12. another_a,another_b=fun(a,a)

  13. print(another_a,':id(another_a)',id(another_a)) #全局a的操作就跟c中的按‘址’操作一样
  14. print(another_b,':id(another_b)',id(another_b)) #全局a的操作就跟c中的按‘值’操作一样
复制代码


运行结果:
        [1, 2, 3] id(a) 3084736
        [1, 2, 3, 3] id(fun.a) 3084736                 #按‘址’传递,地址没变
        [2, 3] id(fun.b) 3087256                        #按 ‘值’传递,新建了个对象
        [1, 2, 3, 3] :id(another_a) 3084736        
        [2, 3] :id(another_b) 3087256

        必须记住:python中的引用操作时刻要明白到底是‘新建了原对象的引用’还是‘用原对象创建了个一样的新对象’。单等号‘=’操作一般都是引用复制给引用,不会改变原对象,而对象创建新对象用切片[:]或者对象内置函数copy(),这里边还有浅拷贝和深拷贝之分,鱼油自行研究吧

        另外以上讨论有个前提:都是可变对象,要是换成字符串,元组,数字等不可变对象,就更简单了,不可变所以每次都是新建了个对象,不可能出现一个不可变对象有两个引用。

        不知道鱼油能明白我的讨论不,从c进入python的一定要记住python处处是对象,处处是引用。

        另外就是不得不佩服python的设计哲学,变量与对象分离,这真是个绝妙的点子,通过对引用的操作来处理对象,而对象你压根不需要知道存储在哪。而整个程序你只需关心’引用‘不需要关心’对象‘。

        来个下期预告,会对元类,类,对象进行讨论,到时会用python的内置函数来一探这些东西里到底有什么,创建的时候到底发生了什么事,因为时间有限,我会在有空的时候一点一点的码出来。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-3-29 03:27

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表