当前位置: 首页 > 知识库问答 >
问题:

python字符串是不可变的。为什么会发生这种情况?

秦雅逸
2023-03-14

Python中的字符串是不可变的,这意味着该值不能更改。我正在测试该场景,但看起来原始字符串已被修改。我只是想理解这个概念

>>> s = 'String'
>>> i = 5
>>> while i != 0:
...     s += str(i)
...     print(s + " stored at " + str(id(s)))
...     i -= 1
... 
String5 stored at 139841228476848
String54 stored at 139841228476848
String543 stored at 139841228476848
String5432 stored at 139841228476848
String54321 stored at 139841228476848
>>> a = "hello"
>>> id(a)
139841228475760
>>> a = "b" + a[1:]
>>> print(a)
bello
>>> id(a)
139841228475312

共有2个答案

令狐和裕
2023-03-14

不管实现细节如何,文档都说:

…两个生命周期不重叠的对象可能具有相同的id()值。

=之后不再存在由引用的前一个对象,因此新对象不会因具有相同的id而违反规则。

谭畅
2023-03-14

当所附加的str恰好没有其他活引用时,这是一个特定于CPython的优化。在这种情况下,解释器“作弊”,允许它通过重新分配(根据堆布局,可以在适当的位置)和直接附加数据来修改现有字符串,而且经常会显著减少重复串联的循环中的工作量(使其更像是列表的摊销附件,而不是每次复制操作)。除了未更改的id之外,它没有任何可见的效果,因此这样做是合法的(除非逻辑上替换了str,否则任何人都不会看到它的更改)。

根据PEP8的第一个编程建议,您实际上不应该依赖它(非引用计数的解释器不能使用这个技巧,因为他们不知道str是否有其他引用):

代码的编写方式应不影响其他Python实现(PyPy、Jython、IronPython、Cython、Psyco等)。

例如,不要依赖CPython对形式为a=ba=ab的语句的就地字符串串联的高效实现。这种优化即使在CPython中也很脆弱(它只适用于某些类型),并且在不使用refcounting的实现中根本不存在。在库中对性能敏感的部分中。应改用join()表单。这将确保在各种实现中以线性时间进行连接。

如果您想打破优化,有各种方法可以做到这一点,例如将代码更改为:

>>> while i!=0:
...     s_alias = s  # Gonna save off an alias here
...     s += str(i)
...     print(s + " stored at " + str(id(s)))
...     i -= 1
... 

通过创建别名、增加引用计数并告诉Python该更改将在其他地方可见,因此它无法应用它来打破它。类似地,代码如下:

s = s + a + b

不能使用它,因为s a首先出现,并产生一个临时的b然后必须添加到其中,而不是立即替换s,并且优化太脆弱而无法尝试处理它。几乎相同的代码如下:

s += a + b

或:

s = s + (a + b)

通过确保最终串联始终为左操作数,并使用结果立即替换左操作数来恢复优化。

 类似资料:
  • 问题内容: 因此,当我发现一些非常奇怪的东西时,我正在使用Node.js REPL和Underscore库。如果I ,则该变量是全局设置的(显然)。然后,当我尝试运行一个简单的命令时,它会打印出来(显然,再次)。但是,此后立即运行,因为变量设置为,它会打印。 为什么这样做呢?如果我从js文件运行相同的代码,则不会发生。这是正常的Node事情,还是全部错误? 仅供参考:节点v0.10.10 问题答案

  • 根据Java教程 将包装类型(整数)的对象转换为其相应的基元(int)值称为取消装箱。当包装类的对象为: 作为参数传递给需要相应基元类型的值的方法 分配给相应基元类型的变量 为什么在这种情况下会发生拆箱? 在这种情况下,这些事情发生在哪里?是否有管理数组中元素访问的底层方法?或者[]暗示某种变量?

  • 安装问题 PS C:\Users\Administrator sharp@0.21.3安装C:\用户\管理员\gatsby-site3\node_modules\锐(节点安装/libvips 使用缓存的C:\Users\Administrator\AppData\Roaming\npm-cache\u libvips\libvips-8.7.0-win32-x64.tar.gz info shar

  • reactive 收集依赖不是要通过 Proxy 触发 get 吗,为什么这里只是打印 obj(没有触发 get),也能够收集到依赖?

  • 问题内容: 我编写了以下代码来实现Singleton模式: 当我编译此文件时,它应该生成Test.class和Test $ TestHolder.class,但它还会生成Test $ 1.class。这没有道理。那么,为什么以及如何呢? 问题答案: 类需要在中调用私有构造函数。但是它是私有的,实际上不能从另一个类中调用。因此,编译器发挥了作用。它 添加了一个仅知道的新的非私有构造函数!_该构造函数