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
不管实现细节如何,文档都说:
…两个生命周期不重叠的对象可能具有相同的id()值。
在=
之后不再存在由引用的前一个对象,因此新对象不会因具有相同的id而违反规则。
当所附加的str恰好没有其他活引用时,这是一个特定于CPython的优化。在这种情况下,解释器“作弊”,允许它通过重新分配(根据堆布局,可以在适当的位置)和直接附加数据来修改现有字符串,而且经常会显著减少重复串联的循环中的工作量(使其更像是列表的摊销附件,而不是每次复制操作)。除了未更改的id之外,它没有任何可见的效果,因此这样做是合法的(除非逻辑上替换了str,否则任何人都不会看到它的更改)。
根据PEP8的第一个编程建议,您实际上不应该依赖它(非引用计数的解释器不能使用这个技巧,因为他们不知道str
是否有其他引用):
代码的编写方式应不影响其他Python实现(PyPy、Jython、IronPython、Cython、Psyco等)。
例如,不要依赖CPython对形式为a=b
或a=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。这没有道理。那么,为什么以及如何呢? 问题答案: 类需要在中调用私有构造函数。但是它是私有的,实际上不能从另一个类中调用。因此,编译器发挥了作用。它 添加了一个仅知道的新的非私有构造函数!_该构造函数