面试题之一。
- 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]
- >>>
- 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]
为了保险起见,加一个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
利用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.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),查看下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
话说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),这是证据:
源代码地址: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
回到面试题:
- 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,全局变量,嗯,不错(这算什么总结嘛)。