python append 为何如此奇怪? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
woniu127
V2EX    Python

python append 为何如此奇怪?

  •  
  •   woniu127 2016-11-20 09:33:25 +08:00 5095 次点击
    这是一个创建于 3252 天前的主题,其中的信息可能已经有所发展或是发生改变。

    这是一段测试代码

    li1 = [] li2 = [] ki = [0] j = 0 for i in range(10): ki[0] = ki[0]+1 j = j+1 li1.append(ki) li2.append(j) print(li1) print(li2) 

    这是输出:

    [[10], [10], [10], [10], [10], [10], [10], [10], [10], [10]] [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 

    为何 append()参数是列表类型时,每次循环都会改变 li1 中的值???

    第 1 条附言    2016-11-20 16:13:14 +08:00
    谢谢大家,今天又学到了很多,是我基础太薄弱了,对对象和引用理解的都不够。
    18 条回复    2016-11-21 16:18:09 +08:00
    laoyur
        1
    laoyur  
       2016-11-20 09:37:55 +08:00   1
    li1 = []
    li2 = []
    ki = [0]
    j = 0
    for i in range(10):
    ki[0] = ki[0]+1
    j = j+1
    li1.append(list(ki))
    li2.append(j)
    print(li1)
    print(li2)
    kindjeff
        2
    kindjeff  
       2016-11-20 09:38:39 +08:00 via iPhone   1
    因为你只是 append 了 ki 对象的引用,而 list 是可变的,内容改变了,你 append 的进去的仍然是 ki 的引用。
    woniu127
        3
    woniu127  
    OP
       2016-11-20 09:48:26 +08:00
    @kindjeff 也就是说只要 append 的是不可变的对象就没问题了
    exoticknight
        4
    exoticknight  
       2016-11-20 10:06:41 +08:00   1
    明显是没搞清楚 python 是引用优先的
    估计楼主肯定还会在用默认参数是对象的时候出现问题
    woniu127
        5
    woniu127  
    OP
       2016-11-20 10:12:51 +08:00
    @exoticknight 学 python 还不够,认识还不够深,只能一个坑一个坑的踩了
    BiggerLonger
        6
    BiggerLonger  
       2016-11-20 10:19:18 +08:00 via Android
    是用 list.extend 方法
    wwqgtxx
        7
    wwqgtxx  
       2016-11-20 10:24:42 +08:00
    又一个被 C 的值传递坑的
    IanPeverell
        8
    IanPeverell  
       2016-11-20 10:53:46 +08:00   1
    因为 append(ki)的时候传递的是 ki 的地址,所以如果想不改变值可以这么些 li.append([x for x in ki])
    mornlight
        9
    mornlight  
       2016-11-20 10:58:09 +08:00 via iPhone   1
    第一个 list 里到最后是 10 个指向同一块内存的相同元素
    dtfm
        10
    dtfm  
       2016-11-20 11:15:46 +08:00   1
    ```
    li1 = []
    li2 = []
    ki = [0]
    j = 0
    for i in range(10):
    ki[0] = ki[0]+1
    j = j+1
    li1.append(ki[0])
    li2.append(j)
    print(li1)
    print(li2)
    ```
    在 ki 里面加一个 ki[0],这样每次都添加就好了
    lzhCoooder
        11
    lzhCoooder  
       2016-11-20 11:29:45 +08:00   1
    浅拷贝 你 li1 里的每个元素都是指向的或者说引用的同一个 ki
    li2 里之所以不这样 是因为 j 是不可变类型,没加一次创建一个新 j
    rebirth2
        12
    rebirth2  
       2016-11-20 12:40:51 +08:00 via Android   1
    可以用 list slice, ki[:]这样直接创建新 list ,不过比较黑科技。。
    onlyice
        13
    onlyice  
       2016-11-20 13:02:14 +08:00 via Android
    把代码粘贴到这里看看就懂了 http://www.pythontutor.com/visualize.html#py=2
    bravecarrot
        14
    bravecarrot  
       2016-11-20 13:13:10 +08:00
    @onlyice 这个有意思啊 哈哈哈哈 不用开 ide 看了
    bravecarrot
        15
    bravecarrot  
       2016-11-20 13:25:14 +08:00   1
    @woniu127 ls 的 @exoticknight 可能说的是这个

    ``` python
    def foo(x, l = []):
    l.append(x)
    return l
    y = foo(6)
    z = foo(8)

    p = foo(2, [3])
    q = foo(4, [5])
    print y
    print z
    print p
    print q
    ```

    output:
    [6, 8]
    [6, 8]
    [3, 2]
    [5, 4]
    *************
    同理,函数每次使用的默认参数的 list 都是同一个,每次都会操作它
    20015jjw
        16
    20015jjw  
       2016-11-20 15:34:28 +08:00
    lz 你显然没理解 reference 的概念..
    enenaaa
        17
    enenaaa  
       2016-11-21 09:10:23 +08:00
    我也觉得奇怪,其他语言标准库的 append 函数多半是值插入, python 非得是引用。
    然后用个不常见 extend 函数代替。 比较坑
    diydry
        18
    diydry  
       2016-11-21 16:18:09 +08:00   1
    对象变动(Mutation)
    Python 中可变(mutable)与不可变(immutable)的数据类型让新很是头痛。 简单的说, 可
    变(mutable)意味着"可以被改动", 不可变(immutable)的意思是“常量(constant)”。 想把脑
    筋转动起来吗? 考虑下这个例:
    foo = ['hi']
    print(foo)
    # Output: ['hi']
    bar = foo
    bar += ['bye']
    print(foo)
    # Output: ['hi', 'bye']
    刚刚发了什么? 我们预期的不是那样!我们期望看到是这样的:
    foo = ['hi']
    print(foo)
    # Output: ['hi']
    bar = foo
    bar += ['bye']
    print(foo)
    # Output: ['hi']
    print(bar)
    # Output: ['hi', 'bye']
    这不是个 bug 。 这是对象可变性(mutability)在作怪。 每当你将个变量赋值为另个可
    变类型的变量时, 对这个数据的任意改动会同时反映到这两个变量上去。 新变量只不过是
    变量的个别名已。 这个情况只是针对可变数据类型。 下的函数和可变数据类型让
    你下就明了:
    def add_to(num, target=[]):
    target.append(num)
    return target
    add_to(1)
    # Output: [1]
    add_to(2)
    # Output: [1, 2]
    add_to(3)
    # Output: [1, 2, 3]
    Python 进阶
    对象变动 Mutation 51 你可能预期它表现的不是这样。 你可能希望, 当你调add_to 时, 有个新的列表被
    创建, 就像这样:
    def add_to(num, target=[]):
    target.append(num)
    return target
    add_to(1)
    # Output: [1]
    add_to(2)
    # Output: [2]
    add_to(3)
    # Output: [3]
    啊哈!这次又没有达到预期, 是列表的可变性在作怪。 在 Python 中当函数被定义时, 默认
    参数只会运算次, 不是每次被调时都会重新运算。 你应该永远不要定义可变类型的
    默认参数, 除你知道你正在做什么。 你应该像这样做:
    def add_to(element, target=None):
    if target is None:
    target = []
    target.append(element)
    return target
    现在每当你在调这个函数不传target 参数的时候, 个新的列表会被创建。 举个例

    add_to(42)
    # Output: [42]
    add_to(42)
    # Output: [42]
    add_to(42)
    # Output: [42]
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3366 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 04:41 PVG 12:41 LAX 21:41 JFK 00:41
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86