面试题之中的一个。

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. 系统出现0x0000006B蓝屏修复,系统文件损坏 bootcat.cache、driver.stl

    系统蓝屏,无论如何都不能进入系统,所以你需要一个U盘启动器,就是能绕过电脑的系统进入电脑,可以用U盘做一个U盘启动器,或者其他方法均可以,只要能进入到你的电脑访问C盘即可 2 下载链接内的文件解压后放 ...

  2. 搭建rsync实时同步

    1.本实验基于centos6.5服务器做的 cat cat /etc/redhat-release 2.在配置环境之前需要先将服务器自带的rsync卸除 yum -y remove rsync* 3. ...

  3. django 用户上传文件media的存储访问配置1

    1. 首先新建文件夹media  后 在项目setting中具体配置: MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'media ...

  4. 题解 P3128 【[USACO15DEC]最大流Max Flow】

    此类型题目有两种比较常见的做法:树链剖分和树上差分. 本题有多组修改一组询问,因此树上差分会比树链剖分优秀很多. 这里两种方法都进行介绍. 树链剖分和树上差分的本质都是将一颗树转换为一个区间,然后进行 ...

  5. ajax动态添加复选框

    function getLands() { $.ajax({ url:"httpserver.do?doPost&userQygs="+$("#userQygs& ...

  6. 兔子--Android Support v4包丢失的解决的方法

    在开发中,Android Support v4包丢失的解决的方法: Project->properties->Java Build Path->Libraries->Add E ...

  7. 实习第四天(bboss框架学习)

    现在好像比较使用的管理工具是gradle管理工具,学长说这个管理工具比maven管理工具要好用! 我今天主要就是想要安装好的gradle这个管理工具,但是可能是我的eclispe版本的问题,我没能安装 ...

  8. h5登录

    <!DOCTYPE html> <html lang="zh-cn"> <head> <meta http-equiv="Con ...

  9. Liunx-php7安装swoole扩展

    Liunx-php7安装swoole扩展 标签(空格分隔): php 下载包 https://github.com/swoole/swoole-src/releases 安装过程 直接wget也行直接 ...

  10. python-搭建django环境

    python-搭建django环境 标签(空格分隔): python Django简介 Django,发音为[`dʒæŋɡəʊ],是用python语言写的开源web开发框架,并遵循MVC设计.劳伦斯出 ...