15

在 Java 中,显式声明的字符串被 JVM 隔离,因此同一字符串的后续声明会导致两个指向同一字符串实例的指针,而不是两个单独(但相同)的字符串。

例如:

public String baz() {
    String a = "astring";
    return a;
}

public String bar() {
    String b = "astring"
    return b;
}

public void main() {
    String a = baz()
    String b = bar()
    assert(a == b) // passes
}

我的问题是,CPython(或任何其他 Python 运行时)是否对字符串做同样的事情?例如,如果我有一些课程:

class example():
    def __init__():
        self._inst = 'instance' 

并创建该类的 10 个实例,它们中的每一个是否都有一个实例变量引用内存中的相同字符串,或者我最终会得到 10 个单独的字符串?

4

4 回答 4

19

这被称为实习,是的,Python 确实在某种程度上这样做,用于创建为字符串文字的较短字符串。有关讨论,请参阅关于不可变字符串的更改 id

实习依赖于运行时,没有标准。实习总是在内存使用和检查是否创建相同字符串的成本之间进行权衡。如果您愿意,可以使用强制解决问题的sys.intern()功能,其中记录了Python 自动为您执行的一些实习:

通常,Python 程序中使用的名称是自动实习的,用于保存模块、类或实例属性的字典具有实习键。

请注意,Python 2 该intern()函数曾经是内置函数,无需导入。

于 2013-07-16T15:04:14.107 回答
4

一个相当简单的判断方法是使用id(). 然而,正如@MartijnPieters 所提到的,这取决于运行时。

class example():

    def __init__(self):
        self._inst = 'instance'

for i in xrange(10):
    print id(example()._inst)
于 2013-07-16T15:05:52.377 回答
4

一些字符串在 python 中被实习。在编译 python 代码时,标识符被嵌入,例如变量名、函数名、类名。

满足以下划线或字符串开头且仅包含下划线、字符串和数字的标识符规则的字符串将被保留:

a="hello"
b="hello"

由于字符串是不可变的,python 在这里共享内存引用,并且

a is b ===> True

但如果我们有

a="hello world"
b="hello world"

由于“hello world”不符合标识符规则,因此 a 和 b 没有被实习。

a is b  ===> False

你可以实习那些有sys.intern(). 如果您的代码中有大量字符串重复,请使用此方法。

a=sys.intern("hello world")
b=sys.intern("hello world")

现在 a 是 b ===> 真

于 2020-08-13T23:46:25.323 回答
3
  • 所有长度为 0 和长度为 1 的字符串都被保留。
  • 字符串在编译时被实习('wtf' 将被实习,但 ''.join(['w', 't', 'f'] 不会被实习)
  • 不是由 ASCII 字母、数字或下划线组成的字符串不会被保留。这就解释了为什么“wtf!” 由于!没有被拘留。

https://www.codementor.io/satwikkansal/do-you-really-think-you-know-strings-in-python-fnxh8mtha

上面的文章解释了python中的字符串实习。有一些例外情况在文章中明确定义。

于 2018-07-02T14:30:45.747 回答