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
jmyz0455
V2EX  ›  Python

如何理解这一句 Python 的赋值语句?

  •  
  •   jmyz0455 · 2016-08-22 19:56:18 +08:00 · 4649 次点击
    这是一个创建于 2807 天前的主题,其中的信息可能已经有所发展或是发生改变。

    self.agent_stats = [[0, 0, 0] for a in self.agents]

    在阅读别人代码的时候看见的,请问这是什么意思?

    31 条回复    2016-08-25 00:13:37 +08:00
    mgna17
        1
    mgna17  
       2016-08-22 20:03:25 +08:00 via Android   ❤️ 1
    等号右边返回一个长度与 self.agents 相同的 list ,其中所有元素全是 [0, 0, 0]。
    搜索关键字: python 列表生成式
    TimePPT
        2
    TimePPT  
       2016-08-22 20:22:04 +08:00 via iPhone
    self.agent_stats = []

    for A in self.agent:
    self.agent_satats.apend([0, 0, 0])
    TimePPT
        3
    TimePPT  
       2016-08-22 20:22:25 +08:00 via iPhone
    @TimePPT for 循环第二行有缩进
    TimePPT
        4
    TimePPT  
       2016-08-22 20:23:11 +08:00 via iPhone
    @TimePPT for a in self.agent

    手机码字真费劲
    jmyz0455
        5
    jmyz0455  
    OP
       2016-08-22 20:24:16 +08:00
    @mgna17 感谢关键词,很多不会的地方都是因为连关键词都想不出来
    jmyz0455
        6
    jmyz0455  
    OP
       2016-08-22 20:24:43 +08:00
    @TimePPT 没关系,看懂了,谢谢
    introom
        7
    introom  
       2016-08-22 21:20:58 +08:00   ❤️ 3
    应该这样写, self.agent_stats = [ [0] * 3 for _ in range(len(self.agents))]
    mingyun
        8
    mingyun  
       2016-08-22 22:15:46 +08:00
    @introom 有什么区别吗
    ericls
        9
    ericls  
       2016-08-22 22:19:34 +08:00 via iPhone
    @mingyun 他这个写法很 pythonic
    msg7086
        10
    msg7086  
       2016-08-23 00:56:12 +08:00
    @ericls 比起 [[0] * 3] * len(self.agents) 有什么优势?
    Jolly23
        11
    Jolly23  
       2016-08-23 01:22:05 +08:00 via iPhone
    类似其他语言的二维数组
    ericls
        12
    ericls  
       2016-08-23 01:23:46 +08:00
    @msg7086 你这个写法更好
    josephshen
        13
    josephshen  
       2016-08-23 02:26:28 +08:00 via iPhone
    半夜一觉睡醒了,我可以负责任的对你们说,乘号的写法是错误的,你们试试用一下 id 求一下 list 里面的数据,比较一下值是多少
    introom
        15
    introom  
       2016-08-23 06:40:50 +08:00   ❤️ 6
    这个算是新手的常见问题吧,我上个礼拜刚给别人解答过。把上次写的直接粘贴复制过来。

    >>>>


    我补充一下, list 的乘法是浅拷贝,只是复制存储的 PyObject*指针,
    所以 a = [[]]*2 ,如果 a[0].append(3), 就会得到[[3], [3]] 而不是[[3], []]
    至于为什么这种效果,没办法,人家就是这样设计的,参见
    https://hg.python.org/cpython/file/8f84942a0e40/Objects/abstract.c#l928
    上面会调用 list 的 sq_repeat , 也就是在这里,
    https://hg.python.org/cpython/file/db93af6080e7/Objects/listobject.c#l539
    你看,它只是复制了指针。

    其实我想补充的是,
    对于 python 的多维数组,请不要这样写,
    [[0 for i in xrange(4)] for j in xrange(4)],
    既然 0 是 immutable ,你完全可以这样写
    [[0]*4 for j in xrange(4)]
    但是,注意到你都用不到 j 这个变量,我发现你用的是 python2, 在 python2 里, list comprehension 没有新开栈帧,用的是当前函数(或者 module,本质上是 PyFrame)的 local namespace, 换句话说,你这个 j 除了污染当前函数的 local 名字空间以外,别无是处。
    建议这样写,
    [[0]*4 for _ in xrange(4)]
    当然,在 Python3 里, list comphrension 会在一个新的 frame 里执行,不会存在名字空间的污染,不过还是推荐写成_, 因为你根本用不到 j 这个变量。
    maowu
        16
    maowu  
       2016-08-23 09:12:21 +08:00 via Android
    @josephshen 能否说明一下为什么错了?
    KingHL
        17
    KingHL  
       2016-08-23 09:59:58 +08:00
    楼上已经有人解释的很好了。个人理解, 对于 mutable 对象来说, 用*是不对的, 因为所有的变量名都会指向同一个值,此值改变了,所有的变量都会变。对于 immutable 对象,虽然所有变量名指也向同一个值,但是在改变值的时候,因为原值是 immutable 的,所以被改变的变量名会解引用,重新指向新值的引用,也就不会出问题了。解释的有点不清楚,建议查资料理解下 python 的对象和命名空间的区别。
    bravecarrot
        18
    bravecarrot  
       2016-08-23 10:07:42 +08:00
    @introom 感谢。之前看到过,结果没记住,昨天还刚刚这样用了呢。还有, _ is really a good name.
    hitmanx
        19
    hitmanx  
       2016-08-23 11:34:10 +08:00
    python 里一直让我比较困惑的就是引用、浅拷贝、深拷贝,可能也和我之前一直用 c/c++有关系。在 c/c++里是按值或按引用 /指针传递,在大部分的情况下是很容易确定的,而且是确定无疑的。在 python 里,我能理解比如最常见的场景: mutable,immutable 涉及到拷贝时产生的状况,但是[[0] * 3] * n 这种情况下会发生什么情况,除了做个实验看一下 id ,我好像还真不敢直接下结论。你们都是怎么记忆的,除了 case by case 的记忆以外,有什么比较通用的规则吗?
    qnnnnez
        20
    qnnnnez  
       2016-08-23 11:57:48 +08:00 via Android
    @hitmanx 全部看成传引用就行了,没有隐式拷贝
    cartmanie
        21
    cartmanie  
       2016-08-23 12:15:31 +08:00
    >>> a=[1,2,3]
    >>> b=[[0,0,0] for c in a]
    >>> print b
    [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
    qnnnnez
        22
    qnnnnez  
       2016-08-23 12:16:29 +08:00
    @introom 反对,和是不是 immutable 没有关系

    a = [1]
    b = a, a, a, a, a
    c = [b] * 5
    print(c)
    a[0] = 2
    print(c)
    shyling
        23
    shyling  
       2016-08-23 12:41:10 +08:00
    你需要[([0]*3)[:] for _ in range(10)]
    hitmanx
        24
    hitmanx  
       2016-08-23 14:20:15 +08:00
    @qnnnnez 涉及到显式拷贝的比较好辨认,包括函数传参。但是像这个*,第一反应没想到是个拷贝动作。

    如果在 c++里,给我的感觉可能类似
    const size_t len = 5;
    std::vector<std::vector<int> > vec(len, std::vector<int>(3, 0));
    allanzyne
        25
    allanzyne  
       2016-08-23 15:06:34 +08:00 via Android
    @shyling [:] 没有必要吧?
    shyling
        26
    shyling  
       2016-08-23 15:12:10 +08:00
    @allanzyne 需要 0 0
    allanzyne
        27
    allanzyne  
       2016-08-23 15:14:48 +08:00 via Android
    @shyling 我测了一下,好像和没写一样啊?
    shyling
        28
    shyling  
       2016-08-23 15:15:09 +08:00
    @allanzyne 哦,不需要,记错了
    gkiwi
        29
    gkiwi  
       2016-08-24 08:51:21 +08:00
    @qnnnnez

    你的姿势不对,后面的 b,c 引用的都是[0]这个 list 的地址,而 list 是 muatble 的;

    你试试这个:

    a = 1
    b = a, a, a, a, a
    c = [b] * 5
    print(c)
    a = 2
    print(c)

    http://blog.csdn.net/hsuxu/article/details/7785835
    qnnnnez
        30
    qnnnnez  
       2016-08-24 11:53:40 +08:00
    @gkiwi 仔细想想,我发现应该是“不包含 mutable 对象的 immutable 对象”
    Yinz
        31
    Yinz  
       2016-08-25 00:13:37 +08:00
    学习了:D
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1008 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 19:25 · PVG 03:25 · LAX 12:25 · JFK 15:25
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.