为什么 `str(1) is '1'` 在 Python 中不是 `True`?

Why isn't `str(1) is '1'` `True` in Python?

我不是在问 ==is 运算符之间的区别!我问的是 interning 之类的..!

在 Python 3.9.1 中,

>>> str(1) is '1'
<stdin>:1: SyntaxWarning: "is" with a literal. Did you mean "=="?
False
>>> '1' is '1'
<stdin>:1: SyntaxWarning: "is" with a literal. Did you mean "=="?
True

我发现匹配 [a-zA-Z0-9_] 的字符被保留在 Python 中。我明白为什么 '1' is '1'。 Python 在内存中的某处存储一个字符 '1' 并在调用 '1' 时引用它。而str(1) returns '1',我想,它应该和其他文字'1'指的是同一个地址。 str(1) is '1' 不应该也是 True 吗?

由于 str() 方法被解释并且 运行 在 运行 时(而不是在编译时),python 编译器不知道什么 str(1) 将等于。但是在编译时基本的字符串连接或变量 运行s 的定义,所以可以进行优化(字符串驻留)。请参阅以下示例:

>>> a = '12'
>>> b = '1' + '2'
>>> c = str(12)
>>> d = ''.join(['1', '2'])

>>> a is b
True
>>> a is c
False
>>> b is c
False
>>> a is d
False

I found out that characters which match [a-zA-Z0-9_] are interned in Python

恐怕你“发现”错了。

Python 自动实习 字符串文字 以及符号名称(例如模块名称,class 名称,方法名称,...)。

And str(1) returns '1', and I think, it should refers to the same address as other literal '1's. Shouldn't str(1) is '1' also be True?

没有。 interning是一个显式的去重操作,CPython只暴露了一个API来intern一个string,目前还没有办法intern一个string,如果已经有一个实习版本,不用手动弄乱解释器的胆量。

这意味着如果 str() 的输出可以被保留(由 str 本身),它总是会被保留,这可能是不可取的:而 CPython 不会“泄漏”实习字符串(他们不会永远离开),增加实习地图的大小会增加其维护和管理成本。

is 检查引用,而不是内容。此外,str(1) 不是文字,因此它不是 interned。

但是'1'是intern的,因为它直接是一个字符串。而 str(1) 经过一个过程成为一个字符串。如您所见:

>>> a = '1'
>>> b = str(1)
>>> a
'1'
>>> b
'1'
>>> a is b
False
>>> id(a)
1603954028784
>>> id(b)
1604083776304
>>>

所以让他们都实习的方法是 sys.intern:

>>> import sys
>>> a = '1'
>>> b = str(1)
>>> a is b
False
>>> a is sys.intern(b)
True
>>> 

docs所述:

Enter string in the table of “interned” strings and return the interned string – which is string itself or a copy. Interning strings is useful to gain a little performance on dictionary lookup – if the keys in a dictionary are interned, and the lookup key is interned, the key comparisons (after hashing) can be done by a pointer compare instead of a string compare. Normally, the names used in Python programs are automatically interned, and the dictionaries used to hold module, class or instance attributes have interned keys.

Interned strings are not immortal; you must keep a reference to the return value of intern() around to benefit from it.

注意在Python2中intern()是内置关键字,现在在python3中合并到sys模块变为 sys.intern