面试题之中的一个。

def func1(p):
p = p + [1] def func2(p):
p += [1] p1 = [1,2,3]
p2 = [1,2,3]
func1(p1)
func2(p2)
print p1
print p2

结果:

我以为像这样的传參作为局部变量。由于都不会影响外部的list。所以答案应该是p1 =[1,2,3] ,p2=[1,2,3],然而

>>>
[1, 2, 3]
[1, 2, 3, 1]
>>>

重新被面试官虐杀,不甘心的我查找了python 局部变量:

x = [1,2,3]

def func(x):
    print "local! original x = ",x
    x  = [1]
    print "local! now x = ",x func(x)
print "global! x = ",x

结果:

local! original x =  [1, 2, 3]
local! now x =  [1]
global! x =  [1, 2, 3]

没错啊。我还记得要用全局变量得加global x 之类的语句呢。

为了保险起见,加一个id(),查查看对象是不是同一个先:

x = [1,2,3]
print "before func(), global! x = ",x,"id(x) = ",id(x) def func(x):
print "in func(), local! original x = ",x,"id(x) = ",id(x)
x = [1]
print "in func(), local! now x = ",x,"id(x) = ",id(x) func(x)
print "after func(), global! x = ",x,"id(x) = ",id(x)

结果:

before func(), global! x =  [1, 2, 3] id(x) =  46798728
in func(), local! original x = [1, 2, 3] id(x) = 46798728
in func(), local! now x = [1] id(x) = 46789512
after func(), global! x = [1, 2, 3] id(x) = 46798728

恩,能够看到,全局变量中的id(x) = 46798728,x进到func()中,由于运行了x = [1],才变成id(x) = 46789512。(合情合理)

这也说明python的确是传引用入函数。(然并卵)

利用id(x),查看下x = x + [1]对象是怎么变化的吧:

x = [1,2,3]
print "before func(), global! x = ",x,"id(x) = ",id(x) def func(x):
print "in func(), local! original x = ",x,"id(x) = ",id(x)
x = x + [1]
print "in func(), local! now x = ",x,"id(x) = ",id(x) func(x)
print "after func(), global! x = ",x,"id(x) = ",id(x)

结果:

before func(), global! x =  [1, 2, 3] id(x) =  46339976
in func(), local! original x = [1, 2, 3] id(x) = 46339976
in func(), local! now x = [1, 2, 3, 1] id(x) = 46390664
after func(), global! x = [1, 2, 3] id(x) = 46339976

啊。x = x + [1],是新建了一个对象,id(x) =  46390664。

利用id(x),查看下x += [1]对象是怎么变化的吧

x = [1,2,3]
print "before func(), global! x = ",x,"id(x) = ",id(x) def func(x):
print "in func(), local! original x = ",x,"id(x) = ",id(x)
x += [1]
print "in func(), local! now x = ",x,"id(x) = ",id(x) func(x)
print "after func(), global! x = ",x,"id(x) = ",id(x)

结果:

before func(), global! x =  [1, 2, 3] id(x) =  46536584
in func(), local! original x = [1, 2, 3] id(x) = 46536584
in func(), local! now x = [1, 2, 3, 1] id(x) = 46536584
after func(), global! x = [1, 2, 3, 1] id(x) = 46536584

啊,id(x)全程一样。x += [1],python直接就在原对象上操作,还真是够懒的说。

利用id(x),查看下x.append([1])对象时怎样变化的吧

x = [1,2,3]
print "before func(), global! x = ",x,"id(x) = ",id(x) def func(x):
print "in func(), local! original x = ",x,"id(x) = ",id(x)
x.append([1])
print "in func(), local! now x = ",x,"id(x) = ",id(x) func(x)
print "after func(), global! x = ",x,"id(x) = ",id(x)

结果:

before func(), global! x =  [1, 2, 3] id(x) =  47191944
in func(), local! original x = [1, 2, 3] id(x) = 47191944
in func(), local! now x = [1, 2, 3, [1]] id(x) = 47191944
after func(), global! x = [1, 2, 3, [1]] id(x) = 47191944

啊,id(x)全程一样,看来list的属性方法都是在原对象上操作的吧,我记得list.sort()也是,待会要验证的list.extend()预计也是。

利用id(x),查看下x.extend([1])对象时怎样变化的吧

x = [1,2,3]
print "before func(), global! x = ",x,"id(x) = ",id(x) def func(x):
print "in func(), local! original x = ",x,"id(x) = ",id(x)
x.extend([1])
print "in func(), local! now x = ",x,"id(x) = ",id(x) func(x)
print "after func(), global! x = ",x,"id(x) = ",id(x)

结果:

before func(), global! x =  [1, 2, 3] id(x) =  48437128
in func(), local! original x = [1, 2, 3] id(x) = 48437128
in func(), local! now x = [1, 2, 3, 1] id(x) = 48437128
after func(), global! x = [1, 2, 3, 1] id(x) = 48437128

