【问题标题】:Why are Python strings immutable? Best practices for using them为什么 Python 字符串是不可变的?使用它们的最佳实践
【发布时间】:2011-12-30 13:45:24
【问题描述】:
  1. 使 Python 字符串不可变的设计原因是什么?它如何让编程变得更容易?
  2. 我习惯于可变字符串,例如 C 中的字符串。如果没有可变字符串,我应该如何编程?有什么最佳做法吗?

【问题讨论】:

  • 有一个可变字符串类型,叫做bytearray
  • @JanneKarila:然而,语义是完全不同的。例如,它不处理 Unicode 字符,只处理字节。它不是一个正确的字符串——使用字符串方法——它是一个可调整的字节数组。
  • @JanneKarila 但它是 C 字符串吗?

标签: python string immutability


【解决方案1】:

当您收到一个字符串时,您会确保它保持不变。假设您将使用字符串参数构造如下Foo,然后修改字符串;那么Foo的名字会突然改变:

class Foo(object):
    def __init__(self, name):
        self.name = name

name = "Hello"
foo = Foo(name)
name[0] = "J"

对于可变字符串,您必须一直进行复制以防止坏事发生。

它还允许单个字符与长度为 1 的字符串没有区别,因此所有字符串运算符也适用于字符。

最后,如果字符串不是不可变的,您就不能可靠地将它们用作dict 中的键,因为它们的哈希值可能会突然改变。

至于使用不可变字符串进行编程,请习惯于以与处理数字相同的方式处理它们:作为,而不是作为对象。更改name 的第一个字母是

name = "J" + name[1:]

【讨论】:

  • Sooooooo 我知道这有点晚了,但你能解释一下可变字符串在字典中不可靠是什么意思吗?列表是可变的,但可以放在字典中,什么会使可变字符串“不可靠”?
  • @wnnmaw larsmans 的意思是你不能可靠地使用字符串作为字典的键,因为修改字符串会改变它的哈希值,这会改变字符串去的桶.您可以通过尝试将列表用作字典的键来自己查看列表(a = {}; a[[1,2]] = 1 抛出 TypeError)。
  • 但它很容易更改字符串:str = list(str); str[0] = "J"; str = ''.join(str)
  • 我不明白。如果替换名字的第一个字母会产生什么不良后果?在这种情况下,如果我为 name 分配一个全新的值,难道不一样吗?
【解决方案2】:

与 C 字符串相比,不可变字符串极大地简化了内存分配:您不必猜测长度并过度分配,而是希望您分配得足够多。

它们更安全:您可以永远像在 C 中那样使缓冲区溢出。

只有一个可变字符串用例。

  • 替换子字符串或单个字符

所有其他字符串用例(连接、搜索等)的可变性无关紧要。在所有其他情况下,可变性并不重要。

如果要在 Python 中替换字符或子字符串,只需创建一个新字符串

x = x[:place] + replacement + x[place+1:]

这是唯一新颖或与众不同的代码。


由于我无法理解的原因,添加以下内容似乎很重要。

“除了不可变字符串之外,还有其他方法可以避免字符串缓冲区溢出。”

出于这个问题的目的(特别是关于 Python),不可变字符串有一个令人愉快的结果,即没有缓冲区溢出。对于其他语言,适用其他原则、规则和细微差别。

【讨论】:

  • Ruby(作为一个例子)有可变字符串,它有自动内存管理,不会有缓冲区溢出。至于替换子字符串是唯一的用例,那么(就地)追加呢? -1
  • 没有“就地附加”。那只是附加。 x = x + y。或x += y。您无法判断它是就地完成还是使用不可变字符串完成。
  • 您(在 31 分钟前编辑之前)做了一个更笼统的(并且,由于这种笼统性,是错误的)陈述,我提供了一个反例。您在答案的那部分中解决的问题的一部分(“为什么要使字符串不可变?”)没有谈到 C。就地附加 不同于连接两个不可变字符串并将结果返回到变量中 - 所有访问(旧)字符串的代码(而不是通过更新的变量)都可以清楚地看到差异。
  • am 在谈论 Python,但是为了对比可变字符串和不可变字符串(请注意,部分问题和所有答案),我提供了一个示例。这个例子不可能在 Python 中,因为它只有不可变的字符串。特别是,Python 中不存在就地追加(不是s = s + ... 的简化形式,而是修改字符串对象的操作)。这就是我想要表达的观点。关于可变字符串可能的操作但不可变字符串不可能的操作,您的答案是不完整的。
  • 我会从(现已确认的)公理继续我的论点,但这越来越荒谬了。 @DavidHeffernan 的评论表明它已经被频繁且清楚地说明,以至于一个人得到了它。我吹毛求疵的冲动得到了满足。
【解决方案3】:
  1. 不可变对象自动是线程安全的。
  2. 您会发现,与在 C 中使用字符串相关的极端痛苦相比,使用 Python 字符串非常容易。

【讨论】:

  • C 字符串的痛苦与可变性无关。这只会使问题更加严重。
  • @leftaround 我同意,但我并没有说 C 字符串的痛苦与它们的可变性有任何关系
【解决方案4】:

不可变字符串可以是字典和类似数据结构中的键,无需复制字符串。在不可变字符串周围创建可变包装器比其他方式更容易。

【讨论】:

    【解决方案5】:

    大多数语言都有不可变的字符串。这包括 Java、Python 和 C#。通常在连接字符串时,语言会分配一个全新的字符串并将两个字符串的内容复制到新字符串中。

    不变性确实使编程更容易。尤其是在处理多线程环境时。

    【讨论】:

      【解决方案6】:

      不可变字符串使编程变得更加容易,这也是 C# 和 Java 也使用它们的原因。

      如果字符串是可变的,您将无法信任任何外部提供的字符串,因为恶意调用者可能会在您下面更改它。
      这也会使多线程变得更加困难。

      【讨论】:

      • 你能举个例子吗?
      • 举个例子?
      • “您将无法信任任何外部提供的字符串”。谢谢
      • 您编写了一个接受字符串的函数,但您的调用者在您的函数运行时改变了字符串。
      • 有时候不是很好吗?我将拥有一个包含最新更改的数据持有者。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-21
      • 1970-01-01
      • 1970-01-01
      • 2015-06-23
      • 2011-11-02
      • 1970-01-01
      相关资源
      最近更新 更多