zoukankan      html  css  js  c++  java
  • python list的+,+=,append,extend

    面试题之中的一个。

    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,全局变量,嗯,不错(这算什么总结嘛)。











  • 相关阅读:
    sublime代码对齐
    sql查询结果存入DataTable,然后从DataTable取数据
    null和System.DBNull.Value的区别
    引用EChart和Bootstrap
    SSIS系列文章收藏
    Object类型的怎么判断空值
    DataGridView刷新数据
    WinFrom弹出输入框
    DataGridView更新数据到数据库
    SqlParameter防止SQL注入
  • 原文地址:https://www.cnblogs.com/yutingliuyl/p/6936750.html
Copyright © 2011-2022 走看看