果然id(x)全程一样。

话说list.append()是追加,extend()是拓展,他们的差别大概就是:

>>> a = [1,2,3]
>>> b = [4,5,6]
>>> c = [7,8,9]
>>> a.append(b)
>>> a
[1, 2, 3, [4, 5, 6]]
>>> c.extend(b)
>>> c
[7, 8, 9, 4, 5, 6]
>>>

看了上面的几段代码,聪明的你应该也能看出来:

list1 += list2  等价于 list1.extend(list2),这是证据

源码地址:

view=markup">http://svn.python.org/view/python/trunk/Objects/listobject.c?

view=markup

913	static PyObject *
914 list_inplace_concat(PyListObject *self, PyObject *other)
915 {
916 PyObject *result;
917
918 result = listextend(self, other); //+=果然用了listextend()
919 if (result == NULL)
920 return result;
921 Py_DECREF(result);
922 Py_INCREF(self);
923 return (PyObject *)self;
924 }

利用id(x)。查看下global x下。对象的变化吧:

x = [1,2,3]
print "before func(), global! x = ",x,"id(x) = ",id(x) def func():
global x
print "in func(), local! original x = ",x,"id(x) = ",id(x)
x = x + [1]
print "in func(), local! now x = ",x,"id(x) = ",id(x) func()
print "after func(), global! x = ",x,"id(x) = ",id(x)

结果:

before func(), global! x =  [1, 2, 3] id(x) =  47781768
in func(), local! original x = [1, 2, 3] id(x) = 47781768
in func(), local! now x = [1, 2, 3, 1] id(x) = 47795720
after func(), global! x = [1, 2, 3, 1] id(x) = 47795720

啊,global就保证了,即使我的变量x在函数中指向对象变了,外部的x也会指向新的对象。

回到面试题:

def func1(p):
p = p + [1] def func2(p):
p += [1] p1 = [1,2,3]
p2 = [1,2,3]
func1(p1)
func2(p2)
print p1
print p2

p1传入func1()。由于+操作,生成一个新的对象。但没有return给外部的p1。所以外部的p1=[1,2,3]。

p2传入func2(),由于+=操作,就是list.extend()。操作。在原对象操作。所以p2=[1,2,3,1]。

吐槽下:

事实上python在函数中參数是传引用的,假设一个对象obj进到函数中,被改变,那不管在哪里这个obj就是被改变了。并没有什么副本什么的。

那为什么有些时候看起来。函数中obj怎么被改变,外部的obj都岿然不动,啊,由于这个被改变后的obj不是原来的它了。

比方x = x + [1]。新的x真的是原来传进来的x吗?不是的。

此时的x是新的对象了(看id就知道了)。先前传进来的x。并没有被改变。

一点浅见,求打脸。

总结:

1、list + 创建一个新的对象。

2、list的 += 和 list.extend(),等价。都是在原对象上操作。

3、list.append()。也是在原对象上操作。

4、global,全局变量,嗯,不错(这算什么总结嘛)。

最新文章

  1. Github上传代码菜鸟超详细教程
  2. PDFsharp Samples
  3. NPOI操作excel之读取excel数据
  4. 20145103 《Java程序设计》第2周学习总结
  5. Spark Tungsten揭秘 Day1 jvm下的性能优化
  6. 深入理解 Spring 事务原理【转】
  7. 实用的两款jquery树形tree插件
  8. python3中bytes与string的互相转换
  9. Oracle-4 - :超级适合初学者的入门级笔记:plsql,基本语法,记录类型,循环,游标,异常处理,存储过程,存储函数,触发器
  10. mac通过自带的ssh连接Linux服务器并上传解压文件
  11. addEventListener以及滑轮滑动事件的应用
  12. 利用DWORD SHOOT实现堆溢出的利用(先知收录)
  13. MySQL 命令行工具不能向表中插入中文的解决方法
  14. 从新安装SQLserver 过程中报错问题合集
  15. 【作业】用栈模拟dfs
  16. mx:Label (标签)
  17. @Value("#{}")与@Value("${}")的区别以及用法
  18. windows和linux文件的转换
  19. getDimension()、getDimensionPixelOffset()和getDimensionPixelSize()区别详解
  20. template.js 模版内调用外部JS方法

热门文章

  1. js效果之导航中英文转换
  2. 安装lnmp前请先运行screen
  3. linux下mysql 查看默认端口号与修改端口号方法
  4. Node_进阶_3
  5. 关于JavaScript中this的指向,你知晓几分?请速来围观!
  6. 特斯拉正加快部署第三代Autopilot自动驾驶计算机
  7. MHA搭建及故障维护
  8. Mysql学习总结(26)——MySQL子查询
  9. Linux入门基础(一)
  10. POJ——T 1469 COURSES