• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

关于python:一个关于-的谜题

python 搞代码 3年前 (2022-03-01) 27次浏览 已收录 0个评论
文章目录[隐藏]

原文链接: 一个对于 += 的谜题

明天在看书过程中发现了一个问题,还挺有意思的,分享给大家。

上面两个 Python 表达式会产生什么后果?

t = (1, 2, [3, 4])
t[2] += [5, 6]

给四个备选答案:

  1. t 变成 (1, 2, [3, 4, 5, 6])
  2. 因为 tuple 不反对对它的元素赋值,所以会抛出 TypeError 异样。
  3. 以上两个都不是。
  4. 以上两个都是对的。

过后看到这个问题,第一反馈就是选 2。因为 tuple 是不可变对象,不反对对它的元素赋值,会报错。

但事实上,这道题的正解是 4。

在终端里验证一下:

Python 3.8.2 (default, Oct  2 2020, 10:45:42)
[Clang 12.0.0 (clang-1200.0.32.27)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> t = (1, 2, [3, 4])
>>> t[2] += [5, 6]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

后果是没问题的,t 被批改了,然而也报错了。

还能够在 Python Tutor 上剖析一下:

网站地址: https://pythontutor.com/

这个网站能够可视化剖析 Python 的运行过程和原理。

执行第一个表达式:

执行第二个表达式:

为什么会这样呢?能够从两个方面来解释:

一、对象类型

Python 中的对象能够分成两类,可变对象和不可变对象,比方一些内置类型:

  1. 可变对象:list,set,dict。
  2. 不可变对象:int,float,bool,string,tuple。

举一个例子:

可变对象:

>>> a = [1, 2, 3]
>>> id(a)
2139167246856
>>> b = a
>>> id(b)
2139167246856
>>> a[1] = 4
>>> a
[1, 4, 3]
>>> b
[1, 4, 3]
>>> id(a)
2139167246856
>>> id(b)
2139167246856

能够看到,扭转 a 的同时 b 也跟着变,因为他们始终指向同一个地址。

不可变对象:

>>> a = (1, 2, 3)
>>> id(a)
2139167074776
>>> b = a
>>> a = (4, 5, 6)
>>> a
(4, 5, 6)
>>> b
(1, 2, 3)
>>> id(a)
2139167075928
>>> id(b)
2139167074776

能够看到,a 的值扭转后,它的地址也产生了变动,而 b 还是原来的地址,并且原地址中的内容也没有发生变化。

二、字节码

首先解释一下字节码是什么?

Python 执行程序时会把源码文件编译成字节码文件,寄存在 __pycahe 目录内,文件用 .pyc 结尾。之后如果不再批改源码文件,运行时则间接应用 .pyc 文件编译成机器码,这样岂但运行速度快,而且反对多个操作系统。

字节码,其实就是一种中间代码。

上面用 dis 模块来看一下表达式 s[a] += b 的执行过程:

>>> import dis
>>> dis.dis('s[a] += b')
  1           0 LOAD_NAME                0 (s)
              2 LOAD_NAME                1 (a)
              4 DUP_TOP_TWO
              6 BINARY_SUBSCR
              8 LOAD_NAME                2 (b)
             10 INPLACE_ADD
             12 ROT_THREE
             14 STORE_SUBSCR
             16 LOAD_CONST               0 (None)
             18 RETURN_VALUE
>>>

通过剖析字节码,能够看到其中的要害三步:

  1. 4 DUP_TOP_TWO:将 s[a] 存入 TOS(Top Of Stack)。
  2. 10 INPLACE_ADD:执行 TOS += b,带入到文章结尾的表达式,就相当于向 t[2] 中增加元素,因为 t[2] 是 list,可变对象,所以这一操作没有问题。
  3. 14 STORE_SUBSCR:将后果保留回 s[a] = TOS,这相当于将后果从新赋值回 t,因为 t 是 tuple,不可变对象,所以报错。

尽管这个问题在平时开发中可能并不常见,但通过剖析还是有不少知识点能够深挖的。

简略总结以下三点:

  1. 不要把可变对象放在元组外面。
  2. 增量赋值不是一个原子操作。咱们方才也看到了,它尽管抛出了异样,但还是实现了操作。
  3. 查看 Python 的字节码并不难,而且它对咱们理解代码背地的运行机制很有帮忙。

以上就是本文的全部内容,如果感觉还不错的话,欢送点赞转发,多谢

举荐浏览:

  • 计算机经典书籍(含下载方式)
  • 技术博客: 硬核后端开发技术干货,内容包含 Python、Django、Docker、Go、Redis、ElasticSearch、Kafka、Linux 等。
  • Go 程序员: Go 学习路线图,包含根底专栏,进阶专栏,源码浏览,实战开发,面试刷题,必读书单等一系列资源。
  • 面试题汇总: 包含 Python、Go、Redis、MySQL、Kafka、数据结构、算法、编程、网络等各种常考题。

搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:关于python:一个关于-的谜题

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址