面试题之中的一个。

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

python list的+,+=,append,extend的更多相关文章

  1. [python][oldboy]list append, extend

    # coding=utf8 li = [1, 3, [1, "liu"], "liu"] print li li.append([1, 2]) print li ...

  2. python列表插入--append(), extend(), insert()

    append(),extend(), insert()都是列表操作中常用的插入函数.其中前两个均接收一个参数,并插入到列表尾部.最后一个接收两个参数,将参数2插入到参数1之前. 本文主要讨论appen ...

  3. Python sys.path.append

    python sys.path.append 对于模块和自己写的程序不在同一个目录下,可以把模块的路径通过sys.path.append(路径)添加到程序中. 在程序开头加上: import syss ...

  4. python 之 append extend

    概述 append和extend针对python的列表 列表内的元素为对象,可以为数字.字符串.列表等等 append添加的是一个对象 extend添加一个列表 例子 append >>& ...

  5. python中List append()、extend()和insert()的区别

    Python中向列表增加更多数据时,有append().extend()和insert()等方法 其中最常用的是list.append(obj) 向列表的尾部添加一个新的元素. 需要一次性添加多个元素 ...

  6. python list中append()方法和extend()方法区别

    共同点 只能作用于list类型(不能作用于tuple等其他类型) 单参数限制(不支持多参数) 不同点 list.append(object) 向列表中添加一个对象object. 使用append的时候 ...

  7. python list成员函数extend与append的区别

    extend 原文解释,是以list中元素形式加入到列表中 extend list by appending elements from the iterable append(obj) 是将整个ob ...

  8. python append extend区别

    1. 列表可包含任何数据类型的元素,单个列表中的元素无须全为同一类型. 2. append() 方法向列表的尾部添加一个新的元素. 3. 列表是以类的形式实现的.“创建”列表实际上是将一个类实例化.因 ...

  9. python list中append()与extend()用法

    列表是以类的形式实现的.“创建”列表实际上是将一个类实例化.因此,列表有多种方法可以操作. 1. 列表可包含任何数据类型的元素,单个列表中的元素无须全为同一类型. 2. append() 方法向列表的 ...

  10. python列表之append与extend方法比较

    append和extend是列表的两种添加元素方式,但这两种方式却又有些不同之处.那么不同之处在哪里呢,我们通过对二者的定义和实例来看一看. list.append() 1.定义:L.append(o ...

随机推荐

  1. 织梦dedecms支持flash的flv文件播放功能代码

    1.打开/include/FCKeditor/editor/dialog/dede_media.htm if(playtype=="rm"|| (playtype=="- ...

  2. HDU 6315 Naive Operations(线段树+复杂度均摊)

    发现每次区间加只能加1,最多全局加\(n\)次,这样的话,最后的答案是调和级数为\(nlogn\),我们每当答案加1的时候就单点加,最多加\(nlogn\)次,复杂度可以得当保证. 然后问题就是怎么判 ...

  3. PHP 变量作用域

    以下为 PHP 中的各种变量在底层实现中是如何存储的. 变量: $temp = 'temp'; $temp2 = $temp; // key p *executor_globals.symbol_ta ...

  4. vue-quill-editor-upload : 实现vue-quill-editor上传图片到服务器

    vue-quill-editor-upload git: https://github.com/NextBoy/vu... A plug-in for uploading images to your ...

  5. 紫书 例题8-10 UVa 714 (二分答案)

    这道题让最大值最小, 显然是二分答案 当题目求的是最大值最小, 最小值最大, 这个时候就要想到二分答案 为什么可以二分答案呢, 因为这个时候解是单调性的, 如果简单粗暴一点 就全部枚举一遍, 验证答案 ...

  6. O(1)复杂度增加和删除和随机取

    题目: https://leetcode.com/problems/insert-delete-getrandom-o1-duplicates-allowed 非常好的解法: https://disc ...

  7. Android清单文件具体解释(六) ---- <activity>节点的属性

    1.android:allowTaskReparenting android:allowTaskReparenting是一个任务调整属性,它表明当这个任务又一次被送到前台时,该应用程序所定义的Acti ...

  8. nj10---文件读取

    介绍:fs模块是文件操作的封装,它提供了文件的读取,写入,更名,删除,遍历目录,链接POSIX文件系统操作.与其他模块不同的是,fs模块中所有的操作都提供了异步和同步两个版本,例如读取文件内容函数异步 ...

  9. 基于机器学习的web异常检测——基于HMM的状态序列建模,将原始数据转化为状态机表示,然后求解概率判断异常与否

    基于机器学习的web异常检测 from: https://jaq.alibaba.com/community/art/show?articleid=746 Web防火墙是信息安全的第一道防线.随着网络 ...

  10. rem自适应布局-移动端自适应必备:flexible.js

    http://caibaojian.com/flexible-js.html