【问题标题】:Python string with space and without space at the end and immutabilityPython 字符串结尾有空格和没有空格且不可变
【发布时间】:2014-02-07 19:19:49
【问题描述】:

我了解到,在一些不可变类中,__new__ 可能会返回一个现有实例——这就是 intstrtuple 类型有时对小值所做的事情。

但是为什么下面两个sn-ps的行为不同呢?

末尾有一个空格:

>>> a = 'string '
>>> b = 'string '
>>> a is b
False

没有空格:

>>> c = 'string'
>>> d = 'string'
>>> c is d
True

空间为什么会带来差异?

【问题讨论】:

  • 对不起。不可重现:)
  • 你是在 python 交互式 shell 还是 scrip.py 中,在 script.py 中它返回相同的结果,所以我认为在编译代码时发生了一些事情。因为在迭代 shell 中,当我们按下回车时,每一行都会被编译。
  • 另外,a='st '; b='st '; a is b 给了True
  • 关键字:可能。 __new__可能返回对具有相同值的现有对象的缓存引用。不保证这样做。 (不过,我确实在 CPython 3.2.3 64 位上重现了这种行为。)
  • 并使它们在多行的函数中仍然打印True

标签: python string immutability cpython python-internals


【解决方案1】:

这是 CPython 实现如何选择缓存字符串文字的一个怪癖。具有相同内容的字符串字面量可以引用相同的字符串对象,但并非必须如此。当'string ' 不是因为'string' 仅包含Python 标识符中允许的字符时,'string' 恰好会被自动实习。我不知道为什么这是他们选择的标准,但确实如此。在不同的 Python 版本或实现中,行为可能会有所不同。

来自 CPython 2.7 源代码,stringobject.h,第 28 行:

Interning 字符串 (ob_sstate) 试图确保只有一个字符串 具有给定值的对象存在,因此相等测试可以是一个指针 比较。这通常仅限于“看起来像”的字符串 Python 标识符,虽然 intern() 内置函数可用于强制 任何字符串的实习。

您可以在Objects/codeobject.c 中看到执行此操作的代码:

/* Intern selected string constants */
for (i = PyTuple_Size(consts); --i >= 0; ) {
    PyObject *v = PyTuple_GetItem(consts, i);
    if (!PyString_Check(v))
        continue;
    if (!all_name_chars((unsigned char *)PyString_AS_STRING(v)))
        continue;
    PyString_InternInPlace(&PyTuple_GET_ITEM(consts, i));
}

另外,请注意,实习是一个独立于 Python 字节码编译器合并字符串文字的过程。如果您让编译器将 ab 分配一起编译,例如通过将它们放在模块或if True: 中,您会发现ab 将是同一个字符串。

【讨论】:

  • 我记得在某处读到过这个。你有准备好链接吗?
  • 是的,我想看看一些实现细节,让我清楚地理解。
  • 很遗憾,我没有链接。我最接近的是forum discussion,在我不认识和不信任的人之间。
  • @yopy:我找到了一个源代码链接,虽然不是处理这项工作的源代码的实际部分。
  • @user2357112,这正是我想要的。谢谢
【解决方案2】:

这种行为并不一致,正如其他人所提到的,取决于正在执行的 Python 的变体。如需更深入的讨论,请参阅this question

如果您想确保使用相同的对象,您可以通过适当命名的intern 强制插入字符串:

实习生(...) 实习生(字符串)->字符串

``Intern'' the given string.  This enters the string in the (global)
table of interned strings whose purpose is to speed up dictionary lookups.
Return the string itself or the previously interned string object with the
same value.
>>> a = 'string '
>>> b = 'string '
>>> id(a) == id(b)
False
>>> a = intern('string ')
>>> b = intern('string ')
>>> id(a) == id(b)
True

注意在 Python3 中,您必须显式导入实习生 from sys import intern

【讨论】:

  • 感谢您提供的信息,但我正在寻找它表现不同的原因。
  • 更多信息请见this question
  • 在 Python 3 中,intern 现在位于 sys 模块中。
猜你喜欢
  • 2019-11-06
  • 2018-08-14
  • 2013-04-07
  • 1970-01-01
  • 2021-03-22
  • 1970-01-01
  • 2021-07-04
相关资源
最近更新 更多