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

关于 Python 不使用临时变量来交换两个值的原理

  •  
  •   Alerta · 2018-08-26 15:22:48 +08:00 · 6956 次点击
    这是一个创建于 2042 天前的主题,其中的信息可能已经有所发展或是发生改变。
    用其他语言交换两个值,而且不用临时变量不是用加减法就是用异或法,但是 python 就直接

    a,b =b,a

    即可

    我很好奇其中的原理是什么,我一开始的猜想是 Python 直接交换了 a,b 引用的内存地址,求各位大神解答
    28 条回复    2018-08-27 15:30:39 +08:00
    huangzhe8263
        1
    huangzhe8263  
       2018-08-26 15:29:50 +08:00
    b, a 返回的是一个 tuple
    然后 a, b 分别赋值为第一个和第二个
    就是
    (a, b) = (b, a)
    fwee
        2
    fwee  
       2018-08-26 15:33:48 +08:00
    学一学编译和解释器的概念
    kkk330
        3
    kkk330  
       2018-08-26 15:35:57 +08:00 via iPhone   ❤️ 1
    dis 看看
    Wincer
        4
    Wincer  
       2018-08-26 15:37:37 +08:00 via Android
    Python 元组拆包,当 a, b = b, a 的时候,会把 b, a 看做一个可迭代对象,依次赋值给 a, b 组成的元组
    jmc891205
        5
    jmc891205  
       2018-08-26 16:16:43 +08:00
    用 dis 看一看汇编就懂了
    wocanmei
        6
    wocanmei  
       2018-08-26 16:18:29 +08:00 via iPhone
    个人觉得这只不过是一种语法糖,虽然没写中间变量底层说不定用了
    nazor
        7
    nazor  
       2018-08-26 16:23:34 +08:00
    CAS
    hhsuan
        8
    hhsuan  
       2018-08-26 16:35:51 +08:00 via Android
    如果是这么个问法,我觉得任何语言都可以不用变量交换两个值。
    codechaser
        9
    codechaser  
       2018-08-26 16:38:56 +08:00 via Android
    unpacking,也就是多个产量负值时序列的拆包。简易写法
    zhicheng
        10
    zhicheng  
       2018-08-26 16:43:29 +08:00 via iPhone
    虽然没有用临时变量,但是用了栈。
    adek06
        12
    adek06  
       2018-08-26 17:21:44 +08:00
    同意一楼的说法
    Alerta
        13
    Alerta  
    OP
       2018-08-26 17:28:18 +08:00
    @kkk330 dis 是??
    Yourshell
        14
    Yourshell  
       2018-08-26 17:29:57 +08:00 via iPhone
    你没看到不代表不存在
    msg7086
        15
    msg7086  
       2018-08-26 17:35:11 +08:00   ❤️ 1
    背后相当于做了:(伪代码)

    tmp = [a, b]
    a = tmp[1]
    b = tmp[0]

    和内存地址没什么关系。各种语言不同的写法最后都会被编译成类似的机器代码。
    Alerta
        16
    Alerta  
    OP
       2018-08-26 17:39:52 +08:00
    感谢各位大神,原来答案不只是拆包。现在优化了之后,在 2、3 个值分配的时候是直接运用栈,在 3 个以上值分配的时候才是用了拆包的原理。
    详细答案在 11 楼哥们的链接里: https://stackoverflow.com/questions/21047524/how-does-swapping-of-members-in-the-python-tuples-a-b-b-a-work-internally
    momocraft
        17
    momocraft  
       2018-08-26 18:31:32 +08:00
    都用 python 了就别想着"内存地址"了
    Feva
        18
    Feva  
       2018-08-26 19:52:27 +08:00
    不爱思考的新手
    Yggdroot
        19
    Yggdroot  
       2018-08-26 20:19:54 +08:00
    只是语法糖而已,如果有一种新的语言,甚至可以这样表示交换两个变量:
    `a<->b`
    Pythondr
        20
    Pythondr  
       2018-08-26 20:23:28 +08:00 via Android
    元组的自动组包与自动解包
    inframe
        21
    inframe  
       2018-08-26 21:38:09 +08:00 via Android
    python 是个栈机,push pop 一波搞定
    scriptB0y
        22
    scriptB0y  
       2018-08-26 22:03:22 +08:00
    @wocanmei 其实没有用中间变量吧。

    只不过 Python 的解释器支持一个字节码,ROT_TWO,可以直接交换栈顶的两个变量。其他的语言没有这个功能而已。应该也不能叫做是语法糖。

    dis 查看方法:

    https://gist.github.com/laixintao/bb4330651c33124d52ff888b99c9e939

    Python ROT_TWO 文档:

    https://docs.python.org/3/library/dis.html#opcode-ROT_TWO

    ROT_TWO
    Swaps the two top-most stack items.

    cc @Alerta
    Joshua999
        23
    Joshua999  
       2018-08-26 22:09:28 +08:00 via Android
    想知道只用加减法怎么实现,不用临时变量交换两个值
    Alerta
        24
    Alerta  
    OP
       2018-08-26 22:52:24 +08:00
    @Joshua999 百度一下有很多
    Alerta
        25
    Alerta  
    OP
       2018-08-26 22:52:38 +08:00
    @scriptB0y 感激感激
    tyx1703
        26
    tyx1703  
       2018-08-27 00:21:48 +08:00 via Android
    a = a + b
    b = a - b
    a = a - b

    @Joshua999
    wocanmei
        27
    wocanmei  
       2018-08-27 08:51:10 +08:00 via iPhone
    @scriptB0y #22 多谢科普
    Joshua999
        28
    Joshua999  
       2018-08-27 15:30:39 +08:00 via Android
    @tyx1703 当时脑抽,看了半天没想出来,谢谢
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2789 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 11:48 · PVG 19:48 · LAX 04:48 · JFK 07:48
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.