这是一个错误吗?在此示例中,变量是对同一字符串的相同引用(Python)

Posted

技术标签:

【中文标题】这是一个错误吗?在此示例中,变量是对同一字符串的相同引用(Python)【英文标题】:Is this a bug? Variables are identical references to the same string in this example (Python) 【发布时间】:2011-05-09 02:50:17 【问题描述】:

这适用于 Python 2.6。

我不明白为什么 a 和 b 是相同的:

>>> a = "some_string"
>>> b = "some_string"
>>> a is b
True

但如果字符串中有空格,则不是:

>>> a = "some string"
>>> b = "some string"
>>> a is b
False

如果这是正常行为,请有人解释发生了什么。

编辑:免责声明! 这不用于检查是否相等。我实际上想向其他人解释“是”只是为了检查身份,而不是平等。 从文档中我了解到,以这种方式创建的引用会有所不同,每次都会创建一个新字符串。 当我无法证明自己的观点时,我给出的第一个例子让我大吃一惊!

编辑: 我知道这不是错误,实习对我来说是一个新概念。 This 似乎是一个很好的解释。

【问题讨论】:

见***.com/questions/306313/… “错误?”问题真的让我很恼火……但我想这不是标记问题的理由……是吗? @cobbal:这与这里发生的情况略有不同。 @Ignacio:不同的根本原因,虽然基本类别相同:一些不可变的对象被缓存,而另一些则没有,基于一些未指定的启发式或其他。 众多示例之一:How is the 'is' keyword implemented in Python? 【参考方案1】:

Python 可能会也可能不会自动实习字符串,这决定了字符串的未来实例是否将共享一个引用。

如果它决定实习一个字符串,那么两者都将引用同一个字符串实例。如果没有,它将创建两个恰好具有相同内容的单独字符串。

一般来说,您无需担心是否会发生这种情况;你通常想检查相等性,a == b,而不是它们是否是同一个对象,a is b

【讨论】:

只是出于好奇,你知道Python实习字符串的逻辑是什么吗?我以为它会保留每个字符串文字,但显然不是... @katrielalex:.py 文件中的字符串有点不同:它们存储在一个常量列表中,这些常量由字节码中的索引引用。这意味着如果您在一个 .py 文件的两个位置使用相同的字符串常量,几乎可以保证它们是同一个对象。这和实习不一样。但是,OP 并没有用完 .py 文件,而是从 Python 解释器运行;这意味着它们被解析为单独的“文件”,并且没有共享字符串表。【参考方案2】:

TIM PETERS 说:抱歉,我在这里看到的唯一错误是您发布的代码中使用“is”来尝试确定两个字符串是否相等。 "is" 测试对象身份,而不是相等性,以及两个不可变对象是否真的是同一个对象通常不是由 Python 定义的。您应该使用“==”来检查两个字符串是否相等。唯一可以可靠地使用“is”的情况是,当您明确地对所有正在比较的字符串进行了实习时(通过使用 intern() 内置函数)。

从这里:http://mail.python.org/pipermail/python-bugs-list/2004-December/026772.html

【讨论】:

-1:对于像字符串这样的不可变对象,您会期望相等的引用,所以这不是错误。 @Falcon:不。字符串是不可变的允许(高效)实习(=相同对象的相同引用),但它不需要。 @Falcon:那么你的期望是错误的。检查本机 python 代码和 python 包装的 c 库之间的相等性,例如:openssl 库。即使您不知道并非所有字符串都被保留。很遗憾我不能标记你。 为此使用is 永远不可靠。 intern 可能是空操作:Python 实现可能选择不使用字符串实习(让实习生简单地返回其参数),它也可能选择忽略实习字符串的请求。例如,CPython 会默默地忽略对 string 的实习生子类的请求。【参考方案3】:

这实际上应该是对格伦的回答的更多评论,但我还不能做 cmets。我直接在 Python 解释器上运行了一些测试,我看到了一些有趣的行为。根据 Glenn 的说法,解释器将条目视为单独的“文件”,并且在存储以供将来参考时它们不共享字符串表。 这是我运行的:

>>> a="some_string"
>>> b="some_string"
>>> id(a)
2146597048
>>> id(b)
2146597048
>>> a="some string"
>>> b="some string"
>>> id(a)
2146597128
>>> id(b)
2146597088
>>> c="some string"   <-----(1)
>>> d="some string"   
>>> id(c)
2146597208            <-----(1)
>>> a="some_string"
>>> b="some_string"
>>> id(a)
2146597248            <---- waited a few minutes
>>> c="some_string" 
>>> d="some_string"
>>> id(d)
2146597248            <---- still same id after a few min
>>> b="some string"
>>> id(b)
2146597288
>>> b="some_string"  <---(2)
>>> id(b)
2146597248           <---(2)
>>> a="some"
>>> b="some"
>>> c="some"
>>> d="some"         <---(2) lost all references
>>> id(a)
2146601728
>>> a="some_string"  <---(2)
>>> id(a)
2146597248           <---(2) returns same old one after mere seconds
>>> a="some"
>>> id(a)
2146601728           <---(2) Waited a few minutes
>>> a="some_string"   <---- (1)
>>> id(a)
2146597208            <---- (1) Reused a "different" id after a few minutes

似乎某些 id 引用可能会在初始引用丢失并且不再“使用”(1) 后被重用,但它也可能与这些 id 引用未被使用的时间有关,因为您可以在我标记为数字 (2) 的内容中看到,根据未使用该 id 的时间长短给出不同的 id 引用。我只是觉得它很好奇,并想发布它。

【讨论】:

以上是关于这是一个错误吗?在此示例中,变量是对同一字符串的相同引用(Python)的主要内容,如果未能解决你的问题,请参考以下文章

重用同一个 NSError 对象会有问题吗?

私有子可以将新创建​​的变量传递给 main() 吗?

pandas.read_csv() 可以在同一列中应用不同的日期格式!这是一个已知的错误吗?如何解决?

如何将变量和字符串同时添加到同一打印语句中? [重复]

变量 a, b, c =

c++ 中char&的理解