1. 程式人生 > >python list的+,+=,append,extend

python list的+,+=,append,extend

list res adding 試題 content int none tro append()

面試題之中的一個。

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),這是證據

源碼地址: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,全局變量,嗯,不錯(這算什麽總結嘛)。











python list的+,+=,append,extend