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

如果Python字符串是不可变的,为什么如果我使用=附加到它,它会保持相同的id?

杨腾
2023-03-14

Python中的字符串是不可变的,这意味着该值不能更改。但是,在以下示例中,当附加到字符串时,由于id保持不变,看起来原始字符串内存被修改了:

>>> s = 'String'
>>> for i in range(5, 0, -1):
...     s += str(i)
...     print(f"{s:<11} stored at {id(s)}")
... 
String5     stored at 139841228476848
String54    stored at 139841228476848
String543   stored at 139841228476848
String5432  stored at 139841228476848
String54321 stored at 139841228476848

相反,在以下示例中,id更改:

>>> a = "hello"
>>> id(a)
139841228475760
>>> a = "b" + a[1:]
>>> print(a)
bello
>>> id(a)
139841228475312

共有3个答案

屠锦
2023-03-14

使用=,更改字符串时,将重新声明其值。例如,代码s表示重新声明的s值等于旧值“I”,这意味着重新声明的s为“H”“I”,即“HI”。

逑兴安
2023-03-14

无论实施细节如何,这些文件都说:

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

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

谢财
2023-03-14

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

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

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

例如,不要依赖CPython对a=ba=a b形式的语句的就地字符串连接的有效实现。即使在CPython中,这种优化也是脆弱的(它只适用于某些类型),并且在不使用重新计数的实现中根本不存在。在库的性能敏感部分,应改用". connect()形式。这将确保连接在各种实现中以线性时间发生。

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

>>> 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 = s + a + b

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

s += a + b

或:

s = s + (a + b)

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

 类似资料:
  • Python中的字符串是不可变的,这意味着该值不能更改。我正在测试该场景,但看起来原始字符串已被修改。

  • 问题内容: 使Python字符串不可变的设计原因是什么?它如何使编程更容易? 我习惯于可变字符串,例如C语言中的可变字符串。我应该如何在没有可变字符串的情况下进行编程?有没有最佳做法? 问题答案: 收到字符串时,请确保它保持不变。假设您将使用字符串参数构造一个如下所示的字符串,然后修改该字符串;那么的名称就会突然更改: 使用可变的字符串,您必须一直制作副本,以防止发生不良情况。 它还使单个字符与长

  • 问题内容: 我的猜测是它表示,对吗? 如果可以,那么什么时候可用? 问题答案: 你说得对,请参阅3.1.3。Unicode字符串。 自Python 2.0以来就是语法。 Python 3使它们多余,因为默认的字符串类型是Unicode。从3.0到3.2版本删除了它们,但在3.3+中重新添加了它们,以便与Python 2兼容以辅助2到3过渡。

  • 问题内容: 我正在阅读有关该功能的信息。问题是我仍然无法理解其用法。据我所知的唯一的事情是相同调用。 我不明白这本书何时提到你如何在运行时不知道其名称的情况下如何使用它来获取对函数的引用。总的来说,也许这是我在编程方面的菜鸟。谁能给这个问题一些启发?我什么时候以及如何使用它? 问题答案: 完全等同于。 有只有两个原因使用它: 你无法编写,因为你事先不知道想要哪个属性(它来自字符串)。对于元编程非常

  • 我正在尝试比较两个char原语ch1和ch2。两者都被分配了值1,如下所示。 但是当使用“==”运算符进行比较时,它返回false,我不明白幕后是如何或发生了什么。

  • 问题内容: 我有一个Python程序,其中两个变量被设置为值’public’。在条件表达式中,比较var1是var2,但如果将其更改为var1==var2,则返回True。 现在,如果我打开Python解释器并进行相同的比较,则此操作成功。 我错在哪里? 问题答案: 1481 是身份测试,是平等测试。你的代码中发生的情况将在解释器中进行模拟,如下所示: 所以,难怪他们不一样吧? 换句话说: